キャラクターの位置にUIを表示するにはどうすればいいの?
表示位置をUI座標に変換してから、その位置にUIを移動させれば良いわ。
uGUIのUI要素をオブジェクトの位置に表示させる方法の紹介です。
シーンに配置されているオブジェクトとuGUIオブジェクトは座標系が異なるため、オブジェクトの位置をそのままUI座標に指定しても正しく表示されません。
オブジェクトと見かけ上同じ位置にUIを表示するためには、
オブジェクトのワールド座標→スクリーン座標→TransformRectのローカル座標
の順に座標変換する必要があります。
この時、カメラ背後に位置するオブジェクトもスクリーン座標に投影されるため、背後のものを非表示にしたい場合は前後判定を行う必要があります。
本記事では、このようなオブジェクトの位置にuGUIのUIを表示する方法について解説します。
この作品はユニティちゃんライセンス条項の元に提供されています
- Unity 2021.1.21f1
目次 非表示
想定する状況
次のようにシーン内のキャラクター(3Dオブジェクト)の位置にUIを表示することを想定します。
また、キャラクターの位置に表示するためにはuGUIのCanvasが必要ですので、配置されていない場合は配置してください。
Canvasの下に次のような体力ゲージのUIマーカーを表示することを例にとって解説していきます。
なお、上記ゲージの表示部分には次のアセットを使用させていただきました。
オブジェクトの座標変換
オブジェクトの位置をUIのローカル座標に変換するためには、
- オブジェクトのワールド座標→スクリーン座標変換
- スクリーン座標→UIローカル座標変換
という2つの変換処理を行う必要があります。
ワールド座標→スクリーン座標変換
オブジェクトのワールド座標をスクリーン座標に変換する処理は次のようになります。
スクリーン座標への変換にはCameraクラスのWorldToScreenPoint()メソッドを使います。
引数には変換元のワールド座標を指定します。
参考:Camera-WorldToScreenPoint – Unity スクリプトリファレンス
スクリーン座標→UIローカル座標変換
スクリーン座標からUIのローカル座標に変換する処理は次のようになります。
座標変換には次のメソッドを使います。
これは、指定されたスクリーン座標を指定されたRectTransformオブジェクトのローカル座標に変換するメソッドです。
第1引数には、変換先のRectTransformローカル座標の親を指定します。
第2引数には、変換元のスクリーン座標を指定します。
第3引数には、Canvasに関連するカメラを指定します。Canvasがオーバーレイモード
場合はnullを指定しなければいけません。第4引数には、RectTransformのローカル座標を受け取るための変数を指定します。
参考:RectTransformUtility-ScreenPointToLocalPointInRectangle – Unity スクリプトリファレンス
背後にオブジェクトがある場合への対処
ここまでの変換処理でUIをオブジェクトの位置の表示させると、次のように背後にオブジェクトがあるときもUIが表示されてしまいます。
これは、ワールド座標をスクリーン座標に変換するとき、カメラ背後の位置も画面上に投影されてしまうためです。
そのため、カメラ背後のオブジェクトを非表示にしたい場合、前後判定処理を行う必要があります。
前後判定の計算方法
前後判定は、カメラの向きベクトルとカメラからオブジェクトへのベクトルとの内積から判定できます。
\vec{n} \cdot (P-C)
\vec{n} : カメラの向きベクトル
C : カメラの位置
P : オブジェクトの位置
内積の値が正の場合はカメラの前方、負の場合はカメラの背後、0の場合はカメラの真横に位置していることになります。
したがって、内積の値が0より大きいときのみUIを表示するようにすれば良いです。
2つのベクトルの内積は、Vector3.Dot()メソッドから計算できます。
参考:Vector3-Dot – Unity スクリプトリファレンス
今回の場合、内積を使うとシンプルに実装できるわ。しかも内積は計算がとても軽いというメリットもあるの。
サンプルスクリプト
指定されたオブジェクトの位置にUIを表示させるサンプルです。カメラ背後にオブジェクトがある場合に非表示にする処理も入っています。
使い方
表示対象の親UIにスクリプトをアタッチします。大本のCanvasでも問題ありません。
例ではヒエラルキーのPanelを表示対象とし、その親オブジェクトMarkerにスクリプトをアタッチしています。
そして、赤枠の項目を一通り設定します。PrefabをInstantiateして生成する場合は、Target Camera、Targetはそのまま設定できないため、Initializeメソッド経由で初期化するようにします。
実行結果
カメラ前方にあるオブジェクトだけが描画されるようになりました。
さいごに
オブジェクトの見かけ上の位置にUIを表示する方法を紹介しました。座標変換を駆使することで実現可能です。
カメラに映らないオブジェクトに対するUIを非表示にする方法は、本記事で紹介した以外にも存在します。例えば、ある距離以上離れたオブジェクトを非表示にしたい場合、今回の方法では対処できず距離判定処理を加える必要があります。
この辺りの実装は、開発するコンテンツに合わせて適宜判断してください。