0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

技術記事未経験で個人完走を目指すAdvent Calendar 2024

Day 25

Unity カメラギズモを独自実装したい

Posted at

Unityでサブカメラを用いる場合、どこにあるか、どの方向を向いているか確認できるようにしたい場面があると思います(レーシングの俯瞰とか、RenderTextureに映すカメラ位置とか)。

本記事では、カメラギズモ(視錘台)を可視化する実装を備忘録がてら紹介。

結論、コードは以下。

using UnityEngine;

public class CameraFrustumDrawer : MonoBehaviour
{
    [SerializeField]
    private Material lineMaterial; // 線を描画するためのマテリアル

    private void OnRenderObject()
    {
        if (lineMaterial == null)
        {
            Debug.LogWarning("Line Materialが設定されていません。");
            return;
        }

        Camera camera = GetComponent<Camera>();
        if (camera == null)
        {
            Debug.LogWarning("カメラコンポーネントが見つかりません。");
            return;
        }

        // 視錐台のコーナーポイントを計算
        Vector3[] nearCorners = new Vector3[4];
        Vector3[] farCorners = new Vector3[4];
        camera.CalculateFrustumCorners(new Rect(0, 0, 1, 1), camera.nearClipPlane * 0.99f, Camera.MonoOrStereoscopicEye.Mono, nearCorners);
        camera.CalculateFrustumCorners(new Rect(0, 0, 1, 1), camera.farClipPlane * 1.01f, Camera.MonoOrStereoscopicEye.Mono, farCorners);

        for (int i = 0; i < 4; i++)
        {
            nearCorners[i] = camera.transform.TransformPoint(nearCorners[i]);
            farCorners[i] = camera.transform.TransformPoint(farCorners[i]);
        }

        // 線の描画
        GL.PushMatrix();
        lineMaterial.SetPass(0);
        GL.Begin(GL.LINES);
        GL.Color(Color.green);

        // 近クリップ面の四辺
        DrawLine(nearCorners[0], nearCorners[1]);
        DrawLine(nearCorners[1], nearCorners[2]);
        DrawLine(nearCorners[2], nearCorners[3]);
        DrawLine(nearCorners[3], nearCorners[0]);

        // 遠クリップ面の四辺
        DrawLine(farCorners[0], farCorners[1]);
        DrawLine(farCorners[1], farCorners[2]);
        DrawLine(farCorners[2], farCorners[3]);
        DrawLine(farCorners[3], farCorners[0]);

        // 近クリップ面と遠クリップ面を結ぶ四辺
        for (int i = 0; i < 4; i++)
        {
            DrawLine(nearCorners[i], farCorners[i]);
        }

        GL.End();
        GL.PopMatrix();
    }

    private void DrawLine(Vector3 start, Vector3 end)
    {
        GL.Vertex(start);
        GL.Vertex(end);
    }
}

ポイントは以下です。

  1. GLクラスでラインを描画
  2. OnRenderObjectを使用
  3. 視錘台のコーナーポイントを計算

1.GLクラスでラインを描画

GL.PushMatrix()GL.PopMatrix()で行列を保存・復元。

GL.Begin(GL.LINES)で線描画モードを開始し、GL.Vertex()で線の始点・終点を指定。

2.OnRenderObject()を使用

OnRenderObject()は、カメラのレンダリング時に呼び出されます。これによってギズモをGameViewでも描画できます。

3.視錐台のコーナーポイント計算

Camera.CalculateFrustumCornersを使用して、カメラの近クリップ面と遠クリップ面の四隅を取得しています。
描画範囲の各コーナーは、cameraのプロパティ、nearClipPlane, farClipPlane
から取得。

ちなみに、本スクリプトをアタッチしたカメラ映像をRendererTextureに設定したい場合、Textureのふちと視錘台のラインがかぶります。

それを防ぐには以下に編集してください。

camera.CalculateFrustumCorners(new Rect(0, 0, 1, 1), camera.nearClipPlane * 0.99f, Camera.MonoOrStereoscopicEye.Mono, nearCorners);
camera.CalculateFrustumCorners(new Rect(0, 0, 1, 1), camera.farClipPlane * 1.01f, Camera.MonoOrStereoscopicEye.Mono, farCorners);

nearClipPlanefarClipPlaneに係数をかけて描画したいラインと実際の描画位置を微妙にずらしています。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?