LoginSignup
1
0

【Unity】現在描画に利用しているカメラの取得方法

Posted at

はじめに

現在の描画に利用しているカメラを取得する際に Camera.current というプロパティから取得できるはずが、取得しても以下の様にnull になってしまっていたので原因を調べてみました。

void Start()
{
    var currentCamera = Camera.current;
    Debug.Log(currentCamera);
}

image.png

Built-in Render Pipelineの場合の取得方法

公式ドキュメントの記載の通り、OnRenderImage、OnPreRender、OnPostRender 以外では取得できないようです。

この関数は、 MonoBehaviour.OnRenderImage、MonoBehaviour.OnPreRender、MonoBehaviour.OnPostRenderのイベントのいずれかを実装する場合にのみ使用します 。

BRPの場合は公式に従って以下の様にそれぞれのイベント

    private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        Debug.Log($"OnRenderImage : {Camera.current}");
    }
    
    private void OnPreRender()
    {
        Debug.Log($"OnPreRender : {Camera.current}");
    }
    
    private void OnPostRender()
    {
        Debug.Log($"OnPostRender : {Camera.current}");
    }

また、これらのイベントはCameraコンポーネントと同一のゲームオブジェクトにアタッチする必要があるので現在のレンダリング中のカメラを取得する用途には制約が多い印象です。
そこで、OnRenderObjectイベントで取得することでCameraをアタッチしているGameObject外でもCamera.currentを取得できるようです。

    private void OnRenderObject()
    {
        Debug.Log($"OnRenderObject : {Camera.current}");
    }

image.png

URPの場合の取得方法

URPではOnRenderImage、OnPreRender、OnPostRenderに加えてOnPostRenderこれら全てが機能しないため、公式ドキュメントに記載されている方法ではCamera.currentを取得することができません。

以下ログの様にイベント自体が呼ばれていません。
image.png

そこで描画タイミングで発生するイベントRenderPipelineManager.beginCameraRenderingを購読することで最新の描画に利用したカメラを取得する方法でCamera.currentっぽい値を取得してみました。

Scene構成は以下の形で、MainCameraがpriorityを0、SubCameraがpriorityを-1に設定してMainCameraの優先度の方が高くなるように設定しています。

image.png

public class CameraCheck : MonoBehaviour
{
    // 直近で描画に利用したカメラ
    Camera _currentCamera;
    private void Start()
    {
        // カメラ描画イベントを購読する
        RenderPipelineManager.beginCameraRendering += WriteLogMessage;
    }
    private void OnDisable()
    {
        // カメラ描画イベントを解除する
        RenderPipelineManager.beginCameraRendering -= WriteLogMessage;
    }

    void WriteLogMessage(ScriptableRenderContext context, Camera camera)
    {
        Debug.Log($"Beginning rendering the camera: {camera.name}");
        
        // 最新の描画用カメラとして登録する
        _currentCamera = camera;
    }

    private void Update()
    {
        // 最後に描画したカメラを表示する
        Debug.Log("_currentCamera : " + _currentCamera);
    }
}

この様にすることで以下のログのように優先度を高く設定したMainCameraが最新のカメラとして取得できるようになりました。

image.png

本記事について、もっと簡単に実現できる方法があればコメントを頂けると幸いです。

余談

ちなみに最後のActionを使う方法ですがUniRxR3で実装するとこの様になります。
取得したいフレームだけイベント購読する。みたいな方法で使えば便利かも知れません。

    private void Start()
    {
        Observable.FromEvent<Action<ScriptableRenderContext, Camera>, Tuple<ScriptableRenderContext, Camera>>
        (
            h => (x, y) => h(Tuple.Create(x, y)),
            handler => RenderPipelineManager.beginCameraRendering += handler,
            handler => RenderPipelineManager.beginCameraRendering -= handler
        ).Subscribe(arg => WriteLogMessage(arg.Item1, arg.Item2));
    }

ActionをStreamに変換することができるObservable.FromEventですが、今回の様に引数が複数になるとタプルに変換して戻すような処理が入り一気に複雑な記述になってしまうため、可読性が悪いためActionのまま実装した方が良い気がしました。。。

1
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
1
0