Cocos Cyberpunk は、エンジンの強力な 3D ゲーム制作能力を実証し、コミュニティの学習意欲を高めるために、Cocos エンジンの公式チームによって立ち上げられた完全なオープン ソース TPS 3D ゲームです。Web、IOS、Android のマルチターミナル リリースをサポートしています。
この連載では、皆さんの学習効率を向上させるために、ソースコードをさまざまな側面から解釈していきます。3D ゲーム開発の道をさらに前進するのに役立つことを願っています。
プロジェクトソースコード無料ダウンロードページ:
https://store.cocos.com/app/detail/4543
メインコンテンツ
ディファード レンダリング テクノロジは 2004 年の GDC で正式に提案されてから 20 年近くが経過しましたが、私の友人のほとんど、特に 3D プログラミングに慣れていない人はまだ詳細を知りません。
この記事は長くありませんが、いくつかのことを簡単に説明します。
- 遅延レンダリング技術が参加するレンダリングリンク
- 遅延レンダリング技術はどのような問題を解決しますか
- 遅延レンダリング技術の原理分析
- Cocos Cyberpunk における遅延レンダリング パイプラインの実装の詳細
- ディファード レンダリング テクノロジのメモリ、互換性、GPU ハードウェア パラメータ
- 透明なレンダリング ソリューション
新しい友達へ: Cocos Cyberpunk は、エンジンの強力な 3D ゲーム制作能力を実証し、コミュニティの学習意欲を高めるために、Cocos エンジンの公式チームによって開始された完全なオープン ソース TPS 3D ゲームです。Web、IOS、Android のマルチターミナルをサポートしています。リリースします。
クリックして原文を読み、プロジェクトのソース コードの無料ダウンロード ページに入ります。
インターネット上には、フォワード レンダリングとディファード レンダリングに関する比較チャートやフローチャートが多数あります。
しかし、いくつかの非常に深刻な問題があり、それによって、この作品は見ないのと同じことになります。
- あまりにも学術的で高級な言葉だが、わかりにくい
- 遅延レンダリング技術の動作境界を明確にしていなかったため、遅延レンダリングがすべての問題を解決できると人々に誤解させた
- 実際の事例と組み合わせていないため、読んだ後忘れたり、学んだ後も捨ててしまいます。
今日、 Qilinzi は、Cocos Cyberpunkオープンソース プロジェクトのソース コードと組み合わせて、これをシンプルかつ率直な方法で説明しようとしました。
Cocos Cyberpunk制作チームに改めて感謝します。このオープンソース プロジェクトがなければ、このトピックを共有するエンジニアリング レベルのケースは存在しなかったでしょう。
参加
テクノロジーの原理を理解したい場合は、そのテクノロジーが関与しているリンクと、そのテクノロジーが出現する理由を理解する必要があります。
悪用を避けるために、その動作境界を知り、適切な適用機会を決定します。
遅延レンダリングに関する記事はたくさんありますが、レンダリング プロセス全体における遅延レンダリングに関係する具体的なリンクについて言及している人はほとんどいません。
遅延レンダリングは何でもできると思っていますが、実際にはほんの一部にしか関与しません。
次に、エンジン内の一般的な 3D レンダリング プロセスを見てみましょう:シャドウ マップ レンダリング-->メイン シーン レンダリング-->スクリーン アフター エフェクト レンダリング--> 2D&UI レンダリング。
1. シャドウマップのレンダリング
この段階では、シーン内のすべてのオブジェクトが統一されたマテリアルでレンダリングされ、次のレンダリング段階で使用するシャドウ マップが生成されます。
2. シーンのレンダリング
このステージは通常のレンダリング ステージであり、シーン内のすべてのオブジェクトがレンダリングされ、シャドウ マップを使用してシャドウが生成され、ライティングの計算が実行され、さまざまなテクスチャが生成されます。シーン内のオブジェクトは、不透明なオブジェクトと半透明なオブジェクトの
2 つのカテゴリに分類でき、それぞれ異なる方法で処理されます。
3. 画面スペースに基づいたエフェクトレンダリング
この段階では、適切な画像アルゴリズムを使用して、レンダリングされたシーンのコンテンツに特別な処理を実行し、画像効果を向上させます。
4. 2D/UIレンダリング
カメラによって変化しない一部の 2D 要素、UI 要素はこの段階でレンダリングされます。
上記は主要な標準レンダリング プロセスにすぎません。一部のプロジェクトはニーズに応じてカスタマイズされ、特殊な目的のレンダリング プロセスが追加されます。
このような長いレンダリング プロセスでは、遅延レンダリングは主にシーン レンダリング プロセスの不透明なオブジェクトを目的としています。
残りの作業はフォワード レンダリング パイプラインとディファード レンダリング パイプラインでほぼ同じであり、大きな違いはありません。
想像していたものと違いますか?
それでは次に、なぜそれが生まれたのかを見てみましょう。
フォワードレンダリングの問題
遅延レンダリングはこの部分にのみ関与するため、以下の説明はシーンのレンダリングプロセスについてのみ説明します。
上記のシナリオでは、次のとおりです。
- 10 モデル (平面 1 個、立方体 9 個)
- 7光源(平行光1本、球面光7本)
フォワード レンダリングの使用方法、プロセスは次のとおりです。
- モデルを取得し、レンダリングのためにグラフィックス カードに送信します。
- 頂点シェーダーで頂点変換やUVなどを処理します。
- フラグメント シェーダーでは、照明の計算に 7 つの光源が順番に使用されます。
- 次のモデルを処理する
上記のプロセスは 10 回実行する必要があり (モデルが 10 個あるため)、各モデルは 7 つの光源で照明計算を実行する必要があることが簡単にわかります。
この場合、照明操作全体を10 * 7 = 70回実行する必要があります。
主に次の 2 つの問題が発生します。
1. シェーダ命令の制限事項
特定の数のライトのみがサポートされます。ライトの数が特定の値を超えると、ライティングの計算を完了するために複数のレンダリングが必要になります。
2. GPU の計算能力の無駄
ライティングの計算は、特に PBR マテリアルの場合、レンダリングで最もコストがかかる部分です。
上記のレンダリング プロセスでは、モデルの一部のオクルージョンされた部分が最終的に見えなくなりますが、それでもライティングの計算に関与するため、無駄が生じます。
シーンが非常に大きく、多数のモデルと光源がある場合、これら 2 つの問題がどれほど深刻になるかを想像してみてください。
遅延レンダリングの登場により、これら 2 つの問題が解決されました。
遅延レンダリングの原理と、遅延レンダリングがこれら 2 つの問題の解決に優れている理由を見てみましょう。
遅延レンダリングの分析
たったの2ステップ
1. 準備段階 (ジオメトリのレンダリング)
この段階で、モデルのライティングを計算するために必要な基本情報 (ワールド空間の位置情報、法線情報、色情報、深度情報など) がレンダリングされ、さまざまな RenderTexture に保存されます。
2. 照明ステージ
ライティング ステージは、名前が示すように、前のステージでレンダリングされた RenderTexture をシーン内のライティング データと組み合わせて使用し、ピクセルの最終的なカラー値を計算します。
2段階目でピクセルの色計算が一律に行われていることがディファードレンダリングの遅延の原因となっていることが分かります。
ピクセルのカラー計算が第 2 段階で統合されるため、オクルージョンされたモデル部分のピクセルが深度テストによって削除され、不要な計算が大幅に回避され、パフォーマンスが向上します。
Gバッファ
GBufferの定義
遅延レンダリング技術で最も重要な概念はGBufferです。
GBufferとはGeometry Bufferの略で、ジオメトリ情報を格納するバッファを意味します。より具体的には、上で述べたように、ジオメトリのレンダリング段階でオブジェクトの位置、法線、色、その他の情報を記述するために使用される RenderTexture の組み合わせです。
したがって、上記のジオメトリ レンダリング ステージは通常、GBuffer ステージとも呼ばれます。
遅延レンダリングは単なるアイデアであり、さまざまなバージョンがあることに注意してください。GBuffer の RenderTexture に格納される内容は均一ではありません。
エンジン エンジニアが遅延レンダリング パイプラインを実装するときは、要件に応じて適切な組み合わせを選択します。
GBufferのコンテンツ構成
照明の計算を完了するには、いくつかの基本情報が必要です。例えば:
- ワールド空間での位置情報
- ワールド空間法線情報
- 物体表面の色情報
しかしそれ以上に、他に何が必要なのでしょうか?
GBuffer は主に照明計算に必要な情報を提供するため、GBuffer の内容を理解するには照明計算の関連内容を理解する必要があります。
照明計算は 3D グラフィックス レンダリングの中核的な問題であり、グラフィックス レンダリングに関する研究のほとんどは照明計算を中心に展開されており、1 つや 2 つの段落では説明できません。
しかし、GBuffer をもっとよく理解してもらうためだけであれば、概念を理解するだけで十分です。
Blinn-PhongであろうとPBRであろうと、それらはすべて最も基本的なライティング公式に従います。
オブジェクトの最終的な色 = 環境光 + 拡散反射 + 鏡面反射 + 自己照明
この 4 つの部分の計算を扱う際に、両者が使用するデータと計算方法が異なるだけです。
周囲光: ブリンフォンでは定数ですが、PBR ではモデルのマテリアル パラメータの影響を受けます。
拡散反射: モデルの材質と照明パラメータによって決定されます。
鏡面反射: モデルの材質パラメータ、照明パラメータ、観察位置によって決定されます。
自己照明: モデル マテリアルの発光関連パラメータによって決定されます。
Blinn-Phong では、使用される式は非常に単純で、ほとんどが定数と単純なベクトル演算式で構成されています。
しかし、PBRでは照明の計算式が非常に複雑で、例えばクック・トーランスのBRDFモデルを使って物体の拡散反射や鏡面反射を計算することになります。周囲光は周囲拡散光とリング鏡面反射光に細分され、IBL を使用して処理されます。
最新のエンジンでは、PBR マテリアルが組み込みの優先マテリアルになっているため、最新のエンジンの GBuffer には少なくとも次の情報が含まれます。
1. アンビエントオクルージョン (AO)
これは、照明計算段階でモデルの拡散反射に参加するために使用されます。
2、粗さ/金属性
PBR のモデルは 1 つだけではありません。わかりやすくするために、この記事では、Cocos Creator で使用される粗さ/金属モデルを例として取り上げます。
3、発光
オブジェクトの自己照明パラメータは、照明計算に単純に追加されます。そのより大きな役割は、ネオン ライトなどのオブジェクトのグロー効果を形成するために使用できることです。
複数のレンダー ターゲット (MRT)
上で述べたように、GBuffer は位置、法線、色、マテリアル パラメーターなどの照明計算のための情報を保存する一連の RenderTexture で構成されます。
これほど多くの RenderTexture をどうやって取得するのでしょうか?
最も簡単な方法の 1 つは、シーンを複数回レンダリングし、レンダリングごとに対応する RenderTexture に異なるコンテンツを出力することです。
しかし、この方法は信頼性が低いように思えます。シーンは数回レンダリングされますが、これは DrawCall の数回に相当し、CPU と GPU の両方にかかる負荷は 2 倍になります。
次に、非常に重要なグラフィックス カードの機能について触れなければなりません。それは、複数のレンダリング ターゲットです。
複数のレンダリング ターゲットの英語名は、Multiple Render Targets (略して MRT) です。これは、遅延パイプライン技術を適用するための基礎です。
グラフィックス パイプラインでは、スクリーン フレーム バッファーとレンダリング テクスチャをレンダリング ターゲットとして参照します。
通常のレンダリング プロセスでは、シーン コンテンツを画面にレンダリングするかテクスチャにレンダリングするかに関係なく、1 つのレンダー ターゲットにレンダリングするだけで済みます。
ただし、さまざまなレンダリング要件の出現に伴い、グラフィック カードは、コンテンツのレンダリング時に同時に複数のレンダリング ターゲットへのレンダリングを徐々にサポートするようになりました。
複数のレンダリング ターゲットのサポートにより、1 つの描画内のすべての GBuffer の RenderTexture を埋めることができます。
Gバッファ圧縮
上記の説明から、それがわかります。PBR ベースの遅延レンダリング パイプラインでは、GBuffer に少なくとも次の情報が含まれている必要があります。
上記のAO、ラフネス、メタリック、エミッシブに加えて。
- 位置: vec3、高精度、予測不可能なコンポーネント範囲
- 通常: vec3、高精度、成分範囲 0.0 ~ 1.0
- カラー: vec3、低精度、成分範囲 0.0 ~ 1.0
- AO : 浮動小数点、値の範囲 0.0 ~ 1.0
- 粗さ: float、値の範囲 0.0 ~ 1.0
- メタリック: float、値の範囲 0.0 ~ 1.0
- Emissive : vec3、コンポーネントの範囲は予測できません
- 深さ:d24s8、成分範囲0.0~1.0
グラフィックス API とグラフィックス カードの機能によっては、深度マップを手動処理なしで直接取得できます。
3 つの PBR パラメータ AO|roughness|metallic を RenderTexture に入力したとしても、要求を満たすには 5 つの RenderTexture (位置、法線、色、PBR、エミッシブ) が必要です。
ただし、現在のグラフィックス API 標準では、OpenGL ES 3.0 では GL_MAX_COLOR_ATTACHMENTS が 4 以上であることのみが規定されています。
つまり、モバイル デバイスでは、マルチ レンダリング ターゲット (MRT) の数が 4 つを超えると、互換性が非常に低くなります。
4 つの RenderTexture のみを使用するようにデータを圧縮する方法を見つける必要があります。
法線は正規化できるため、正規化された法線の 2 つの成分がわかっていれば、3 番目の成分を計算できます。この方法では、法線に必要なパスは 2 つだけです。各データの値の範囲と組み合わせると、終了後に次の GBuffer を取得できます。
- GBuffer_slot0:RGBA8
- xyz -> アルベド.rgb
- w -> アイドル状態
- GBuffer_slot1:RGBA16F
- xy -> 通常.xy
- z -> 粗さ
- w -> メタリック
- GBuffer_slot2:RGBA16F
- xyz -> エミッシブ
- w -> アオ
- GBuffer_slot3:RGBA16F
- xyz -> 位置.xyz
- w -> アイドル状態
もちろん、深度マップ用の隠された GBuffer_slot4: D24S8 もあります。ただし、これは深度バッファの機能であり、MRT の数を占有するわけではありません。
ココス サイバーパンク
Cocos Creator v3.1バージョンでは、遅延レンダリング パイプライン(遅延レンダリング パイプライン) を選択できます。
Cocos Cyberpunkプロジェクトでは、 Cocos Creator 3.7の新しいカスタム パイプライン機能を利用して、制作チームはプロジェクトの要件に従って遅延レンダリング パイプラインのカスタマイズされたバージョンも実装しました。
次に、Qilinzi は、Cocos Cyberpunk のソース コード、パイプライン フロー、GBuffer の構築と充填、ライティングの計算を組み合わせて、実際の遅延レンダリング パイプラインの実装の詳細を示します。
Cocos Cyberpunk プロジェクトの完全なソース コードは、 https://store.cocos.com/app/detail/4543から無料で入手できます。
前回の記事で説明した方法に従って、カスタム レンダー パイプライン グラフ ウィンドウを開くと、メイン パイプラインにDeferredBufferPassとDeferredLightingPassが表示されます。
Gバッファの構築
deferred-gbuffer-pass.ts ファイルを開き、DeferredGBufferPass クラスを見つけます。
const colFormat = Format.RGBA16F;
let posFormat = colFormat;
if (!sys.isMobile) {
posFormat = Format.RGBA32F
}
passUtils.addRasterPass(width, height, 'default', `${
slot0}_Pass`)
.setViewport(area.x, area.y, width, height)
.addRasterView(slot0, colFormat, true)
.addRasterView(slot1, colFormat, true)
.addRasterView(slot2, colFormat, true)
.addRasterView(slot3, posFormat, true)
.addRasterView(slot4, Format.DEPTH_STENCIL, true)
addRasterPassメソッドの機能は描画処理を追加することです。
addRasterViewメソッドの機能は、レンダー ターゲットを追加することです。
ここでは合計 5 つのレンダー ターゲットが作成され、slot3 は位置の保存に使用され、slot4 は深度マップに使用されます。ここでは、slot0、slot1、slot2 の効果は確認できません。
もう一度その形式を見てみましょう。
slot4 は深度マップであるため、専用フォーマット Format.DEPTH_STENCIL を使用していることがわかります。
位置情報の保存にはslot3を使用しますが、非モバイル側では精度を高めるため、高精度フォーマットのFormat.RGBA32Fも使用されます。
残りのレンダー ターゲットは Format.RGBA16F を使用します。
Gバッファパディング
GBuffer 充填フェーズの主な作業は、モデル描画を呼び出し、
pipeline/resources/surface/custom-surface.effect を開くことです。
次のコードが見つかります。
#elif CC_PIPELINE_TYPE == CC_PIPELINE_TYPE_DEFERRED
layout(location = 0) out vec4 fragColor0;
layout(location = 1) out vec4 fragColor1;
layout(location = 2) out vec4 fragColor2;
layout(location = 3) out vec4 fragColor3;
...
#endif
このコードではfragColor0~3の4つの描画ターゲットを宣言しており、layout(location=number)で描画ターゲットのインデックスを指定しています。
下にスクロールすると、このコードが見つかります。これが Cocos Creator PBR Shader の主な機能であり、いくつかの変更はありますが、大まかな考え方は同じです。
void main () {
StandardSurface s; surf(s);
#if CC_FORCE_FORWARD_SHADING
fragColor0 = CCStandardShadingBase(s, CC_SHADOW_POSITION);
return;
#endif
if (cc_fogBase.x == 0.) {
// forward
fragColor0 = CCStandardShadingBase(s, CC_SHADOW_POSITION);
}
else if (cc_fogBase.x == 1.) {
// deferred
vec3 diffuse = s.albedo.rgb * (1.0 - s.metallic);
vec3 lightmapColor = diffuse * s.lightmap.rgb;
float occlusion = s.occlusion * s.lightmap_test;
fragColor0 = s.albedo;
fragColor1 = vec4(float32x3_to_oct(s.normal), s.roughness, s.metallic);
fragColor2 = vec4(s.emissive + lightmapColor, occlusion);
fragColor3 = vec4(s.position, 1.);
}
}
Cocos Creator での PBR レンダリング プロセスは、マテリアル パラメータの取得とライティングの計算という2 つの主なステップに分かれています。
この分割の利点は、シェーダーの記述を十分に統合できるため、開発者が順方向レンダリングと遅延レンダリングの違いに対処する必要がないことです。
main 関数の最初の文は、surf 関数を呼び出します。その関数は、アルベド、ラフネス、メタリック、エミッシブなどのオブジェクトの PBR マテリアルを取得することです。
StandardSurface s; surf(s);
ライティングの計算段階では、フォワード レンダリングとディファード レンダリングの間には若干の違いがあります。
フォワード レンダリングでは、シェーディング関連関数を直接呼び出して計算を完了します。
遅延レンダリングでは、最初にオブジェクト マテリアル パラメータが GBuffer にレンダリングされ、後で均一に計算されます。
次のコードは、GBuffer にコンテンツを埋めるために使用されます。
fragColor0 = s.albedo;
fragColor1 = vec4(float32x3_to_oct(s.normal), s.roughness, s.metallic);
fragColor2 = vec4(s.emissive + lightmapColor, occlusion);
fragColor3 = vec4(s.position, 1.);
ここで一目でわかります。
- fragColor0:RGBA16F
- xyzw -> アルベド.rgba
- fragColor1:RGBA16F
- xy -> 通常.xy
- z -> 粗さ
- w -> メタリック
- fragColor2:RGBA16F
- xyz -> エミッシブ
- w -> アオ
- fragColor3:RGBA16F
- xyz -> 位置.xyz
- w -> 1.0
照明計算
次に、照明計算に関するコードを見てみましょう。
deferred-lighting-pass.ts ファイルを開き、DeferredLightingPass クラスを見つけます。
次のコードが見つかります。
passUtils.addRasterPass(width, height, 'deferred-lighting', `LightingShader${
cameraID}`)
.setViewport(area.x, area.y, width, height)
.setPassInput(this.lastPass.slotName(camera, 0), 'gbuffer_albedoMap')
.setPassInput(this.lastPass.slotName(camera, 1), 'gbuffer_normalMap')
.setPassInput(this.lastPass.slotName(camera, 2), 'gbuffer_emissiveMap')
.setPassInput(this.lastPass.slotName(camera, 3), 'gbuffer_posMap');
setPassInput は、対応するレンダー ターゲットを gbuffer_****Map にバインドします。
遅延レンダリング ライティングの計算に使用される deferred-lighting.effect を開くと、次のコードが表示されます。
void main(){
StandardSurface s;
vec4 albedoMap = texture(gbuffer_albedoMap,v_uv);
vec4 normalMap = texture(gbuffer_normalMap,v_uv);
vec4 emissiveMap = texture(gbuffer_emissiveMap,v_uv);
vec3 position = texture(gbuffer_posMap, v_uv).xyz;
s.albedo = albedoMap;
s.position = position;
s.roughness = normalMap.z;
s.normal = oct_to_float32x3(normalMap.xy);
s.specularIntensity = 0.5;
s.metallic = normalMap.w;
s.emissive = emissiveMap.xyz;
...
}
このコードの役割は明らかで、GBuffer からマテリアル パラメーターを取得し、後続の照明計算のために StandardSurface 情報を再構築します。
以降のライティング計算プロセスはフォワード レンダリングの場合と同じであるため、ここでは繰り返しません。
半透明のレンダリング
deferred-lighting-pass.ts に戻ると、ファイルの最後に次のコードがあります。
// render transparent
if (HrefSetting.transparent) {
...
}
これは、ラスタライズベースのグラフィックス パイプラインでは、正しいブレンド結果を保証するために、半透明のオブジェクトを遠くから近くの順に描画する必要があるためです。
遅延レンダリング パイプラインでは、ジオメトリ描画段階では照明計算が実行されず、カラー バッファーに描画された効果が最終的な効果ではないため、この段階で透明レンダリングを実行すると、不正確な結果が得られます。また、後続の照明計算にも干渉します。
したがって、フォワード レンダリングを使用してシーン内に半透明のオブジェクトを描画する必要があります。
上記のコードはその仕事を行います。
メモリ、互換性、GPU パラメータ
3D レンダリングを初めて使用する友人の多くは、レンダリング テクノロジの長所と短所を判断する方法がありません。
一般に、レンダリング テクノロジの長所と短所は、メモリ オーバーヘッド、パフォーマンス オーバーヘッド、互換性の 3 つの側面から判断できます。
メモリ オーバーヘッドは比較的単純で、割り当てる必要があるリソースをリストし、占有されているメモリをカウントするだけです。
互換性も比較的簡単で、サポートする必要がある機能を列挙し、対応するプラットフォームのサポート率をカウントするだけで評価できます。
パフォーマンスのオーバーヘッドはさらに厄介で、基本的な知識とプロジェクトの経験の組み合わせが必要です。
CPU 上で実行されるプログラムの場合、オペレーティング システムの原理、コンパイルの原理、メモリと CPU のアーキテクチャ、および動作原理を習得すると、考えられるパフォーマンスのボトルネックをすぐに評価できます。
3D プログラミングも同様で、コンピュテーショナル グラフィックスの原理、グラフィックス パイプラインの動作原理、GPU のアーキテクチャと動作原理をマスターしていれば、比較的正確な判断が可能です。
次に、メモリ消費量、互換性、GPU ハードウェア パラメータ要件の観点から、遅延レンダリング テクノロジの長所と短所について説明します。
単一のオブジェクトにはメリットもデメリットもありません。
したがって、以下の利点と欠点の説明では、デフォルトは参照標準としてフォワード レンダリングです。
メモリ消費量
テクスチャメモリの計算方法
テクスチャのメモリ計算方法は非常に単純で、メモリ = 幅 x 高さ x 1 ピクセルのメモリ サイズです。
1バイト = 8ビット
RGBA8:4 * 8btis = 4 バイト
RGBA16F:4 * 16ビット = 8バイト
RGBA32F:4 * 32ビット = 16バイト
D24S8:24ビット+8ビット=4バイト
GBuffer 全体のオーバーヘッド
Cocos Cyberpunk は RGBA16F を 4 つと D24S8 を 1 つ使用します。
解像度が 1280 x 720 の場合、GBuffer 全体が占有する合計メモリは次のように計算されます。
1280 x 720 x ( 4 * 8 + 4 ) バイトは、約 31.64MB に相当します。
他の 16 から 9 の解像度での GBuffer のメモリ オーバーヘッドを比較してみましょう。
- (720p)1280×720 -> 31.64MB
- (960p)1706 x 960 -> 56.23MB
- (1k)1920×1080 -> 71.19MB
- (2k)2560 x 1440 -> 126.56MB
- (4k)3840 x 2160 -> 284.76MB
解像度が 1k 以上になると、メモリ使用量が過小評価できないことがわかります。
特にモバイル側では、レンダリング解像度を可能な限り制御する必要があります。
GBuffer がメモリよりも GPU に負荷をかけることを心配する必要があります。
今日この機会を利用して、Qilinzi は GPU のパフォーマンスに関連するいくつかの重要なパラメーターについて簡単に説明します。
GPUパラメータとパフォーマンスのボトルネック
GPUハードウェアパラメータ
- コア周波数 (GPU クロック) : CPU と同様に、GPU の計算パフォーマンスを決定します。
- 論理演算ユニット (ALU) : VS および FS でのベクトル行列演算などの一般的な計算を処理するために使用されます。
- 光学的削除処理ユニット (ROP - ラスター オペレーション ユニット) : このハードウェア ユニットは主にピクセル値をレンダリング ターゲットに書き込む役割を果たします (深度テスト、ステンシル テスト、透明混合)。
- テクスチャ マッピング ユニット (TMU - テクスチャ マッピング ユニット) : このハードウェア ユニットは主にテクスチャ命令を実行します。
- メモリクロック: 水道管内の水の流れの速度と同様に、ビデオメモリによって転送されるデータの応答速度を決定します。
- ビデオメモリのバス幅(Bus width) : ビデオメモリの厚さに関係なく、1回の転送データのサイズを決定します。
GPU評価パラメータ
GPU ハードウェア パラメーターを直接見てグラフィック カードの機能を理解するのはそれほど簡単ではないため、ハードウェア パラメーターを計算した後、GPU の品質を評価するための次の重要なパラメーターを取得できます。
1. ピクセルフィルレート
ピクセル フィル レートは、GPU が 1 秒あたりにレンダリングできるピクセル数を GPixel/s (ギガピクセル/秒) の単位で表します。
計算式: ピクセル フィル レート = コア周波数 (GPU クロック) x ラスター プロセッシング ユニット (ROP) の数
2. テクスチャのフィルレート
テクスチャ フィル レートは、グラフィックス カードが 1 秒あたりにテクスチャ マップをサンプリングできる回数を指し、単位は GTexel/s (10 億テクセル/秒) です。
計算式:テクスチャフィルレート=コア周波数(GPUクロック)×テクスチャユニット数(TMU)
3. メモリ幅
ビデオ メモリ帯域幅は、ビデオ メモリが 1 秒あたりに転送できるデータのバイト数を GB/秒 (ギガバイト/秒) で表します。
帯域幅 = メモリクロック x バス幅 / 8
4. 浮動小数点演算 (FLOPS/TFLOPS)
GPU の計算能力を測定するための中心的な指標は FLOPS、つまり 1 秒あたりの浮動小数点演算数、つまり 1 秒あたりに実行される浮動小数点演算の数です。
最新の GPU の強力な浮動小数点演算能力により、一般に TFLOPS (1 秒あたり 1 兆回の浮動小数点演算) で表されます。
この値は ALU とコア周波数によって決定され、メーカーの測定データの影響を受けます。
上記のパラメーターを理解すると、GPU パラメーターを比較するときに、GPU がどこが強いのか、どこが弱いのかをすぐに確認できるようになります。
パフォーマンスの問題が発生した場合、モデルのボトルネックを迅速に特定し、適切な解決策を策定できます。
遅延パイプラインの GPU への影響
ここで、フォワード レンダリングと比較して、遅延レンダリング パイプラインが GPU にどのような負担を与えているかを見てみましょう。
1. ピクセルフィルレート
フォワード レンダリングでは、1 つのレンダー ターゲットと 1 つの深度ステンシル バッファーのみが必要です。遅延レンダリングでは、4 つのレンダリング ターゲット + 深度ステンシル バッファーを含む GBuffer を例にとると、合計 5 つが必要になります。
ピクセル フィル レートのオーバーヘッドに関して言えば、遅延レンダリングのオーバーヘッドは順方向レンダリングの 2.5 倍です。
2. テクスチャの充填率
モデルが PBR マテリアルを使用している場合、IBL がオンになっていると、ピクセルごとに IBL 計算が実行され、環境マッピングに関連するテクスチャ作業が実行されます。ただし、遅延レンダリング プロセスでは、これらの計算は遮蔽されたピクセルに対して実行されません。
全体として、テクスチャ フィル レートのオーバーヘッドはいくらか節約されますが、それほど大きなものではありません。
3. メモリ帯域幅
フォワードレンダリングでは、RGBA8 x1 + D24S8 x1 のみが必要です。
ただしディファードレンダリングではRGBAF16×4+D24S8×1が必要です。
ビデオ メモリ帯域幅の要件が 4.5 倍に増加しました -> (4x8+4)/(4+4)
4. 浮動小数点演算
PBR の主なコストは照明段階にあるため、特に BRDF と IBL は多数の数式演算を実行します。
ただし、遅延レンダリング プロセスでは、ブロックされたピクセルはこれらの計算を実行しないため、ここでのオーバーヘッドを大幅に節約できます。
まとめ
遅延レンダリングにより、ピクセル塗りつぶしの量が 2.5 倍、ビデオ メモリ データ アクセスの量が 4.5 倍に増加し、テクスチャ塗りつぶしの作業の一部と多数のロジック演算が節約できることがわかります。
したがって:
- ラスター機能とメモリ帯域幅が不十分な GPU ではパフォーマンスの問題が発生します
- 消費電力の増加は電力消費と発熱を引き起こすため、モバイル端末プロジェクトでは特に注意が必要です
一般的な最適化手法
遅延レンダリングの最適化方法は、主に次の 2 つの側面から始まります。
1.GBufferでレンダリングターゲットの解像度を制限する
これが最も操作しやすいですが、絵柄を確保したい場合はレンダリング対象の解像度を可能な限り下げてください。
2. GBuffer のレンダー ターゲットの数を減らす
レンダリング ターゲットの数を減らしたい場合は、圧縮アルゴリズムを使用して、データが占めるバイト数を減らし、データをチャネルに保存できます。
これにより精度は失われますが、効果が維持されるという利点があります。
もう 1 つは、不要なパラメータを削除することですが、その副作用として、一部の効果が得られなくなります。
3. RGBA8 の使用を優先する
RGBA16F と比較して、RGBA8 のメモリ使用量は 1 分の 1 であり、グラフィックス カードの帯域幅の最適化が大幅に向上します。ただし、副作用として精度が失われ、一部のエフェクトはそれほど精細ではなくなります。
Cocos Cyberpunk プロジェクトでは、fragColor0 が RGBA8 を使用できることに注意してください。これは、albedo の元の値が RGBA8 であり、精度が失われることがないためです。
互換性
開発者が特定のプラットフォーム向けにのみ製品をリリースする場合、互換性を扱う際に考慮すべきことはほとんどありません。
たとえば、Cocos Creator を使用して製品を開発し、 Nintendo。
対応するスイッチを入手してテストに合格するだけです。他の問題については心配しないでください。
ただし、Cocos Creator はクロスプラットフォーム エンジンであるため、ユーザーは IOS、Android、Hongmeng、PC、およびその他のシステムを検討することができます。
さらに、同じシステムにおいて、ネイティブ ゲーム、ミニゲーム、Web の違いも考慮する必要があります。
幸いなことに、 Nintendo Switch などの独自プラットフォームを除いて、Metal、OpenGL ES、WebGL、Vulkan、WebGPU など、他のプラットフォーム用のグラフィックス ドライバーが知られています。
したがって、テクノロジーの互換性と使いやすさを評価する前に、主なグラフィックス機能をリストし、これらの機能をサポートする各グラフィックス API のリリース時期を確認する必要があります。
前述したように、適切に動作する遅延レンダリングには、サポートする 3 つの機能が必要です。
- 奥行きのあるテクスチャを取得する
- 複数のレンダー ターゲット (MRT)
- 浮動小数点テクスチャへのレンダリング
上記 3 つの機能は正式にサポートされており、対応する API は次のとおりです。
デスクトップ
- Direct3D 9.0c、2004-07-26、100%
- OpenGL 2.0、2004-09-07、100%
モバイルネイティブ
- OpenGL ES 3.0、2012-08-05、99.5%
- メタル 1.0、2014-06-03、99.5% (iPhone 6/6 Plus)
- モバイル用 Vulkan、2016 年 8 月 22 日、Android 7.0
ウェブ
- WebGL 2.0、2017 年 4 月 11 日、OpenGL ES 3.0 ベース
- WebGPU 1.0、2023 年に正式リリース予定
このことから、PC デスクトップとネイティブ エンドでのレンダリングの遅延による互換性の問題を心配する必要がないことがわかります。
Web 側では、WebGL 2.0 ブラウザがこれをサポートする必要があります。
2022 年 2 月 14 日、クロノス グループは、すべての主要ブラウザが WebGL 2.0 のサポートを実装したと発表しました。Safari と Edge の 2 つのネイル アカウントが含まれます。
WebGPU は正式にはリリースされていませんが、多くのブラウザーが実験的なサポートを追加しています。
そして、Cocos Creator では、状況に応じて OpenGL ES/Metal/Vulkan/WebGL/WebGPU のいずれかを選択してターゲット プラットフォームに公開することができます。
Android と Windows をリリースするときは、Vulkan/OpenGL ES 3.0/OpenGL ES 2.0 の使用を選択できます。
Web デスクトップを公開するときに、WebGPU を有効にするかどうかを選択できます。
iOS/Mac をリリースする場合、Apple の制限により、Metal はグラフィック レンダリング バックエンドとしてのみ使用できます。
一般に、現在のデータから判断すると、遅延レンダリングでサポートされているプラットフォームは数多くあります。
さらに、Cocos Creator のマテリアル システムは上位レイヤーに分離されており、フォワード レンダリングとディファード レンダリングのパイプラインで同じマテリアルのセットを正常にレンダリングできます。
したがって、互換性の問題はそれほど大きくなく、実行できない環境が発生した場合は、フォワード レンダリングにフォールバックして、ユーザーがスムーズにゲームに参加できるようにすることができます。
遅延レンダリングの概要
遅延レンダリング手法には多くの利点があります。
- 照明計算の複雑さをM*NからM+Nに変更し、照明計算のオーバーヘッドを削減できます。
- 照明計算段階では、可視ピクセルのみが計算されるため、Overdrawの消費が大幅に削減されます。
- 深度、位置、法線、自己照明強度などの情報はGBufferから直接取得できます。ブルーム、SSR、SSAOなど、画面空間に基づいた高度なレンダリング効果を実現するのに非常に便利です。
同時に、次のような欠点もあります。
- 追加のメモリオーバーヘッド
- GPU ピクセル フィル レートとメモリ帯域幅に対する要件が数倍高い
- 消費電力の増加による発熱と電力消費はフォワードレンダリングよりも高くなります
- 透明レンダリングはサポートされていないため、透明レンダリングは処理のためにフォワード レンダリング パイプラインにフォールバックする必要があります。
- MRT の理由により、グラフィックス カードに付属の MSAA アンチエイリアス方式は使用できず、FXAA および TAA で処理する必要があります。
すべての状況を満足できる単一のテクニックはないことがわかります。Qilinzi が以前に述べた、ハイエンド、ハイエンド、ローエンド マシンのパフォーマンス適応戦略と組み合わせると、使用できるソリューションが 2 つあります。
- ハイエンド マシンでは遅延レンダリングを使用し、ローエンド マシンでは高度なエフェクトをオフにして、フォワード レンダリングに戻します。
- さまざまな画質とパフォーマンスの要件に応じて、さまざまな精度で GBuffer を定式化します。たとえば、圧縮ストレージ メカニズムを使用し、Normal、Color、Position を単一の RGBA16F レンダリング テクスチャに配置し、RGBA8 または RGBA16F を使用して照明パラメータを転送します。
最後に書きます
プロジェクト技術の上陸と普及には時間がかかります。
遅延レンダリングがリリースされる前は、ハイエンドのコンピューターのみでしか実行できませんでしたが、現在はどのコンピューターでも実行できるようになりました。一部のミドルエンドからハイエンドの携帯電話でもスムーズに動作します。
ハードウェアの継続的な開発により、ディファード レンダリング テクノロジはモバイル側でも活躍できると私は信じています。
人生はいつも驚きに満ちていますが、この記事は元々それほど多くのことを書くつもりではありませんでした。しかし、書いているうちに、誰もがよりしっかりと学ぶためには、背景知識を追加する必要があると感じました。
GPU パラメータ、グラフィックス API の普及率、互換性の判定、メモリの見積もりはすべて予想外です。
でも、書いた後はすべてが安心します。そうでないと、いつも他人に借りがあると感じます。
最後に、皆さんに励ましの言葉を贈りたいと思います。
基本的な知識と基礎となるロジックを強化するためにより多くの時間を費やすことによってのみ、変化しながら安定と進歩を求めることができます。