【Unity】カメラのレンダリング対象の変更と、Blitによるレンダリングについて

レンダリング周りを制御する下記のメソッドやプロパティの使い方で少し混乱したのでメモです。

  • Camera.targetTexture
  • Camera.SetTargetBuffers()
  • Graphics.SetRenderTarget()
  • Graphics.Blit()

カメラのレンダリング対象を変更する

まず、カメラのレンダリング先を変更してみます。

何もしなければカメラは画面にレンダリングを行いますが、 レンダーテクスチャや独自のカラーバッファ・深度バッファなどにもレンダリングできます。

var camera = GetComponent<Camera>();

// RenderTextureを作る
var format = SystemInfo.SupportsRenderTextureFormat(RenderTextureFormat.ARGBHalf) ? RenderTextureFormat.Default : RenderTextureFormat.ARGBHalf;
var rt = new RenderTexture(Screen.width, Screen.height, 24, format);
rt.Create();

// パターン1
// RenderTextureに対してレンダリングする
camera.targetTexture = rt;

// パターン2 
// カラーバッファ、深度バッファそれぞれ別のテクスチャにレンダリングしたいときや
// 複数のテクスチャをターゲットにしたいときはこのメソッドを使う
camera.SetTargetBuffers(rt.colorBuffer, rt.depthBuffer);

//パターン3 
// 画面に対してレンダリングする
camera.targetTexture = null;

使い方はコメントに書いた通りです。

また、レンダリングのタイミングはCameraのアタッチされているオブジェクトに下記のようなスクリプトをアタッチすることで取得できます。

using UnityEngine;

public class RenderingTest : MonoBehaviour {

    /// <summary>
    /// このカメラのレンダリング前の処理
    /// </summary>
    private void OnPreRender()
    {
    }

    /// <summary>
    /// このカメラのレンダリング後の処理
    /// </summary>
    private void OnPostRender()
    {
    }
}

Unity - Scripting API: MonoBehaviour.OnPreRender()

Unity - Scripting API: MonoBehaviour.OnPostRender()

カメラを使わずにレンダリングを行う

Graphicsクラスを使うとカメラを通さずにレンダリングすることもできます。
レンダリングするためにはGraphics.Blit()メソッドを使います。

// レンダーテクスチャを別のレンダーテクスチャにコピーする
Graphics.Blit(_renderTextureSrc, _renderTextureDst, _material);

// nullは画面をレンダリング対象とすることを意味する
// 画面にBlitする場合
Graphics.Blit(_renderTextureSrc, null, _material);

// 画面の表示をレンダーテクスチャにBlitする場合
Graphics.Blit(null, _renderTextureDst, _material);

画面を対象にした場合、Blitした後に同フレーム内で画面への描画が行われるともちろん上書きされますので、タイミングには注意が必要です。
(OnRenderImageとかであれば問題なし)

また、Blit()はカラーバッファしかコピーしないようです。
よってデプスバッファやステンシルバッファをコピーしたい場合には、Graphics.SetRenderTarget()を使う必要があります。

// srcRT: コピー元のレンダーテクスチャ
// destRT: コピー先のレンダーテクスチャ
// BlitすることでdestRTのcolorBufferにsrcRTのdepthBuffer情報(ステンシルなど)を用いて描画する
Graphics.SetRenderTarget(destRT.colorBuffer, srcRT.depthBuffer);
Graphics.Blit(srcRT, material);

これについては詳細は下記を参照してください。

Graphics.Blit does not copy RenderTexture depth – Unity

参考

http://www.shibuya24.info/entry/rendertarget https://docs.unity3d.com/ja/560/ScriptReference/Graphics.Blit.html

関連

light11.hatenadiary.com