Cooooding!!

Unity(C#)を使ったゲーム開発関連Tipsなど

Gizmosで平面を描画する【Unity】

概要

計算結果の平面(UnityEngine.Plane)が正しいかどうかを確認するためにGizmosで描画しようと思ったら簡単に描画できる関数がなかったので実装してみました。Planeは長さを持たず無限に広がるため、描画時に座標とサイズを指定して一部分を描画することになります。

実装

片面の平面を描画

Planeは向き(法線方向)を持つため向きが確認できるように片面だけ描画します。

/// <summary>
/// 片面の平面を描画する
/// </summary>
/// <param name="plane">平面</param>
/// <param name="point">この点に最も近い平面上の座標を中心とする</param>
/// <param name="size">描画するサイズ</param>
public static void Draw(
    Plane plane, Vector3 point, Vector2 size
)
{
    var mesh = MakeMesh(plane, point, size);
    Gizmos.DrawMesh(mesh);
}

/// <summary>
/// 平面を描画するためのMeshを作る
/// </summary>
public static Mesh MakeMesh(Plane plane, Vector3 point, Vector2 size)
{
    // Unityは左手系なので、時計回りの頂点で法線は(0, 0, -1)方向
    var vertices = GetVertices(plane, point, size);
    var mesh = new Mesh();
    mesh.SetVertices(new List<Vector3>(vertices));
    mesh.SetTriangles(new List<int>(){ 0, 1, 2, 0, 2, 3 }, 0);
    mesh.RecalculateBounds();
    mesh.RecalculateNormals();
    return mesh;
}

/// <summary>
/// 平面を描画するための頂点位置計算
/// </summary>
public static Vector3[] GetVertices(
    Plane plane, Vector3 point, Vector2 size
)
{
    // pointが平面上にないなら最も近い平面上の座標を中心とする
    var center = plane.ClosestPointOnPlane(point);

    var rotation = Quaternion.LookRotation(-plane.normal);
    var width = 0.5f * size.x;
    var height = 0.5f * size.y;
    var vertices = new Vector3[] {
        new Vector3(-width, -height, 0),
        new Vector3(-width,  height, 0),
        new Vector3( width,  height, 0),
        new Vector3( width, -height, 0),
    };
    for (int i = 0; i < vertices.Length; ++i)
    {
        vertices[i] = rotation * vertices[i] + center;
    }
    return vertices;
}

片面の平面を描画した結果

両面の平面を描画

Planeは向きを持つものの両面表示したいこともあります。これは細長いCubeを使うと簡単に実装できます。

public static void DrawBothFace(
    Plane plane, Vector3 point, Vector2 size
)
{
    // pointが平面上にないなら最も近い平面上の座標を中心とする
    var center = plane.ClosestPointOnPlane(point);

    var backup = UnityEngine.Gizmos.matrix;
    Gizmos.matrix = Matrix4x4.TRS(
        center,                                 // 中心
        Quaternion.LookRotation(plane.normal),  // 回転
        new Vector3(size.x, size.y, 0.0001f)    // サイズ(厚みをほぼ0する)
    );
    Gizmos.DrawCube(Vector3.zero, Vector3.one);
    Gizmos.matrix = backup;
}

両面の平面を描画した結果

枠だけを描画

簡単なのでついでに枠の描画も実装してみます。

public static void DrawWire(
    Plane plane, Vector3 point, Vector2 size
)
{
    var vertices = GetVertices(plane, point, size);
    for (int i = 0, length = vertices.Length; i < length; ++i)
    {
        var p0 = vertices[i];
        var p1 = vertices[(i + 1) % length];
        Gizmos.DrawLine(p0, p1);
    }
}

平面の枠だけ描画した結果

環境

  • Unity 2018.4.2f1
  • VisualStudio 2019 (ver16.1.5)