simplestarの技術ブログ

目的を書いて、思想と試行、結果と考察、そして具体的な手段を記録します。

Unity:ScriptableRenderPipeline(SRP)の書式確認

Unity の Scriptable Render Pipeline(SRP) とは端的に言うと、Unity がフレームをどのようにレンダーするかをデベロッパーが C# で制御できるようにするものです。(大事なことなので何度でも)

前回の記事でSRPの導入方法はバッチリ
simplestar-tech.hatenablog.com
今回は、前回記事の最後に確認した最も単純な BasicRenderPipeline の実装について確認していきます。

具体的には次の BasicRenderPipeline.cs コードを詳説して終わります。
github.com

定義されているクラスは三つ
1.public class BasicRenderPipeline : RenderPipelineAsset
Unity のプロジェクトから選択できる SRP アセットを定義しています
2.public class BasicRenderPipelineInstance : RenderPipeline
上のアセットに紐づくパイプラインで、実装は次のクラスの Render 関数を呼ぶだけ
3.public static class BasicRendering
ScriptableRenderContext renderContext, Camera cameras を受け取って、実際にパイプラインを実装している静的クラス

終始 public bool UseIntermediateRenderTargetBlit; フラグで分岐するコードがあるが、これはシーンからユーザーがチェックボックスで設定するもので、基本 false の値となっている。
シーンで切り替えられるように配置したフラグをネストが深いところまで連絡しているコードが全体を汚しているだけなので
最初は UseIntermediateRenderTargetBlit の連絡コードと分岐先の実装は無視して読むと、認識負荷は大きく落とせます。

そうした上で BasicRendering クラスの実装の中身は次の通り
1.ScriptableRenderContext renderContext, Camera cameras を受け取る、静的な Render 関数の実装
2.その Render 関数で利用する ConfigureAndBindIntermediateRenderTarget 関数(UseIntermediateRenderTargetBlit == true の時のみ実行するので無視)
3.その Render 関数で利用する BlitFromIntermediateToCameraTarget 関数(UseIntermediateRenderTargetBlit == true の時のみ実行するので無視)
4.その Render 関数で利用する SetupLightShaderVariables 関数
5.その Render 関数で利用する GetShaderConstantsFromNormalizedSH 関数

最初に通しで読む関数は 1.4.5.だけです。
1.では camera のループを回し、camera から見えないオブジェクトを削ぐようにカリングする実装から始まり
コンテキストに camera の設定を入力して、CommandBufferPool からコマンドを取得し depth のみクリアしています。
続いて global lighting shader variables を最大 8 個まで更新して RenderQueueRange.opaque と不透明オブジェクトのみを扱うようにフィルタリングして、近い順に描画しています。
そのあとに余ったピクセルに Skybox を描き、最後に RenderQueueRange.transparent と半透明オブジェクトのみを扱うようにフィルタリングして、遠い順に描画しています。
camera 単位の描画処理を記述したら context.Submit(); して次の深度のカメラについて処理していきます。
stereoEnabled フラグは XR でデバイスを検知しない限り false なので、ほとんどのコードを無視してパイプラインの実装を読むことが出来ました。
以上です。

これはわかりやすい。
では少し弄ってみましょう。

不透明オブジェクトとSkyboxを描画してから半透明オブジェクトを描画していますが
半透明オブジェクトの描画を先頭に持ってくるとどうなるでしょうか?

f:id:simplestar_tech:20180909125955j:plain

半透明オブジェクトが…

f:id:simplestar_tech:20180909130230j:plain

不透明オブジェクトで上書きされてしまいました。
Unity にはオブジェクトごとのレンダリング結果を見る Frame Debugger がありますので、そちらを使って描画順序を確認してみましょう。
するとこんな感じ

f:id:simplestar_tech:20180909131718g:plain

なるほど、半透明を描画してから不透明で上書きしていることがはっきりわかりますね。
Sort フラグもちょっといじりますか
None を設定したところ、Plane の描画順番が早い段階に移動してしまいました。
これでは、後で不透明オブジェクトで上書きされてしまう無駄なピクセルの計算が走ってしまいます。

f:id:simplestar_tech:20180909132447j:plain

なるほど、こんな感じで FrameDebugger と連携しながら、シーン描画を最適化するようにパイプラインを弄っていけば、かなり描画パフォーマンスを意識したパイプラインを構築できるようになっていくのではないでしょうか?
また少しレベルアップ出来た気がします。