Unity 5ではCommand Bufferによる特定タイミング時のレンダリングパイプラインへの描画割り込みが可能になっている。が、新機能でテストが不十分なのか、仕様であるがドキュメントが不十分だかで、よく分からん挙動をする時があるようだ。
特に、CameraEventのAfterImageEffectsとAfterEverythingは、それまでのCameraEventとは挙動が異なる。これは恐らく、Back Bufferか何かしら特殊なバッファへの転送後に割り込むためだと思われる。ここではBack Bufferに転送済みと仮定して記述する。
Unity 5.0.1p1, DX11 Deferred Renderingで確認。他の組み合わせは知らないが、5.0.0p2などでも挙動が若干異なっていた。
スクリーンショットを貼りながらの方が分かりやすいのだが、枚数がえらいことになるので割愛。Unityユーザでレンダリングパイプラインをカスタマイズしようという人の数はそれほど多くないと思われるし、少数の対象の人はサンプル書いてFrame Debuggerを追ってみると分かるだろう。
座標系について:
- AfterImageEffects, AfterEverythingでは、スクリーン座標系の上下が反転する(UIと同じになる)
Blitの挙動について:
- AfterImageEffects開始時の、BuiltinRenderTextureTypeのCurrentActiveをsrcとしたBlit命令は、内部でBlit Copyではなく、Back BufferをsrcとしたGrab RenderTextureが発生する
- AfterEverything開始時の、CurrentActive, CameraTargetをsrcとしたBlit命令は、内部でBlit Copyではなく、Back BufferをsrcとしたGrab RenderTextureが発生する
- Grab RenderTextureは、上下が反転した状態で転送される(座標系自体が反転しているため)
- Grab RenderTextureはBlit Copyとは異なり、src, destが同一のサイズとフォーマットでないと失敗し、エラーも出力されない
1の通りAfterImageEffects時のCameraTargetは、Back Buffer転送前のRender Textureであるため、Grab RenderTextureではなくBlit Copyとなり、上下が反転していないRender Textureがコピーされる。
既に座標系の上下が反転しているため、このBlitしてきたRender Textureを用いて何かする場合だけ上下を反転して扱う必要がある。これだけ一貫性のない挙動となる。
4は知らないとハマる。Blitではなく挙動の違う謎の転送命令が内部で呼び出されているとは思うまい。ダウンサイズ時に余計なコピーが必要になるため同じ挙動の方が望ましいのだが、せめてエラーは出力されて欲しい。
SetRenderTargetの挙動について:
- AfterImageEffectsでは、SetRenderTargetにCameraTargetを指定しても、Back Buffer転送前のRender Textureがセットされる(つまり実際のBack Bufferには以降の描画は反映されない)
- AfterEverythingでは、SetRenderTargetにCameraTargetを指定するとBack Bufferがセットされる(他と一貫性がある挙動)
- 全CameraEvent共通で、SetRenderTarget( -1 )と指定するとBack Bufferがセットされる(RenderTargetIdentifer( int nameID )でそうなっている?)
1はBlitとの対応は一応取れているのだが、バグだと思う。
このためAfterImageEffectsでは一度Render Targetを切り替えると、当初のRender Target(Back Buffer)に戻す手段が無い。
…と思っていたのだが、ドキュメントには書いていないSetRenderTarget( -1 )でRender TargetをBack Bufferに戻せる。少なくとも今のバージョンの挙動では。
要するに、AfterImageEffects時のCameraTargetはBack Bufferを示すようにするか、AfterImageEffectsはBack Buffer転送前に発生するべきである。そうすることでBlitとSetRenderTargetの問題は両方とも解決する。
2022-11-30 追記: 最近のバージョンでも、これらの基本的な整合性のない挙動は変わっていない。ただし、 SetRenderTarget(-1) は、 SetRenderTarget(BuiltinRenderTextureType.BindableTexture) で可能になった(定義が=-1になっているだけだが)。この列挙子はScript Referenceには記載されていないままである。
2件のコメント