第16章 Gizmo(ギズモ) - エディター拡張入門

第16章 Gizmo(ギズモ)

ギズモはシーンビューで編集やデバッグのために、オブジェクトの位置や範囲、特定の要素を可視化するための仕組みです。*1

例えば、プリミティブの Cube を作成したとします。

作成した Cube を選択した状態でシーンビューで見た時の表示

図16.1: 作成した Cube を選択した状態でシーンビューで見た時の表示

少しわかりづらいですが、図16.1 の Cube の辺には緑色の線、または青色の線が表示されています。この見える線がギズモです。このギズモがあることによって、「このゲームオブジェクトにはコライダーがアタッチされている」「コライダーの大きさはこれくらいである」のような情報をもたらしてくれます。

16.1 ゲームオブジェクトにギズモを追加

また、ギズモはアイコンも表示できます。これは標準機能として実装されており、インスペクターにあるゲームオブジェクトのアイコンをクリックすることでアイコン選択画面が表示されます。

インスペクターの左上にあるアイコンをクリック

図16.2: インスペクターの左上にあるアイコンをクリック

デフォルトで3つの形状とさまざまな色が用意されています。

また、好きなテクスチャをアイコンとして指定することも可能です。

テクスチャは透過しているものが好ましい

図16.3: テクスチャは透過しているものが好ましい

アイコンを付けることで、「どこにオブジェクトがあるかわかりやすくなる」「描画するものがなくシーンビューで選択できなかったオブジェクトを選択できるようになる」メリットがあります。

GameManager は普段ギズモが表示されずシーンビューで選択ができなかったがアイコンをクリックすることで選択できるように

図16.4: GameManager は普段ギズモが表示されずシーンビューで選択ができなかったがアイコンをクリックすることで選択できるように

16.2 ギズモの描画

「Box Collider がアタッチされているかのような状態」をギズモで表現してみましょう。

空のゲームオブジェクトを作成し、作成したスクリプトをアタッチします。

OnDrawGizmos と OnDrawGizmosSelected

最も簡単にギズモを表示する方法として、2つのメソッドが用意されています。そのメソッドは MonoBehaviour の派生クラス内で Update 関数のようなコールバックとして使用できます。ゲームオブジェクトまたは親を選択中の時のみ表示する OnDrawGizmosSelectedゲームオブジェクトがアクティブの時に常に表示する OnDrawGizmos の 2 つがあります。

OnDrawGizmosSelected を使ってオブジェクトを選択中にギズモを表示

図16.5: OnDrawGizmosSelected を使ってオブジェクトを選択中にギズモを表示

OnDrawGizmosSelected では子要素のギズモもまとめて表示

図16.6: OnDrawGizmosSelected では子要素のギズモもまとめて表示

using UnityEngine;

public class Example : MonoBehaviour
{
    void OnDrawGizmosSelected ()
    {
        //ギズモの色を変更
        Gizmos.color = new Color32 (145, 244, 139, 210);
        Gizmos.DrawWireCube (transform.position, transform.lossyScale);
    }
}

DrawGizmoAttribute

手軽に使用できる OnDrawGizmos と OnDrawGizmosSelected を紹介しましたが、もともとギズモはエディター側の機能です。ランタイムのスクリプトにエディターのコードを書くのは気持ちの良いものではないかもしれません。*2

ギズモを描画する方法として DrawGizmoAttribute があります。この属性は、特定のコンポーネントに対してギズモを適用するためのものです。つまり、OnDrawGizmos や OnDrawGizmosSelected と同じ機能を扱えるということです。

OnDrawGizmos と同じ機能を DrawGizmoAttribute で実装すると次のコードになります。 GizmoType.NonSelected のみだと、オブジェクトを選択した時に表示されなくなってしまうので GizmoType.Active*3 も追加し、選択状態でもギズモを表示するようにします。

using UnityEngine;
using UnityEditor;

public class EditorScript
{
    [DrawGizmo (GizmoType.NonSelected | GizmoType.Active)]
    static void DrawExampleGizmos (Example example, GizmoType gizmoType)
    {
        var transform = example.transform;
        Gizmos.color = new Color32 (145, 244, 139, 210);

        //GizmoType.Active の時は赤色にする
        if ((gizmoType & GizmoType.Active) == GizmoType.Active)
            Gizmos.color = Color.red;

        Gizmos.DrawWireCube (transform.position, transform.lossyScale);
    }
}
子要素である中の小さな Cube を選択した状態

図16.7: 子要素である中の小さな Cube を選択した状態

OnDrawGizmosSelected を表現する場合は GizmoType.InSelectionHierarchy で可能です。

[DrawGizmo (GizmoType.InSelectionHierarchy)]
static void DrawExampleGizmos (Example example, GizmoType gizmoType)
{
    //略
}
子要素である中の小さな Cube を選択した状態

図16.8: 子要素である中の小さな Cube を選択した状態

シーンビューとゲームビューでギズモの色を変える

シーンビューとゲームビューで異なるギズモの色を表示したいことがあるかもしれません。ですが、ギズモには「どのビューで描画するか」の判断を行う API は存在しません。

ゲームビューに描画するギズモは、内部で描画する直前に INTERNAL_CALL_RenderGameViewCameras が呼び出されています。これがどちらのビューに描画されるかの唯一の判断材料になるものです。

スタックトレースを使い、INTERNAL_CALL_RenderGameViewCameras が呼び出されているかどうかを確認します。次のコードはそのサンプルとなります。

void OnDrawGizmosSelected ()
{
  var trace = new System.Diagnostics.StackTrace ();
  var frame = trace.GetFrames () [1];

  if (frame.GetMethod ().Name == "INTERNAL_CALL_RenderGameViewCameras")
    Gizmos.color = Color.red;

  Gizmos.DrawCube (Vector3.zero, Vector3.one);
}
シーンビューでは灰色、ゲームビューでは赤色になっていることが分かる

図16.9: シーンビューでは灰色、ゲームビューでは赤色になっていることが分かる

ただし、ギズモを描画する毎フレームでスタックトレースを生成しているので若干パフォーマンス的に不安が残ります。大量のギズモに対してこの処理を行うのはできるだけ避けた方がよさそうです。

ギズモは単純な機能ですがアイデア次第で、シーン内をより見やすく、理解しやすくすることが可能です。

Cube に上部を知らせる半球と軸を表示

図16.10: Cube に上部を知らせる半球と軸を表示

[*1] オプションによりゲームビューにも描画できるようになります

[*2] #if UNITY_EDITOR で囲めばコンパイルは問題ありません

[*3] 「ギズモが」アクティブと判断されるのは「ゲームオブジェクトが」アクティブかつゲームオブジェクトを選択した時

第15章 ScriptTemplates 第17章 Handle(ハンドル)