レンダリングはまだ進化しているか?

11.4K Views

November 27, 23

スライド概要

■概要
RE ENGINEの第八/第九世代のコンソールで利用されているレンダリングの技術の紹介を行います。
CPU負荷軽減のためのバインドレスを利用したレンダリングの最適化や、各種のレンダリング技術について紹介します。
また、将来のタイトル向けのレンダリング技術について紹介します。

※CAPCOM Open Conference Professional RE:2023 で公開された動画を一部改変してスライド化しております。

■想定スキル
Graphics APIの知識、リアルタイムCGのレンダリング

詳細は下記公式サイトをご確認ください。
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
CAPCOM Open Conference Professional RE:2023
https://www.capcom-games.com/coc/2023/

カプコンR&Dの最新情報は公式Twitterをチェック!
https://twitter.com/capcom_randd
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

profile-image

株式会社カプコンが誇るゲームエンジン「RE ENGINE」を開発している技術研究統括によるカプコン公式アカウントです。 これまでの技術カンファレンスなどで行った講演資料を公開しています。 【CAPCOM オープンカンファレンス プロフェッショナル RE:2023】  https://www.capcom-games.com/coc/2023/ 【CAPCOM オープンカンファレンス RE:2022】  https://www.capcom.co.jp/RE2022/ 【CAPCOM オープンカンファレンス RE:2019】  http://www.capcom.co.jp/RE2019/

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

関連スライド

各ページのテキスト
1.

レンダリングはまだ進化しているか? レンダリングはまだ進化しているか?と題してお話をさせていただきます。 ©CAPCOM 1

2.

目次 Ray Tracing Bindless 見た目の改善 将来的な機能 今回はこのような内容をベースにRE ENGINEのレンダリングの進化をお話します。 2 ©CAPCOM 2

3.

目次 Ray Tracing Bindless 見た目の改善 将来的な機能 はじめにRay Tracingです。 3 ©CAPCOM 3

4.

Ray Tracing デビル メイ クライ 5 スペシャルエディション、エグゾプライマルまでリリース • 今後のタイトルも利用 MaterialとAcceleration Structureについて発表 • DenoiserなどはAdvances in Ray Tracingで発表 Ray Tracingは、第9世代のコンソールのローンチに合わせてRE ENGINEに対応しました。 デビル メイ クライ 5 スペシャルエディションは、 キャラクターや背景を可能な限りAcceleration Structureにしました。 4 また、RE ENGINEで初めてGIやReflectionにRay Tracingを利用しました。 バイオハザード ヴィレッジは背景のみにとどまりましたが、GIやReflectionに利用しています。 さらに、UpdateでRay Tracingに対応したバイオハザード7、RE:2、RE:3は、 キャラクターを含むGIやリフレクションを利用しています。 Reflectionのみ対応したバイオハザードRE:4やカットシーンのみ対応したエグゾプライマルなどがあります。 Ray Tracingは各タイトルが、実行時のパフォーマンスや、表現による何を使うかを決めています。 今回、私はMaterialとAcceleration Structureについてお話をします。 Denoiserなどの表現部分に関しては、Advances in Ray Tracingで説明をします。 ©CAPCOM 4

5.

Ray Tracingの実装と指針 どのプラットフォーム、どのIHVでも安定した動作 • Inline Ray Tracing(RayQuery)を利用 • Inline Ray TracingはDXRの様な任意のシェーダを複数個利用しづらい • 単一のマテリアル関数のみを利用 • 従来の最適化の知見が使える可能性 • Bindlessリソースに対応すれば任意のシェーダの代用品になりえる アートパイプラインに影響を与えない • Ray Tracingを有効にしたら従来の近似機能を置き換える • Opaque MeshのIndirect Illuminationを置換など • 作成済みのAssetに手を入れずに導入を行う • メッシュやマテリアルへの修正は可能な限り最小限にする Ray Tracingは、どのプラットフォーム、どのIHVでも安定した動作が必要です。 そのためRE ENGINEはInline Ray Tracingを利用しました。 Inline Raytracingは、DXRの様な任意のシェーダを利用しづらいです。 現在リリースされているタイトルは、単一のマテリアル関数のみを利用しています。 単一のマテリアルにすることで、従来の最適化の知見が使える可能性があります。 5 マテリアルの対応には、任意のテクスチャやUVを使える必要があります。 Bindlessリソースを利用し多様なマテリアルを表現しています。 また、アートパイプラインに影響を与えないことも重要です。Ray Tracingを有効にしたら従来の機能を置き換えます。 たとえば、不透明物体の間接照明を置き換えたりします。 これを可能にするために、作成済みのAssetに手を入れずに導入を行います。 現実問題として多少の設定変更は行います。メッシュやマテリアルの修正は可能な限り最小限にしています。 ©CAPCOM 5

6.

Ray Tracingのマテリアル対応関係 RE ENGINEは、ArtistがShader Graphを使い作成 • TextureやShader 変数の命名規則は、Presetが多く使われている • ゲーム開発チーム固有のものもあるため特別な対応を行う Ray Tracingの模倣シェーダ 背景のシェーダ 次はRay Tracingのマテリアル対応関係です。 RE ENGINEはシェーダグラフを使いアーティストがシェーダを作成します。 Ray Tracingのマテリアルは、いうなれば左のグラフを右のグラフに置き換えるようなものです。 6 対応関係に使うのは、 Textureや Shader 変数の命名規則です。 これらは、シェーダグラフのPresetの名前が多く使われます。 しかしながら、ゲーム開発チーム固有のものも存在するため、特別な対応が必要になります。 ©CAPCOM 6

7.

既存のマテリアルとRay TracingのBinding 対応関係の設定はjsonで対応関係ファイルを定義 Rasterize Ray Tracing "LayerMap":{ "Redirects":[ { "Type":"L1L2XX", "Name":"LayerMaskOcclusionMap" }, { "Type":"L1L2XX", "Name":"LayerMaskOcclusionMap" } ] }, "Layer1AlbedoMap":{ "Redirects":[ { "Type":"ALBD", "Name":"Snow_ColorRoughnessMap" }, { "Type":"ALBD", "Name":"BaseDirecticMap1" }, { "Type":"ALBM", "Name":"BaseMetaMap1" } ] }, "LayerNormalMap":{ "Redirects":[ { "Type":"NRRC", "Name":"NormalRoughnessCavityMapBase" }, { "Type":"NRRC", "Name":"NormalRoughnessCavityMap1" }, { "Name":"NormalRoughnessMap1" } ] }, "Layer2AlbedoMap":{ "Redirects":[ { "Type":"ALBD", "Name":"Snow_ColorRoughnessMap" }, { "Type":"ALBD", "Name":"BaseDirecticMap2" }, { "Type":"ALBM", "Name":"BaseMetalMap2" } ] }, Json タイトルのマテリアルをRay Tracingに対応する場合は、右側のjsonのように対応関係を記述しています。 バインドした結果を見てみましょう。 画像は、バイオハザード ヴィレッジの適当なアセットを使いテストしたものです。 画面中央に鏡を置いた状態で撮影したものです。 画面左側は、従来のラスタライザーで表示したものです。 右側は、Ray Tracingの結果を比較したものです。 7 なんとなく似た結果となっています。 一部のデカールなどのマテリアルはRay Tracingに対応をしていません。 テーブルの血痕がなどです。 ここまでで、マテリアルの表現はできるようになりました。 ©CAPCOM 7

8.

Acceleration Structure 頂点単位でRay Tracing用のデータ構造のAcceleration Structureが必要 メッシュなどはBottom Level Acceleration Structure(BLAS)が必要 • Static Meshなら、一つのBLASをInstancingとして再利用 • Environments, Props • Dynamic Meshなら、Object単位でBLASをUniqueに作成 • 形状の変形後の位置のBuffer, Acceleration Structure(AS)のメモリが必要 • 形状の変形に伴う更新作業も必要、ASの RefitもしくはBuildのGPUの処理時間が必要 • Skinning Mesh, Destruction, etc. Dynamic Meshの増加はメモリとGPU処理を消費 次はAcceleration Structureになります。 Ray TracingはAcceleration Structureと呼ばれるRay Tracing用のデータ構造が必要になります。 メッシュなどは、BottomLevelAccelaration Structure(BLAS)が必要になります。 8 Static Meshなら、一つのBLASをInstancingとして再利用することができるため、 既存のメッシュと似たような扱いになります。Static Meshは背景物や設置物にあたります。 Dynamic Meshなら、Object単位でBLASをUniqueに作成する必要があります。 形状の変形後の位置のBufferとAcceleration Structureのメモリが必要になります。 また、形状の変形に伴う、Acceleration Structureの Refit もしくは、Buildを実行するための、GPUの処理時間が必要です。 Skinning Meshが該当します。 このことから分かるように、Ray Tracingは、Dynamic Meshが増加すると、メモリとGPUの処理時間を消費します。 そのため、Dynamic Meshのために特別な対応が必要になりました。 ©CAPCOM 8

9.

1 JointのメッシュをStatic Meshに降格 主にはドアなどの、インタラクト可能なオブジェクト • BLASの削減、Skinningの時間の削減 まずは簡単な問題から対応をしましょう。 ゲームを通して有効なSkinning Joint数を調査をすると、面白い事実がわかってきました。 9 扉などのモデルには、一つのジョイントしか入っていないSkinning Meshが多数存在していることがわかりました。 こういった箇所を、自動でStatic Meshに変換することにより、 BLASの作成するメモリと、GPUの処理時間の削減につながりました。 ©CAPCOM 9

10.

Dynamic Mesh 多くのSkinningを使った人体モデルは、Refitだけでも機能 Skinningを使ったDestructionはRefitだけでは不十分 • 一定間隔で更新? 次は複雑なメッシュの対応です。 ここでは、Skinning MeshとDestructionについて扱います。 Skinning Meshは、通常RefitとよばれるAABBの再設定だけでも十分な結果が得られます。 でもDestructionはどうでしょうか? 10 カプコンでは伝統的にSkinning Meshを使い、Destructionを再生しています。 ビデオを見てみましょう。 このビデオは、DestructionをRefitだけで実行した例になります。 GeForce RTX 2070 SUPERを使い、Ambient Occlusionを計算するテストです。 時間がたつととても重たくなっています。 これは、Refitだけを使うとBLASの品質が低下し、Ray Tracingの性能が低下していることを示しています。 ©CAPCOM 10

11.

より安定したBLASの更新評価 CPUでGPUのBLASの粗い再現を行う • Skinning MeshのBounding Boxを再利用して評価用のBVHを構築 • Bounding Box はJoint単位のAABB群から作成 • 一つのメッシュのJoint数はバイオハザード ヴィレッジでは最大で256個 • BVHはLinearBVHを利用 CPUで、GPUのBLASの粗い再現を行い、より安定したBLASの更新評価を導入しました。 この時に Skinning MeshのBounding Boxを計算する際に計算する、 細かなAABBを再利用して、評価用の簡易的なBVHを構築します。 11 左の画像は、キャラクターの最終的なBounding Boxを表しています。 真ん中は体のジョイント単位のAABB群、右は頭のジョイント単位のAABB群となります。 これらのAABB群から、LinearBVHを使用しSAH(surface area heuristic)を算出します。 SAHが閾値を越えたら、更新をするようにしています。 詳細はGDCの資料をご覧ください。 ©CAPCOM 11

12.

より安定したBLASの更新評価 refitのみ AABBのSAHを利用したbuildとrefitの組み合わせ 左側はRefitのみで、右側はCPUのBVHを使いbuildタイミングを決定しています。 右の図を見ると、GPUの処理時間がある程度上がったらbuildされることで、 性能改善し、安定したフレームレートが出るようになっているように見えます。 12 この方法は、等倍スケールには適応できませんが、実践的な方法ではないかと思います。 ©CAPCOM 12

13.

BLASの最適化 Ray TracingアップデートからAsync ComputeのPC対応 • Dynamic MeshのBLAS更新はAsync Compute必須 つぎは、最適化です。 バイオハザード ヴィレッジは、RE ENGINEのPC版はAsync Computeに非対応でした。 13 バイオハザード7、RE:2、RE:3のRay Tracingアップデートは、 動的な物体のBLAS更新の効率化のためにPC版のAsyncCompute対応を行いました。 CommandListで同期ができないため、PCは特別に重たいタスクのみを実行するようにしています。 Dynamic Meshが多数存在する場合、BLASの refitやbuildは、 AsyncComputeで動かすことが性能改善につながります。 ここまででゲームでのAcceleration Structureの作成は終わりです。 ©CAPCOM 13

14.

Ray Tracingの応用 Light Probe 従来はマルチバウンスをすると貫通した光が問題 • Cube mapの撮影処理の再利用は品質が悪かった Ray Tracingは交差判定 • マルチバウンスしても安定した結果が作成可能 次にRay Tracingの応用例です。 まずは、Light Probeです。 従来のRE ENGINEはCube mapの撮影を再利用してLight Probeを作成しています。 14 ですが、マルチバウンスで光が貫通する問題がありました。 これは1パス目でベイクした結果を2パス目ではプローブで補間したものを使うため、 プローブの補間を遮断しきれない場合、不正な見た目が発生します。 Ray Tracingで作成する場合は、単純な光の追跡になるため、 遮蔽を正しく処理できるため、マルチバウンスも正しく表現できます。 また、見た目も、シャドウレイを飛ばすことで、 シャドウマップより安定した結果が高速につくれるようになりました。 ©CAPCOM 14

15.

Ray Tracingの応用 Lightmap ストリートファイター6の一部のステージで背景にLightmapを使用 • エンジンでベイクするため機能としてRay Tracingを利用 さらにストリートファイター6は一部のステージでLightmapを使いたいという要望がありました。 Lightmapには、直接照明も焼きこみたいという要望もありました。 15 左側がLightmapで右側がLight Probeです。 ここでもRay Tracingを使いBakeを行っています。 ちょうどオレンジ色の部分が照明も含めたベイクになります。 影が直接照明も焼かれています。 ©CAPCOM 15

16.

Ray Tracingの応用 Lightmap ストリートファイター6の一部のステージで背景にLightmapを使用 • エンジンでベイクするため機能としてRay Tracingを利用 テクスチャを抜いた感じではこんな感じです。 16 ©CAPCOM 16

17.

Ray Tracingの応用 SignedDistanceField SDF作成もRay Tracingは容易に実装可能 • ゲーム中のシーンデータのベイクに利用 初期のSDF SDFAO 最後にSignedDistanceFieldのベイクにもRay Tracingを利用しています。 ゲーム中のシーンでベイクすることもRay Tracingを使えば容易に実現できます。 ハードウェアのRay Tracingは、ゲームランタイムだけではなく開発のツールとしても有用な機能です。 17 ここまででRay Tracingの話はおしまいです。 ©CAPCOM 17

18.

目次 Ray Tracing Bindless 見た目の改善 将来的な機能 つぎはBindlessについてのお話です。 Bindlessは、テクスチャやバッファなどを明示的にGraphicsのAPIにセットしない方法です。 18 ©CAPCOM 18

19.

Bindless バイオハザード ヴィレッジ • 第8世代のコンソールと第9世代のコンソールの 二つの世代をまたがるタイトル • CommandListの作成時間に多くのCPU時間を消費 • リソースバインドはShaderのReflectionを利用した Data Drivenな実装 • Batch間でDescriptor Tableの再利用率が低い • シェーダやマテリアルでDescriptor Tableの 組み合わせがユニークになり再利用率が低下 Bindlessを利用してMeshのマテリアルを表現 REENGINEのBindlessは、Ray Tracing対応時に行いました。 Bindlessをさらに一般化して利用したのが バイオハザード ヴィレッジです。 このタイトルは、第8世代と第9世代のコンソールでリリースされています。 19 RE ENGINEの各Graphics APIへのリソースバインドは、 シェーダをコンパイルしたリフレクションからData Drivenに決定をしています。 シェーダグラフにより大量のリソースを利用されるようになると、 GPU向けのCommandListの作成時間が長くなる問題が出てきました。 この多くは、マテリアル単位でシェーダが、異なるテクスチャのバインドを行っていることです。 こうなると、Batch間でDescriptor Tableの再利用がほぼできないため性能が低下していましました。 これは特にXBOX Oneで問題となりました。 そこで、Bindlessを利用してMeshのマテリアルを表現することで、Descriptor Tableの再利用率の改善を行います。 ©CAPCOM 19

20.
[beta]
Bindlessの対応範囲
一般化するためにDirectX12
• ShaderModel6.0から6.5まではSpaceでBindless Resourceにアクセス
• ShaderModel6.6はResourceDescriptorHeapでBindless Resourceにアクセス
BindlessはShaderResourceView (SRV) のみ
• ShaderからHandleでTextureへアクセス
• Streaming TextureもIndexをベースに更新

#if !defined(HEAP_DIRECTLY_INDEXED)
.....
Texture2D<float4> BindlessTexture2D[] : register(t0, space4);
.....
#endif
Texture2D<float4> getBindlessTexture2D(uint handle) {
#if defined(HEAP_DIRECTLY_INDEXED)
return ResourceDescriptorHeap[NonUniformResourceIndex(handle)];
#else
return BindlessTexture2D[NonUniformResourceIndex(handle)];
#endif
}
.....

ここからは、話を一般化するためにDirectX12をベースにお話しをします。
RE ENGINEは、ShaderModel6.0から6.5まではspaceでBindlessの範囲を指定しています。

20

比較的新しいタイトルはShaderModel6.6へ移行しており、ResourceDescriptorHeapを使えれば使用します。
BindlessとしてアクセスするのはShaderResourceView(SRV)のみに限定します。
シェーダからのテクスチャへのアクセスは、ハンドルを利用します。
これは、ストリーミングテクスチャの更新時にもハンドル自体は変わらずに中身の差し替え対応するのに有利です。
では、どのようにマテリアルをBindless対応にしましょうか?

©CAPCOM

20

21.

Shader GraphのパラメータをBindless化 Shader GraphのCode生成時にBindless用の構造を出力 • ユーザー定義の定数値とテクスチャをBindless化 • プロジェクトの設定でBindless/非Bindlessをカジュアルに切り替えが可能 RE ENGINEはShader Graphを使っています。 なので、Code生成時にBindless用の構造を出力できるようにします。 ユーザー定義のパラメータとテクスチャのみをBindless化します。 21 また、Bindlessの使用の有無は、プロジェクトの設定でBindless/非Bindlessを切り替えるようにしています。 ©CAPCOM 21

22.

Materialの変数のBindless化 従来のConstantBuffer • シェーダグラフに従いパラメータを作成 cbuffer UserMaterial { float4 VAR_BaseColor; float4 VAR_EmissiveColor; float4 VAR_Bulb_Color; float4 VAR_LampShade_Color; float VAR_EmissiveIntensity; float VAR_EmissiveRate; float VAR_EmissiveRateGamma; float VAR_Metallic; ……. }; まずは、手始めにパラメータをBindless化を行います。 従来はConstantBufferとして定義されています。 22 このConstantBufferはシェーダグラフのパラメータから作成しています。 ©CAPCOM 22

23.

Materialの変数のBindless化 ConstantBufferから巨大なStructuredBufferに変更 • StructuredBuffer<uint4> BindlessBuffer; • 32MiB程度 • パラメータはすべてstaticなグローバル変数で定義 static float4 VAR_BaseColor; static float4 VAR_EmissiveColor; static float VAR_EmissiveIntensity; static float VAR_EmissiveRate; static float VAR_EmissiveRateGamma; static float VAR_Metallic; static float VAR_Roughness; static float VAR_Translucency; static float VAR_UV_Select; static float VAR_use_Bulb; static float4 VAR_Bulb_Color; static float VAR_Bulb_Intensity; static float VAR_Bulb_Pow_Rate; static float VAR_Bulb_Levels_min; …. void initializeUserMaterialConstantsFromBindlessBuffer(uint BindlessOffsetByte){ const uint index = BindlessOffsetByte / 16; const uint4 block0 = BindlessBuffer[index + 0]; const uint4 block1 = BindlessBuffer[index + 1]; …… const uint4 block7 = BindlessBuffer[index + 7]; const uint4 block8 = BindlessBuffer[index + 8]; VAR_BaseColor.x = asfloat(block0.x); VAR_BaseColor.y = asfloat(block0.y); VAR_BaseColor.z = asfloat(block0.z); VAR_BaseColor.w = asfloat(block0.w); VAR_EmissiveColor.x = asfloat(block1.x); VAR_EmissiveColor.y = asfloat(block1.y); VAR_EmissiveColor.z = asfloat(block1.z); VAR_EmissiveColor.w = asfloat(block1.w); …… } 次に、ConstantBufferから巨大なStructuredBufferに変更します。 バイオハザード ヴィレッジは、StructuredBufferをuint4単位でアクセスできるようにします。 23 メモリは32MiB程度を割り当てます。 シェーダのパラメータは、すべてstaticなグローバル変数として定義し、初期化関数を使いパラメータの初期化をします。 初期化は、専用の関数にオフセットバイトを指定することで行います。 ©CAPCOM 23

24.

テクスチャのBindless化 パラメータの一部としてテクスチャのhandleを保持 • 任意のパラメータを保持できるため幾らでも慎重可能 static Texture2D BaseMetalMap; static Texture2D NormalRoughnessMap; static Texture2D EmissiveMap; …. void initializePSTextureFromBindlessBuffer(uint BindlessOffsetByte){ const uint index = (BindlessOffsetByte / 16); const uint4 block0 = (BindlessBuffer[index + 9].block); BaseMetalMap = getBindlessTexture2D(block0.x); NormalRoughnessMap = getBindlessTexture2D(block0.y); EmissiveMap = getBindlessTexture2D(block0.z); } 次にテクスチャのBindless化です。 テクスチャもstatic変数として定義します。 24 テクスチャもパラメータと同様のオフセットバイトから、各デスクリプターを復元します。 つまり、従来のconstant bufferの直後に、テクスチャ用のインデックスを保持していることになります。 ©CAPCOM 24

25.

実際のBindless情報の作成と更新 32MiB程度のBindlessBufferをHeapAllocatorとして使用 • Shader Graphの生成アルゴリズムに従い必要なパラメータ数でメモリを確保 • 確保したメモリのオフセットバイトはマテリアル描画時に必要な情報 • 我々はBindlessMaterialHandleと呼ぶ • BindlessMaterialHandleを使いGPU上のBindlessBufferを更新 • CPUのmemcpyと同じように、メモリ構造を更新 実際のBindless情報の作成と更新は、CPU側でメモリ範囲を分配するようにしています。 現在は、VideoMemory用のHeapAllocatorを再利用しています。 25 シェーダグラフの生成アルゴリズムに従い、 必要なパラメータ数やテクスチャの数からサイズを求め、メモリを確保します。 こうしたメモリのオフセットバイトは、BindlessMaterialHandleと呼んでいます。 BindlessMaterialHandleを使いGPU上のBindlessBufferを更新します。 これはCPUのmemcpyと同じように、メモリ構造を更新となります。 ©CAPCOM 25

26.

DrawCallの改変 RE ENGINEはDrawやDispatchに32bit Root Constantを設定可能 • D3D12_ROOT_PARAMETER_TYPE_32BIT_CONSTANTSに相当 • パラメータはバッチ毎に設定を逐次設定 • 未対応プラットフォームはConstant Bufferとして動作 単品のDrawCall • BindlessMaterialHandleをRoot Constantに直接指定 InstancingのDrawCall • Instancingの管理バッファにBindlessMaterialHandleを指定 さて、最後に従来のドローコールの改変です。 GPU上の特定のStructuredBufferの中にパラメータが入っているため、外部から読み込むオフセットを指定する必要になります。 26 RE ENGINEは、DrawやDispatchに32 bit の即値を入れる機能としてRoot Constantを設定できるようにしてます。 これはバッチ毎に設定を逐次行います。 未対応のプラットフォームは、Constant Bufferとして動作させます。 Root Constantを使い単品のDrawCallであれば、直接BindlessMaterialHandleを指定します。 また、InstancingのDrawCallであれば、Instancingの管理バッファにBindlessMaterialHandleを指定します。 ©CAPCOM 26

27.

CPUの最適化の結果 非Bindlessの10.3msからBindless化で8.2msに削減 • Resource Barrierの作成時間 2.1msから1.79msへ削減 • GbufferのCommandListの作成時間 3.3msから2.1msへ削減 CPUの最適化の結果をみてみましょう。 計測環境は図の場所にて、XBoxOneの開発ビルドで計測をしました。 手動で計測しているため、完全に同じ場所、同じタイミングではありません。 27 最適化の比較です。 ResourceBarrierの作成時間は、従来の2.1msから1.79msとなりました。おおよそ0.3ms短縮しています。 次に、commandlistの作成のうち重たいGbufferを見てみましょう。従来のGbufferは、3.3msから、2.1msになりました。 要因は、従来のGbufferは、バッチ数が927個で、ユニークなDescriptor Tableは864個存在しました。 BindlessのGbufferは、バッチ数が936個で、ユニークなDescriptor Tableは96個になりました。 DescriptorTableが再利用されるようになり、DescriptorTableの作成時間をスキップできるようになりました。 Bindless化することで、cpuのcommandlistの作成時間は改善しました。 ©CAPCOM 27

28.

GPUの最適化 CPUは性能改善、GPUは性能低下 • 原因はStructuredBuffer経由により各パラメータがVGPRへ展開 • Instancing描画時に顕著 VGPRをSGPRに変換するためにScalarizationを明示的に実行 • BindlessMaterialHandle単位でScalarization 従来 Bindless Bindless+Scalarization 12 textures 68VGPR 124VGPR 72VGPR 3 textures 32VGPR 60VGPR 56VGPR Bindlessに移行することで、CPUは改善しましたが、GPUの性能は低下しました。 この原因は、Constant BufferやTextureなどが、StructuredBuffer経由になったことです。 特に顕著なのは、Instancingです。 28 InstancingのIndexがPixelShaderではUniformであるとは判断できないのです。 結果として、レジスターが増加傾向になります。 今回は、AMD向けでよく使われるScalarizationを導入します。 ここでは、バイオハザード ヴィレッジのlookdevシーンから、 適当なシェーダを取り出して、XBOXOneでの各シェーダのレジスター使用量を表にしてみました。 非Bindlessが68VGPRで、Bindlessでは124VGPRだったところが、最適化により72VGPRにレジスターが減りました。 これによりGPUの並列度とメモリアクセスの改善が行われました。 ©CAPCOM 28

29.

その他のBindlessの利用例 多くはVideo Memoryの削減のための利用 • Local Cube map(Reflection Probe) • LocalCubemapはランタイム中のTexture Arrayなどへのコピーは不要 • 任意の解像度を保持可能 • Forward RendererのDecal • 以前は大きなTexture2DAtlasだった • 解像度の自由、Textureの圧縮、Mipmapを保持可能 • SignedDistanceField • Atlas的な3DTextureは不要 • 異なる精度で保持が可能(BC4、R8Unorm,R16Float…) Bindlessの利用例を見てみましょう。 そのほとんどは、Video Memoryの削減です。 29 従来は内部のメモリのコピーをして持っていた処理が、 Bindlessにすることでリソースをそのまま参照できるようになりました。 これにより、データ管理がより直接的になり、メモリも削減されます。 ©CAPCOM 29

30.

Bindlessの反作用 Bindless化による不安定化 • すべてGPU上で管理、未初期化、更新ミスで不安定化 • データブレイクやクラッシュダンプからの状態確認は絶望的 使用できる武器 • NVIDIA Aftermath+ NVIDIA Nsight Graphics • 問題発生個所の実行中のシェーダの命令単位でminidump出力 • RE ENGINEのゲーム開発中はデフォルトでAftermathが有効 • コンソールのデバッグ機能 GPUクラッシュは専門的な知識が必要 • 可能な限り自動制御 • 共通のインターフェイスを使うことが重要 パフォーマンスやメモリが致命的な処理以外はBindlessを使用しない ここまでは、Bindlessの利点でしたが、使用することによる反作用があります。 従来のdescriptorなどは、すべてCPUで管理していました。 これは、デバッグ機能やデバッグレイヤーで安定度を高められました。 30 ですが、Bindless化は、すべてGPU上で管理されるため、未初期化や、更新ミスで不安定化します。 不安定化は すなわちGPUのクラッシュに通じます。 使う側の問題ですが、GPU上ですべて管理されたものを扱うため、GPUに対してデバッグを行うのは困難です。 PCの場合、最も役に立つのはNVIDIAのAftermathです。 RE ENGINEは開発中常にAftermathを有効化し、GPUがクラッシュするとmini dumpを生成します。 このminidumpは、shader codeの問題の洗い出したり、 バッファオーバランを指摘してくれるため、問題の範囲をある程度絞ることができます。 特にminidumpを生成してもらえるのはQAでの不具合調査に役立ちます。 ©CAPCOM 30

31.

Bindlessの反作用 Bindless化による不安定化 • すべてGPU上で管理、未初期化、更新ミスで不安定化 • データブレイクやクラッシュダンプからの状態確認は絶望的 使用できる武器 • NVIDIA Aftermath+ NVIDIA Nsight Graphics • 問題発生個所の実行中のシェーダの命令単位でminidump出力 • RE ENGINEのゲーム開発中はデフォルトでAftermathが有効 • コンソールのデバッグ機能 GPUクラッシュは専門的な知識が必要 • 可能な限り自動制御 • 共通のインターフェイスを使うことが重要 パフォーマンスやメモリが致命的な処理以外はBindlessを使用しない また、コンソールは優秀なデバッグ機能をもっているため、プラットフォーム非固有の問題で役立ちます。 ただ、現時点でもGPUクラッシュは専門的な知識が必要です。 31 Bindlessの管理機構をいくら自動制御にしても、思わぬケースで不正なアクセスでクラッシュすることがあります。 可能な限り共通のインターフェイスを使い、可能な限り保護機能を一般化して利用することが重要です。 なので、個人的には実行時間やメモリが致命的な処理以外は、Bindlessを使わないのが一番です。 安定性はとても重要です。 ©CAPCOM 31

32.

目次 Ray Tracing Bindless 見た目の改善 将来的な機能 さて次です。 見た目の改善は常にされていますが、効果的だったものを紹介します。 32 ©CAPCOM 32

33.

不可視法線問題への対応 シェーダの結果見えない法線が形成 • 主に法線マップにより発生 環境マップと平面 環境マップと法線マップ ここでは、不可視法線問題への対応について紹介します。 通常の法線マップを使わない場合、見えている面は可視法線であることがほとんどです。 33 反射している画像には水平面以下は映り込みません。 ですが、法線マップを適応すると、右の図のような見た目になります。 この時ところどころに見える暗く見える部分は、見えない法線により水平線より下の環境マップを参照している状態です。 ©CAPCOM 33

34.

不可視法線問題への対応 視線と法線の内積で不可視領域を可視化 この問題は視線と法線の内積(dot product)ですぐにわかります。 左は法線マップを可視化したもので、右は視線と法線の内積したものです。 本来は見えない法線です。 34 私たちも、以前からこの問題に気付いていましたが、無視をしてきました。 とはいえ、さすがに第九世代も中盤なので、手を打ちたくなってきました。 ©CAPCOM 34

35.

不可視法線問題への対応 シェーディング時に見えない法線を見えるように修正 • バイオハザード RE:4 から導入 そこで、我々は、シェーディング法線の不適切な結果を防ぐために、 ポリゴンの平面であるgeometry normalを使い修正をする機能を追加しました。 この機能は、シェーダ単位でON/OFFできるようにしていますが、多くのシェーダで利用されています。 35 これにより、見えない法線がなくなり、より安定したシェーディング結果が得られるようになりました。 ©CAPCOM 35

36.

従来法線+直接照明 従来の法線と直接照明の結果です。 36 ©CAPCOM 36

37.

法線修正+直接照明 修正後の直接照明です。 より見た目の破綻が感じられにくくなっています。 37 修正方法の是非はあると思いますが、見えない法線がなくなることで安定した安定した結果が得られます。 ©CAPCOM 37

38.

目次 Ray Tracing Bindless 見た目の改善 将来的な機能 最後に将来の機能について話をします。 38 ©CAPCOM 38

39.

MeshShader 頂点をMeshletと呼ばれる単位で分割して処理 • 64triangle/128triangle単位で保持 利点 • 頂点バッファを柔軟な圧縮 • 一つのMeshletのすべての頂点のUVや頂点カラーなら一つの値だけ保持 • メモリの削減に寄与 • カリング処理 • ComputeShaderやAmplificationShaderでカリングも可能 • シャドウマップ作成時に明確に性能改善 欠点 • 未対応ハードウェア • VertexShaderで模倣したコードを再現 • 新しいGPUでないと性能が出にくい 将来の機能としては、MeshShader対応があります。 現在開発中のタイトルは、MeshShaderを利用した背景のレンダリングを行っています。 主な導入理由は、頂点バッファの柔軟な圧縮にあります。 39 Meshletとよばれる単位で区切られた描画単位で、データの圧縮や解凍を行うことでVideoMemoryの削減になります。 位置の量子化を含めて多くのケースで40%以上のデータ圧縮が効きます。 また、従来から使用しているGPUのオクルージョンカリングの粒度は、768三角形単位でのカリングでした。 Meshletは128三角形単位となるため、より細かなカリングを実現します。 MeshShaderが使えないハードウェアは頂点シェーダで模倣したコードを動かしますが、頂点再利用率が悪い状態になります。 ©CAPCOM 39

40.

VisibilityBuffer 2回頂点処理が不要 • MeshShaderやVertexShaderからPrimitiveIDやInstanceIDを出力 • オーバードローが少ないため処理時間が劇的に低下 • 同一シェーダなら1DrawCallにマージして実行 • MaterialはBindlessで定義されている • CPU処理時間の削減 つぎに、VisibilityBufferの導入です。 すでに多くのゲームエンジンで導入されていますが、2回頂点の処理が不要になります。 40 通常のGbufferで問題となるオーバードローによるピクセル負荷の増加を防ぐのに有利です。 さらに、マテリアルは、すでにお話をした通りBindlessになっています。 頂点データもVisibilityBufferから復元ができます。 このことから、同一のシェーダであれば、異なる頂点、 異なるマテリアルであっても1ドローコールでまとめて実行することが可能になります。 MeshShaderとVisibilityBufferを利用することで、GPUとCPUの負担がかなり減ることがすでに分かっています。 ©CAPCOM 40

41.

まとめ • Ray Tracingに対応し第九世代らしい機能を追加 • Bindlessを利用した性能とメモリ改善 • 昔から気になる見た目の改善 • 今後のメモリの削減と描画コール数とGPU負担の削減方法 まとめです。 Ray Tracingに対応し第九世代らしい機能を追加しました。 Bindlessを利用した性能とメモリ改善しました。 41 昔から気になる見た目の改善にも手が入りました。 MeshShaderとVisibilityBufferで将来への備えが出来ました。 RE ENGINEのレンダリング機能はまだ進化しています! ©CAPCOM 41

42.

今後の課題 ・より安全なBindlessの運用 ・VisibilityBuffer、DeferredTexturingへ完全移行 • 多くのパフォーマンス改善に寄与 ・各IHV向けの最適化 ご清聴ありがとうございました 今後の課題は、より安全なBindlessの運用があります。 またレンダリングのVisibilityBuffer、DeferredTexturingへの移行もあります。 42 複雑なシェーダや頂点数が大量にあるゲームでは、多くのパフォーマンス改善が得られます。 各IHV向けの最適化の拡充もあります。 よりハードウェアを知り、ぞれぞれに適した最適化を適応していきたいと思います。 以上で、本講演は終了です。 本講演内容が皆様のお役に立てれば幸いです。 ©CAPCOM 42

43.

付録:VisibilityBuffer + VariableRateShading VariableRateShadingで性能改善をしたい • Tier1相当を実行するとPolygonEdgeまで低解像度に フル解像度 HardwareVRS Tier1 2x2 これはテスト中のものなので最終的に採用されないかもしれないです。 もうすこしだけVisibilityBufferを高速化したくなります。 43 何も考えずにVariable Rate Shading のTier1を 実行するとPolygonEdgeまで低解像度になります。 これはポリゴン向けに作られているHardwareの Variable Rate Shadingの使用によるものです。 ©CAPCOM 43

44.

付録:VisibilityBuffer SoftwareVRS VisibilityBufferをMSAA or Interleaveで保持 • テストではMSAAはVisibilityBufferの処理が高速になった • GBufferのVisibilityBufferの処理区間は削減だがResolveコスト高い フル解像度 HardwareVRS Tier1 2x2 SoftwareVRS Tier1 2x2 これはテスト中のものなので最終的に採用されないかもしれないです。 MSAAにMaterialIDを展開し、GbufferをDepthEqualと SampleRateで実行することで、SoftwareVRSの実現も行っています。 44 テストではInterleaveよりはMSAAのほうがいい結果が得られましたが、 VRSを解除するためのマニュアルResolveはGbufferの枚数分実行するため、 見た目の劣化と解凍コストに対して現時点では有意義なVRSではないです。 もうすこし実験が必要かもしれません。 ©CAPCOM 44