Unityで、何かしらのオブジェクトを画面いっぱいに表示したい、ということはあるかもしれません。
これがUIなら簡単な話で、Rect Transformのインスペクターを弄ればすぐです。しかし、オブジェクトとなると苦戦するかと思います。
今回は画面いっぱいにオブジェクトを表示、というかオブジェクト自体を拡大なり縮小なりしてしまうという、ある種強引でわかりやすい方法のご紹介です。




前提条件:画面いっぱいに、というのは困難を極める
紹介するとか言いながら、矛盾した見出しになってしまいました。しかしこれは先に言っておかなければなりません。
Unityを3Dで作成したとき、メインカメラの範囲を見るとこんな感じになりますよね。うっすらとした線で、範囲が見えます。
ちょうどカメラビューがついてますし、話が進めやすい。そう、今回のお題は、このビューいっぱいに、指定のオブジェクトを表示することなのですが、カメラの位置から放射状に広がる描写範囲を見て、勘の鋭い人は気づいてしまうでしょう。
これ、角度計算しなきゃいけないのか、と。
はい、計算しないといけません。
オブジェクトの形状にもよるのですが、例えばCubeを配置して、それをカメラビューいっぱいに拡大したい場合、
- カメラに映る面の頂点の座標を調べる。
- 各頂点の同Z座標平面上の、カメラ描写範囲限界の点を調べる。
- オブジェクトのScaleを上手く調整して拡大する。
という手順を歩むことになります。
この、2のところで、文系の私が拒否感の余り鳥肌を立たしてしまう、三角関数を使わなければいけません。横から見て、角度はこうだから、sinθの値が…ってあれですね。
一例としてCubeを例にあげましたが、これが複雑な形状のオブジェクトならもうおてあげですね。どうScaleの値をいれるというんだ…。
「画面いっぱい」という言葉の定義を、私は「画面ぴったり」と考えていますが、そうでなくてもう全部映さなくていいから画面の端から端までこのオブジェクトを表示したいんだ、という話なら、適当に大きな値をScaleをインスペクターに入れておけば解決するでしょう。そうでないなら絶望的ですね…。
複雑な形状じゃなくて、普通のCubeとかなんだけど、という方なら、まだ可能性の芽はあります。
文系脳の私は諦めましたが、こちらの質問が参考になるかと思います。
画角ってなんだよ、ってところで私は諦めましたが。あはは…。
しかし2Dなら比較的簡単
画面いっぱい、画面ぴったりというお題が困難を極めるのは上記の通り、角度を計算しなくてはいけないからだというのは先述の通りです。
しかしです。この角度という問題が出てくるのは、Unityが3Dゲームの開発ツールだからです。3Dだから、先ほども「同平面上」とか、わけのわからない言葉を使わなくてはいけないわけで。
…じゃあ最初から、固定した平面でいいんじゃね?
あるいは、同じZ座標で考えたらいいんじゃね…?
という考えが出てくるのは、もう必然といって差し支えないでしょう。
なんだか色々と遠回りしましたが、要するに固定の平面で開発をする、Unity2Dなら比較的容易に問題を解決する、という話がしたかったのです。
長い前振りにお付き合いいただき、ありがとうございました。
ではここから後は、Unity2Dにて画面いっぱいにオブジェクトのサイズを変える方法をご紹介しましょう。
実行環境について
Unityバージョン:2019.4.18f1
Visual Studio Community 2019バージョン:16.9.1
オブジェクトの配置
今回、こんな感じでCubeを配置しました。
サイズ変更もしていない、単なるCubeですね。
スクリプト作成
じゃあスクリプトを一つ作成してみましょう。
こんな感じで一つ作って、Cubeにアタッチして、はい終了!です。
スクリプトの名前は、"SizeControll"にしました。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SizeControll : MonoBehaviour
{
private Camera m_MainCamera; // メインカメラ
Vector3 BottomLeft;//左下
Vector3 TopRight; //右上
float Width; //x座標系、幅
float Height; //y座標系、高さ
float ObjectWidth; //オブジェクトの幅
float ObjectHeight; //オブジェクトの高さ
// Start is called before the first frame update
void Start()
{
m_MainCamera = GameObject.Find("Main Camera").GetComponent<Camera>();
//カメラ領域の左下の座標を取得
BottomLeft = m_MainCamera.ScreenToWorldPoint(Vector3.zero);
// カメラ領域の右上の座標を取得
TopRight = m_MainCamera.ScreenToWorldPoint(new Vector3(Screen.width, Screen.height, 0.0f));
//オブジェクトの幅・高さを取得
ObjectWidth = this.GetComponent<MeshRenderer>().bounds.size.x;
ObjectHeight = this.GetComponent<MeshRenderer>().bounds.size.y;
//カメラの領域の幅・高さをワールド座標系数値で取得
Width = (TopRight.x - BottomLeft.x) ;
Height = (TopRight.y - BottomLeft.y) ;
//上記二値からスケール(ローカル座標系)を調整
transform.localScale = new Vector3(Width/ ObjectWidth, Height/ ObjectHeight, 0);
}
}
これをアタッチして、ゲームを起動させてみるとこんな感じ。
Unity2Dのカメラの描写範囲は、放射状ではなくて一方向にまっすぐ貫通なんですよね。Cubeはその範囲に合わせて、ピッタリサイズになっているのがわかるかと思います。
スクリプトの解説
さて、ここからは少しスクリプトの解説じみたものを書いていこうと思います。
このスクリプトを応用的に使われたい方は、いくつか注意すべき箇所がありますので、ぜひご一読ください。
①スクリプトの方針
このスクリプトがそもそもどういう方針で書かれているか、ということですが、
- メインカメラを取得→メインカメラのカメラ描写領域の縦横を取得
- オブジェクトの縦横を取得
- ①の数値/②の数値 を縦横で算出し、CubeのScaleに代入
別に複雑なことをしているわけじゃありません。
算数の授業で、大きな四角形と小さな四角形を出されて、さて小さな四角形のどの辺を何倍すれば大きな四角形になりますか?っていうのがあったと思います。あれですね。
今回の話なら、さしずめ「大きな四角形」にあたるのが「カメラの描写領域」で、「小さな四角形」にあたるのが「オブジェクト」だっただけです。
②カメラの描写領域の取得について
Unity2Dのカメラには便利なメソッドが用意されていまして、今回はそれを使っています。
"ScreenToWorldPoint"を使うと、カメラの領域の座標をワールド座標で取得できます。
Unityにはワールド座標・ローカル座標・スクリーン座標と、座標のスタイルが色々あって難しいですが、今回のように四則計算みたいなことをする場合は、計算に使う数値を同じ座標のスタイルで扱うのが基本ですね、そりゃそうだ。
さて、"ScreenToWorldPoint"はネットサーフィンしていると、結構間違った情報が流布している気がします…。
Vector3 PointA(ワールド座標)=Camera.ScreenToWorldPoint(スクリーン座標);
敢えて公式化すると、ScreenToWorldPointの使い方はこんな感じです。
あんまり見覚えないと思うのですが、スクリーン座標というのは、画面の左下を原点とする座標です。画面の縦横がスクリーン座標の該当領域という感じ。
小学校の頃から、私たちは左下に(0,0)と書いて、比例のグラフなりなんなり描いてきたと思います。原点の位置で戸惑うところはないでしょう。
③オブジェクトの幅・高さの取得について
//オブジェクトの幅・高さを取得
ObjectWidth = this.GetComponent<MeshRenderer>().bounds.size.x;
ObjectHeight = this.GetComponent<MeshRenderer>().bounds.size.y;
今回のスクリプトでは、こんな感じで取得してきました。
bounds.sizeというメソッドは、レンダラー系のコンポーネントについているやつらしく、今回のCubeにはMesh Rendererがついていたので、それを取得してから使いました。
このレンダラーはオブジェクトによって違うと思いますので、各自の変更箇所ですね。要う周囲事項かと思います。
④その他
まぁざっと、頑張って調べて組み込んだメソッドを紹介しましたが…。
そうですね、他に書いてない箇所があるとすれば、最後のScaleに代入する点でしょうか。
"LocalScale"とスクリプトに書いてある通り、Scaleはローカル座標対応です。②と③で、ワールド座標で取得しているのにおかしいじゃないか、と思われるかも…?
これはもはやプログラミングではなくて数学の話なんですが、Scaleに代入している値はワールド座標をワールド座標で割った拡大率(?)なので、大丈夫…ああ…全然説明できてない…。数学は苦手だったので、このへんで勘弁してくださいっ…!💦
最後に
また記事が長くなってしまった…。
どこかで区切れるといいのですが、上手くいきませんね…。
0 件のコメント:
コメントを投稿