渋谷ほととぎす通信

「Unityをわかりやすく」初心者のためのゲーム作りブログ

Unity SetTargetBuffers、Blit、SetRenderTargetの関係性の謎にせまる

Unity SetTargetBuffers、Blit、SetRenderTargetの関係性の謎にせまる

こんにちは、Unityエンジニアのオオバです。

世界ふしぎ発見を見ながら記事を書いていたのでタイトルが影響を受けております。
2017年も残りわずか、この記事が今年最後の投稿になるかもしれません。来年もよろしくお願いいたします。

では本題へ

  • camera.SetTargetBuffers
  • Graphics.Blit
  • Graphics.SetRenderTarget

イマイチ理解していなかった上記3メソッドの調査しました。

👉DOTweenの教科書を読んでUnityアニメーションをプログラミングしてみよう!

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をセットしています。

Unity SetTargetBuffers、Blit、SetRenderTargetの関係性の謎にせまる_0

初期状態には何も投影していないため、真っ白な状態です。

SetRenderBuffers実行後

Unity SetTargetBuffers、Blit、SetRenderTargetの関係性の謎にせまる_1

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に描画されている画像を画面に写してみます。

// 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つの記述は内部処理として同じなので覚えておきたいところです。

最後に

検証プロジェクトを作ってみてやっと理解できた気がします。
SetRenderBuffersは一度指定すると解除することが出来ないっぽいのですが、そういうものなのでしょうか...調べても分かりませんでした。

また今回の流れを図でまとめています。

1.初期状態

Unity SetTargetBuffers、Blit、SetRenderTargetの関係性の謎にせまる_2

2.SetTargetBuffers実行

Unity SetTargetBuffers、Blit、SetRenderTargetの関係性の謎にせまる_3

3.Graphics.Blit実行

Unity SetTargetBuffers、Blit、SetRenderTargetの関係性の謎にせまる_4

4.Graphics.SetRenderTarget(null)を実行

Unity SetTargetBuffers、Blit、SetRenderTargetの関係性の謎にせまる_5

CameraクラスにSetRenderBuffersと同じようなtargetTextureプロパティも存在します。
コチラはまた余力がある際に調査しいます。

今回のサンプルプロジェクトです。

GitHub - baobao/RenderTargetTest

素材はコチラのサイトから使わせてもらいました。

オススメ記事
検証環境
  • Unity2017.3.0f3
  • macOS Sierra 10.12.6
参考サイト