世界ふしぎ発見を見ながら記事を書いていたのでタイトルが影響を受けております。
2017年も残りわずか、この記事が今年最後の投稿になるかもしれません。来年もよろしくお願いいたします。
では本題へ
- camera.SetTargetBuffers
- Graphics.Blit
- Graphics.SetRenderTarget
イマイチ理解していなかった上記3メソッドの調査しました。
camera.SetTargetBuffers
SetTargetBuffersはCameraクラスのインスタンスメソッドで、カメラがレンダリングするRenderTextureのバッファを指定します。
var rt = new RenderTexture(300, 200, 24, RenderTextureFormat.ARGB32); rt.name = "TestRenderTarget"; _camera.SetTargetBuffers (rt.colorBuffer, rt.depthBuffer);
このような感じでカメラにRenderTextureのバッファをセットします。
上記のサンプルコードの場合、このカメラのレンダリング対象がRenderTextureのrtになったため、今まで画面に写っていた画像は映らなくなります。
文字だと分かりづらいのでサンプルをどうぞ。
初期状態
右下にはuGUIのRawImageでRenderTextureをセットしています。
初期状態には何も投影していないため、真っ白な状態です。
※RenderTexture生成時に白色を描画しています
SetRenderBuffers実行後
SetRenderBuffersを実行したので、今まで映し出されていた画面表示が消え、カメラのレンダーターゲットがRenderTextureに移ったことが分かります。
void OnPostRender()
{
Debug.Log(RenderTexture.active);
}
カメラのレンダーターゲットがRenderTextureに移った事は、RenderTexture.active
をOnPostRender(レンダリング終了時)のログを取得してみると分かります。
ここまでで、SetTargetBuffers
はカメラのレンダリング先を変更できるということがわかりました。
Graphics.Blit
Graphics.Blitは引数で渡されたRenderTextureをターゲットのRenderTextureにコピーするスタティックメソッドです。
Graphics.Blit(src, dst);
この場合テクスチャsrcをRenderTextureのdstにコピーします。
もう1つの機能としてdstにnullを代入することで、srcを画面に直接描画することが出来ます。
この機能を使い、カメラからRenderTextureに描画されている画像を画面に写してみます。
Unity - Scripting API: Graphics.Blitより
// dstを指定しないことでnullが代入されるオーバーロード void OnPostRender() { // rtを画面に直接描画 Graphics.Blit(rt, material); }
※上記materialは入力画像をそのまま出力した単純なシェーダです
しかしこのままでは画面に描画されません。
Graphics.SetRenderTarget
最後に登場したSetRenderTargetはメソッド名の通り、引数に渡したRenderTextureやRenderBufferをレンダーターゲットに指定することが出来ます。
先のRenderTextureのrtを画面に表示させるためにGraphics.Blitを実行しましたが、残念ながら思うような挙動をしませんでした。
理由としてはカメラのレンダーターゲットが未だにRenderTextureのrtを指しているからです。
画面に描画するタイミングで、SetRenderTargetを使ってカメラのレンダーターゲットを解除する必要があります。
void OnPostRender() { // カメラのレンダーターゲットを解除 Graphics.RenderTarget(null); // rtを画面に直接描画 Graphics.Blit (rt, material); }
と、引数にnullを代入することでレンダーターゲットがRenderTextureから外れ、画面にRenderTextureが描画されるようになります。
カメラのレンダーターゲットからRenderTextureが外れたのであればGraphics.Blitは不要ではないか?という疑問が湧いてきます。
しかし、カメラがレンダリングするバッファはRenderTexutreのrtと指定されているため、この設定が外れるわけではありません。あくまで一時的にレンダーターゲットから外しているだけで、次フレームの描画ループになったときには再度元のレンダーターゲットに戻っています。
余談
Graphics.RenderTarget(null)
と
RenderTexture.active = null
この2つの記述は内部処理として同じなので覚えておきたいところです。
Unity - Scripting API: Graphics.SetRenderTargetより
最後に
検証プロジェクトを作ってみてやっと理解できた気がします。
SetRenderBuffersは一度指定すると解除することが出来ないっぽいのですが、そういうものなのでしょうか...調べても分かりませんでした。
また今回の流れを図でまとめています。
1.初期状態
2.SetTargetBuffers実行
3.Graphics.Blit実行
4.Graphics.SetRenderTarget(null)を実行
CameraクラスにSetRenderBuffersと同じようなtargetTextureプロパティも存在します。
コチラはまた余力がある際に調査しいます。
今回のサンプルプロジェクトです。
素材はコチラのサイトから使わせてもらいました。
検証環境
- Unity2017.3.0f3
- macOS Sierra 10.12.6