16.5K Views
September 26, 19
スライド概要
2019/9/25-6に開催されたUnite Tokyo 2019の講演スライドです。
堂前 嘉樹(株式会社ロジカルビート)
こんな人におすすめ
・Unityの描画フローにもどかしさを感じているプログラマー
・最適化を図りたいと思っているプログラマー
・どのゲームエンジンを選択するか悩んでいるプログラマー
受講者が得られる知見
・SRPを導入することで得られるメリット
・SRPを構築するための細かなテクニック
・描画フローの構築を一から行うための基礎知識
Unityのイベント資料はこちらから:
https://www.slideshare.net/UnityTechnologiesJapan/clipboards
リアルタイム3Dコンテンツを制作・運用するための世界的にリードするプラットフォームである「Unity」の日本国内における販売、サポート、コミュニティ活動、研究開発、教育支援を行っています。ゲーム開発者からアーティスト、建築家、自動車デザイナー、映画製作者など、さまざまなクリエイターがUnityを使い想像力を発揮しています。
SRPで一から描画フローを作ってみた! ~Unity描画フローからの脱却~ 株式会社ロジカルビート 代表取締役 / プログラマー 堂前 嘉樹
自己紹介 3
自己紹介 — 株式会社ロジカルビートの代表取締役かつプログラマー。 — 新横浜にある、プログラマ主体の会社です。 — コンシューマ、スマホ、Unity、UE4、ネイティブと、なんでも対応。 — 前職は大手コンシューマ会社でグラフィックスプログラム担当。 — 2016年のUniteでも講演させてもらいました。 – Unity5を使った「いけにえと雪のセツナ」の雪世界の作り方 – https://www.youtube.com/watch?v=6RppDyZuTt4 4
はじめに 5
Scriptable Render Pipeline (SRP) 6
LWRP HDRP LWRPやHDRPの情報は良く見るようになったが、 SRPで新規構築する話はあまり見ない! 7
チャレンジしてみた! 8
今回やってみたこと 9
SRPを使ってやってみたこと — 某レンダラーソフトのレンダリングを(ある程度)移植。 – 最適化や手間の兼ね合いである程度の処理は省いた。 – ポストフィルタも実装。 — iPhone XSをターゲットとして実行。 – fpsはこだわらなかったが、30fpsでは動いた。 — 検証期間・約3ヶ月。 — LWRPやHDRPからの派生ではなく、SRPを一から構築! 10
機能詳細 — PBRベースのシェーディング。 – Microsurface(Gloss) – Diffusion(Lambertian / Subsurface Scatter) – ※Subsurface Scatterはポスト処理も並行。 – Reflectivity(Specular / Metalness) – Reflection(Mirror / Blinn Phong / GGX / Anisotropic) – ※Subsurface ScatterとAnisotropicの併用不可。 — ライトはDirectional LightとPoint Lightのみ対応。 11
機能詳細 — ベースはDeferred Rendering。 – 半透明はForwardで対応。ディザパターンも可。 – G-Bufferは4枚~8枚利用。 – Subsurface ScatterやAnisotropicを利用する時は8枚。 — シャドウはシンプル。カスケード無し。 – カスケード対応の時間が無かった。 — SSAOも対応。SSRは非対応。 – こちらも時間不足で作り込めていません。 12
※Lee Perry-Smith の Infinite 3D Head Scan。クリエイティブ・コモンズ・ライセンス 3.0 (www.ir-ltd.net で入手可能) 13
調整した状態 ※Lee Perry-Smith の Infinite 3D Head Scan。クリエイティブ・コモンズ・ライセンス 3.0 (www.ir-ltd.net で入手可能) 14
off default Screen Space Sub Surface Scatter ※Lee Perry-Smith の Infinite 3D Head Scan。クリエイティブ・コモンズ・ライセンス 3.0 (www.ir-ltd.net で入手可能) 15 max
Gloss 0.0 1.0 0.0 1.0 Metalness 16
UnityのStandard利用 ※Lee Perry-Smith の Infinite 3D Head Scan。クリエイティブ・コモンズ・ライセンス 3.0 (www.ir-ltd.net で入手可能) 17
18
自前でリッチな 描画が出来た 19
注意点 20
Unity 2018.3.14f1 ↓ Unity 2019.2.5f1 21
「LWRP」で統一します (※2019.3からUniversal Render Pipeline) 22
SRPを使ってみて 23
最初に所感 24
最高です! 積極的に使っていきたい 25
Unityの描画フローに もどかしさ 26
Unityでの経験談 27
その1 投影テクスチャシャドウに変更したい! 28
シンプルな影でいい 29 カメラが作る画像
デプスシャドウ デプス比較 シャドウマップ 影を作る 必ずデプスバッファ 30
投影テクスチャシャドウ デプス比較せず描画 シャドウマップ 影を作る 31 R8バッファでも良い が、変更できない!
カメラを置いて シャドウマップを無理矢理作る Camera増によるコスト ボリュームを どう作る? Castオブジェクトだけ 描画するのが大変 32
シャドウマップ自作 — Unityは通常、デプスシャドウでシャドウを描画する。 — ゲームのカテゴリやシチュエーションによっては、投影シャドウに したい場合がある。 – 主にセルフシャドウを必要としないシチュエーション。 – シャドウマップはR8程度でも良い。 — シャドウの処理をVSMにしたいということもあるかもしれない。 – その際はR16G16のシャドウマップを使いたい。 — シャドウマップのフォーマットは、ユーザー側では変更できない! 33
シャドウマップ自作 — それならシャドウマップを自作しようと試みたとする。 – – 視錐台用のカメラを追加しなければならない。 – 独自フォーマットのRenderTextureを使いたいので。 – カメラ固有のCPU負荷が無駄に掛かる恐れがある。 そのカメラ位置などを自前で計算しなければならない。 – Unity側で算出する情報は取得できないため。 – 品質の高い視錐台を作るためには計算コストが掛かる。 — 総じて手間が掛かって面倒! 34
その2 3D部と2D部での解像度変更 35
3Dモデル等の描画 ・キャラクターや背景などの描画。 ・GPUコストが掛かりやすい。 ・フル解像度ではなく、縮小させた解 像度のバッファで描きたい。 (動的解像度も視野) Camera ポストフィルタ処理等 ・縮小して描いた3D部分のバッファ を、ポストフィルタを掛けつつ、フル 解像度に戻したい。 2D描画(UI) ・ゲーム的に必要なUIを描画。 ・ディスプレイと同じ解像度(フル解 像度)で描きたい。 ・モデル等は描かない。 Camera 36 Camera
3Dモデル等の描画 不透明 半透明 SSAO 縮小バッファ etc.. 37
3D部と2D部での解像度変更 — 3D部分は必要に応じて解像度を動的に変えたい! – 俗にいう動的解像度的なことが行えると良い。 — 2D部分はぼかしたくないのでフル解像度で描きたい。 — 3D→2Dで解像度を変えると、Cameraがまた必要になる。 – 3D→RenderTexture 2D→デフォルトターゲット – OnPreRender() ,OnPostRender(), OnRenderImage()もあるが、スクリ プトを用意しないといけないので手間。 38
3D部と2D部での解像度変更 — 3D部分も、凝ったことがやりたくなる。 – 縮小バッファやSSAO等。 – SSAOはCommandBufferを使えば行けなくは無さそうだが、やや手間。 – 縮小バッファは、縮小バッファを作るところはCommandBufferで対応可 能そうだが、その後エフェクトを描画するところは別Cameraが必要。 (Layerが別なため) 39
その3 RenderTextureとCamera管理 40
描画システム Camera Camera Camera Camera RenderTexture RenderTexture RenderTexture RenderTexture RenderTexture RenderTexture RenderTexture RenderTexture prefab 41
それぞれにスクリプトも 必要になる Cameraが複数必要 実行時に真っ先に ロードしないといけない Scene Game Sceneビューで確認できない! 42
RenderTextureとCamera管理 — 複数のRenderTextureとCameraを管理する仕組みが必要。 それをprefabで用意して、起動時に適応させるしかない。 — 不都合が多く出てくる。 – 起動させないと絵が確認できない。(Sceneビューで見れない) – 実行した時にprefabを真っ先にロードする必要がある。 – Camera間を跨ぐScript処理も書かないといけない。 – 「Camera作ったらこのスクリプトも付けて!」も発生。 — 総じて管理、作成コストが大きくかかる! 43
他にも もどかしいところが たくさん・・・ 44
そこでSRP!! 45
https://docs.unity3d.com/ja/2018.1/Manual/ScriptableRenderPipeline.html 46
バイナリを作成 (RenderPipelineAsset) Graphics Settingsに設定 47
特別なスクリプトも不要 (今回は追加しましたが。。) 48
SRPの可能性 — SRPを使うと描画処理をほぼ乗っ取れるらしい? — 使い方も割と簡単。 – RenderPipelineAssetを作り、Graphics Settingsに設定。 – スクリプト(MonoBehaviour)も特に必要ない。 — Unity描画フローを使うより楽になるのではないか? レンダリング処理は完全に書かないとだけど。 49
SRPの中身を作る(基礎) 50
※弊社ブログで(近日中に)補足します https://logicalbeat.jp/blog/ 51
「完全にカスタマイズ」 どのレベル? 52
最小のRenderPipeline処理 53
一切何も表示されない! 54
LWRPを参考にしたい! 55
— LWRPのパッケージをインストールした状態。 — Library/PackageCacheにインストールしてあるパッケージ の実データ(スクリプトなど)が収められている。 — LWRPは左図の赤枠のところに収められている。 56
最初の取っ掛かり — SRPを新規に作ってRenderPipelineを空にする。 そうすると全く何も表示されない状態! – 「完全にカスタマイズ」なので、当然と言えば当然。 — 最初はLWRPを参考にすると進めやすいです。 – というより、他に無いです。 — LWRP自体はLibrary/PackageCacheにあるので、それを見る。 – LWRPを改造する場合もここから。 57
描画の簡単な流れ 58
最低限動作するRenderPipeline処理 59
それに対応するシェーダ(Unlit相当) 60
最低限の絵は実現できた 61
カメラ一つずつに対して処理 最低限動作するRenderPipeline処理 62
カメラのVPマトリクスなどを作ってる? レンダラやライト等のカリング処理 フィルタリング&ソート 描画命令 終了処理 最低限動作するRenderPipeline処理 63
大きなポイントは 2箇所 64
レンダラやライト等のカリング処理 フィルタリング&ソート 65
レンダラやライト等のカリング処理 66
不要なRendererとライトを省く 67
https://docs.unity3d.com/ScriptReference/Rendering.CullingResults.html 68
カリング処理 — カメラに対してオブジェクトの視錐台カリングを行う部分。 – カメラからカリングのための情報を取得。 – – Camera.TryGetCullingParameters()で行う。 結果は「CullingResult」に格納される。 — ライトのカリングも行われる。 – 視錐台の外にあって、オブジェクトに影響を及ぼさない点光源などはここ で排除される。 – CullingResults.visibleLights — シャドウも考慮。 69
フィルタリング&ソート 70
0 2500 LightModeの合致 Queueが範囲内 2000 71
描画対象Layer設定 72
手前から奥に描画 https://docs.unity3d.com/ScriptReference/Rendering.SortingCriteria.html 73
ソート&フィルタリング処理 — 描画する部分を抑制する処理。 – 半透明だけ描く、不透明だけ描く。 – 特定のレイヤーは描画しない。(UIなど) – 描き方の種類を変える。(LightMode) — オブジェクトのソートの指定方法もここで行う。 – 不透明ならば手前から描く。半透明ならば奥から描く、とか。 — 独自にルールを作れる!! 74
シンプルながらも 描画が出来た! 75
SRPの中身を作る(拡張) 76
自由に構築していい!! 77
実験 縮小バッファ対応 78
79
Camera.targetTexture LightMode=lbForward Queue→0~2500 Blit RT(A) Copy Depth LightMode=lbParticle Queue→2500~3000 RT(B) 単一のCameraで実現できる!! 80 Merge
Camera.targetTextureの 縦横70%サイズのRT(A)を用意 RT(B)にLightMode=lbParticle のみ描画 RT(A)にQueue→0~GeometoryLast まで描画(要するに不透明描画) RT(A)のカラーバッファに RT(B)のカラーバッファを合成 RT(A)にポストフィルタ描画(SSAO等) RT(A)にポストフィルタ描画(ブルーム等) RT(A)の縦横1/2サイズのRT(B)を用意 Camera.targetTextureにRT(A)をコピー RT(B)のデプスバッファに RT(A)のデプスバッファをコピー World UI(体力ゲージ的なの)を描画 81
SRP処理内での拡張 — カメラのデフォルトターゲットに最終的な絵が出力されれば、そ の過程はかなり自由に処理してしまって構わない。 – デフォルトターゲットとは別のRenderTextureを用意して描く。 – シャドウマップのフォーマットを別のものにする、など。 — 縮小バッファも対応できた。 – デプスバッファを縮小コピーした上でブレンドバッファ描画。 — Deferredに限らず、Forward+も実現できるかもしれない。 – Compute Shaderが動かせればチャンスあるかも。 82
Unityの機能は どれくらい活用できるか? 83
ReflectionProbeの適応 84
ビルトインシェーダでのunity_SpecCube0利用 85
unity_SpecCube0を使ってみた 86
DrawingSettings.perObjectData PerObjectData.ReflectionProbes https://docs.unity3d.com/ScriptReference/Rendering.DrawingSettings.html https://docs.unity3d.com/ScriptReference/Rendering.PerObjectData.html 87
設定を追加 88
unity_SpecCube0が適応できた 89
ReflectionProbeの適応 — シェーダ内でunity_SpecCube0を参照しても適応されない! — LWRPを調べてみると「DrawingSettings.perObjectData」に 「PerObjectData.ReflectionProbes」を設定していた。 – オブジェクト毎にどの描画設定を適応するか?の設定。 – 恐らく、SH(LightProbes)も適応できると思われる。 — ※unity_SpecCube0使用時は、「Light –Environment Reflections」の設定に気を付ける。 90
PostProcessing Stack の適応 91
PPS適応前 PPS適応後 ※Lee Perry-Smith の Infinite 3D Head Scan。クリエイティブ・コモンズ・ライセンス 3.0 (www.ir-ltd.net で入手可能) 92
適応したPPS 93
PostProcessing Stackの OnPreCull()とOnPreRender() 94
SRP利用時は動作しないようになっている! 95
private関数なので外から呼べない! 96
PostProcessingRenderContextというのがあったので それを活用して実現 97
PostProcessing Stackの利用 — どうせならPostProcessing Stackを利用したいので試みる。 – 一からポストフィルタを作りたい気持ちはあるが、エンジンの機能はやは り活用できると好ましいので。 — 本家はCameraに付与すれば良かったが動作せず。 — こちらもLWRPで調査。 — 「PostProcessingRenderContext」を活用することで解決した! 98
デフォルトUIシェーダ の活用 99
100
ビルトインシェーダのUI/Default LightModeが存在しない!! 101
LWRPのUI描画部分 SRPDefaultUnlitにすると 表示される!
デフォルトUIシェーダの活用 — さすがにUIまで手を付けたくないので、既存のを使いたい。 だがデフォルトのUIシェーダはLightModeが無い! — 例によってLWRPを調査。 — どうも「SRPDefaultUnlit」というのが該当LightModeだったよう なので、それを使って対処。 103
SRPの中身を作る(その先へ) 104
小ネタをいくつか (※未検証のもあります) 105
デフォルトシェーダの変更 106
新規マテリアル生成時に 特定のシェーダを付与してくれる! https://docs.unity3d.com/ScriptReference/Rendering.RenderPipelineAsset.html 107
デフォルトシェーダの変更 — 独自シェーダを構築すると、デフォルトマテリアルも変えたくなる。 そんな要望もキチッとサポートされている。 — 通常モデル、UI、パーティクルなど、種類ごとに設定可能。 — RenderPipelineAssetのプロパティをoverrideすることで対応。 108
カリング方法の微調整 (※検証不足) 109
カリングに負荷がかかる! ので、あえて行わないようにしたいことがある 110
Cameraのカリングパラメータ cullingOptionsが怪しい? https://docs.unity3d.com/ScriptReference/Rendering.ScriptableCullingParameters.html 111
ので、メンバを調査 CullingOptionsのドキュメントが無い!! https://docs.unity3d.com/ScriptReference/Rendering.ScriptableCullingParameters-cullingOptions.html 怪しいの発見 112
None 結果は変わらず・・・ DisablePerObjectCulling 113
カリング方法の微調整 — カメラから取得したカリングパラメータを編集することにより、カ リングの仕方を微調整できそうな印象がある。 — オブジェクトカリングを敢えてしたくない局面もあるので、それが 出来ないか試してみることに。 – カリング処理でCPU負荷がかさんでしまうため。 – 特にUIなどでは不要なので、ずっとやりたかった。 114
カリング方法の微調整 — が、それっぽい「CullingOptions.DisablePerObjectCulling」を試 してもダメだった。 – ※余談ですが、「cullingPlaneCount」を変更してもダメでした。 — そもそもドキュメントに無いので、あまりオープンになっていない 機能かもしれない。 情報開示されると嬉しいです。 115
まとめ & 要望 116
まとめ — SRPを一から組んで、独自の描画フローを構築できた。 – 描画処理に詳しい人ほど、既存描画フローの挙動に悩まされることがある と思うので、気持ちいいことは気持ちいい。 – 他エンジンではこういった事が出来ないので、非常にポイント高い。 — 処理的にもスリム化が図れるので、描画処理が組める人は一か ら組んでも良いかもしれない。 – 非Unity系からの移植や、トゥーン系ならやりやすそう。 — Camera一つで完結するのも大きい! 117
まとめ — が、エンジンの機能を享受しつつ独自フローを書くとなると、結局 調べ物が多くなる。 – 今回ならReflectionProbeなど。 – LWRPを調べつつ進めるスタンスになると思います。 — LWRPをベースに改造するスタンスも良いかと思います。 – ゲーム的に必要な機能が出てきたら改造する、的な。 — 一から組めるので、敢えて学生さんの勉強などにも良いかも。 118
要望 — 要望として、LWRP自体の情報は出始めていますが、SRPを一か ら作る話をあまり見かけません。 ドキュメントも整備されていないです。 – 今回ならCullingOptionsなど。 — 細かい要望点は多いですが、とにかく情報が欲しいです。 — 今回の講演で「SRPで一から作ってみよう!」という人が増えてき て、情報が多く出てくると幸いです。 119
Thank you!! Twitter:@yoshiking2000 Twitter:@logicalbeat_jp