はじめに
こんばんは、代表の堂前です!
前回、前々回とバッチングの話をしてきたんですが、調べたいテーマが急に降ってきたので・・・。
今回は急遽、「ScriptableRenderLoop」を取り上げます!
※検証したのはMacのUnity5.6.0f3になります。
ScriptableRenderLoopについて
GDC2017期間中に↓のツイートを見かけました。
「スクリプタブルレンダーパイプライン」というものですが、読むからにUnity(のカメラ)内部で行われていた描画フローをある程度制御できる機能っぽく思えます。
自分自身Unityを使っていて非常に便利だなと思う反面、汎用的に使われることを想定して「しっかりしすぎた」描画フローになっていて、それをゲーム毎にカスタマイズしたい想いは強く持っていました。
(エンジンに頼らず独自で描画フローを書いていた人は同じ様に感じていたと思います。)
ということで、Unity2017から入ると言われるこの機能は楽しみに待っていました。
そして!「2017.1.0 Beta 1」がリリースされたので本記事を・・・となったわけです。
ScriptableRenderLoopの情報&設定
ScriptableRenderLoopの情報を集めました。
pdfとドキュメントは各自読んでもらうとして・・・。
今回はgithubでプロジェクト一式を落として実行して雰囲気を掴んでいこうと思います。
以下の手順で準備します。
・Unity5.6.0f3を用意します。
・githubで「Tag」を「unity-5.6.0b10」に変更してダウンロードします。
・解答したものをUnity5.6.0f3で読み込ませます。
ここで気付いた方もいるかもしれませんが・・・。
Unity2017ではなく、Unity5.6.0でも動作するようです!
基本動作の確認
上記のプロジェクトですが「BasicRenderLoopScene」というのが一番分かりやすいので、今回はそれを元に解説を進めます。
↑のGameウインドウの左下にも書かれているのですが、ScriptableRenderLoopのキモになるのが「Edit – Project Settings – Graphics」の「Scriptable RenderLoop settings」という項目です!
ここに「BasicRenderLoop」というアセットを選択します。
↑
↑
↑
これで基本設定はOKで、ScriptableRenderLoopが利用されている状況になります。
「BasicRenderLoop.asset」を選択すると「BasicRenderLoop.cs」を参照していることが分かります。
このスクリプトこそ、描画フローを制御しているスクリプトになります!
このアセットの作成方法やその他細かい話は今回は抜きにして・・・。
スクリプトで描画をしてそうなところをチェックします。
以下の部分が実際に描画フロー処理している部分になります。
public static void Render(ScriptableRenderContext context, IEnumerable<Camera> cameras)
{
foreach (var camera in cameras)
{
// Culling
CullingParameters cullingParams;
if (!CullResults.GetCullingParameters(camera, out cullingParams))
continue;
CullResults cull = CullResults.Cull(ref cullingParams, context);
// Setup camera for rendering (sets render target, view/projection matrices and other
// per-camera built-in shader variables).
context.SetupCameraProperties(camera);
// clear depth buffer
var cmd = new CommandBuffer();
cmd.ClearRenderTarget(true, false, Color.black);
context.ExecuteCommandBuffer(cmd);
cmd.Release();
// Setup global lighting shader variables
SetupLightShaderVariables(cull.visibleLights, context);
// Draw opaque objects using BasicPass shader pass
var settings = new DrawRendererSettings(cull, camera, new ShaderPassName("BasicPass"));
settings.sorting.flags = SortFlags.CommonOpaque;
settings.inputFilter.SetQueuesOpaque();
context.DrawRenderers(ref settings);
// Draw skybox
context.DrawSkybox(camera);
// Draw transparent objects using BasicPass shader pass
settings.sorting.flags = SortFlags.CommonTransparent;
settings.inputFilter.SetQueuesTransparent();
context.DrawRenderers(ref settings);
context.Submit();
}
}
詳細説明は省きますが、「カリング→描画設定→画面クリア→ライトセットアップ→不透明描画→Skybox描画→半透明描画」というのを全カメラに対して行なっている様です。
本当に制御できているかを確認するため、一部をコメントアウトして試してみましょう。
↓
↓(36行目をコメントアウト)
↓
↓
↓(更に31行目をコメントアウト)
↓
半透明描画と思わしき箇所と、Skybox描画を思わしき箇所をコメントアウトしてみました。
確かに描画されないのを確認できました!
ScriptableRenderLoopで描画フローをある程度いじれそうです。
ScriptableRenderLoopで夢広がる
今回は単純なテストでScriptableRenderLoopの動作を実感しました。
しかし大事なのは、この機能でどういうことが出来るかを考えることと思います。
自分が考えている、やってみたい処理は次の様な感じです。
(ScriptableRenderLoopで出来るかどうか分からないですが、書くだけ書いてみます。)
・シャドウマップで独自フォーマットを利用してVSMを実現する。
(シャドウ用のカメラはエンジン側のを利用したいので。)
・UIなどを描くカメラではカリングを無効化する。
(どうせ全部映ると分かっているので処理の無駄。)
・カメラで描くオブジェクトが無いと判断した時は、カメラのクリア処理をスキップ。
(UI用カメラを多重に持っている時に有効。)
これらが実装できたらいいなと思うのですが、これからも調査が必要そうです。
基本的にはUnity内部の描画フローで事足りますが、機能的もしくは負荷的に突き詰めたい時はこのScriptableRenderLoopと向き合っていけると、他と差をつける使い方が出来るかなと思います。
【免責事項】
本サイトでの情報を利用することによる損害等に対し、株式会社ロジカルビートは一切の責任を負いません。