遅延シェーディングは、後の段階で実際のシェーディング操作を「延期」するための手法にすぎません。これは、10パスを必要とする10個のライトをレンダリングするために必要なパス数を減らすのに役立ちます。私のポイントは、使用しているレンダリング手法に関係なく、レンダリングパイプラインで処理する必要のあるオブジェクト(頂点、法線など)の数を減らす特定のレンダリング最適化があります。
レンダリングの最適化のための事実上の標準はありませんが、特定のパフォーマンス特性を達成するために交換可能または一緒に使用できる多くのテクニックがあります。各手法の使用は、レンダリングされるシーンの性質に大きく依存します。
遅延レンダリングは、ライトの数が増えると問題を解決しようとします。これにより、フォワードレンダリングではパスの数が爆発する可能性があります。
これらの手法は、遅延シェーディング部分を直接最適化しませんが、説明によると、遅延シェーディング部分は問題ではありません。ただし、あなたの問題は、シーン全体をレンダリングパイプラインに送信することです。そのため、結果をgバッファに送信できるようにするために、エンジンはシーン内で処理する必要があります(たとえば、1億個の頂点すべて)。これらの1億個の頂点のほとんどは、前処理頂点とフラグメントが通過します。
フォワードレンダラーの場合、N頂点は、頂点ステージによって合計で処理さvertex count*lights count
れ、フラグメントステージによって合計で処理されますfragments count*number Lights
。遅延シェーディングは、これを解決する前にvertex count
、頂点ステージとfragments count
フラグメントカウントに対してのみ効果的に削減します。実際のシェーディング。しかし、Nを処理するには多すぎる場合があります。特に、それらのほとんどを簡単に選別できる場合はなおさらです。
これにより、フォワードレンダリング/複数パスの場合にカリングがより効果的になります。ただし、ほとんどのエンジンはデュアルレンダリングアプローチを使用することに注意してください。遅延シェーディングだけでは透明なオブジェクトを解決できないため、これらの最適化を使用する必要があります。すべてを実行しない商用エンジンは知りません。
錐台カリング
ビュー錐台に完全または部分的に含まれるオブジェクトのみが、レンダリングパイプラインに送信される必要があります。これは錐台カリングの基本概念であり、残念ながらメッシュが視錐台に出入りするかどうかを確認するのは高価な操作になる可能性があるため、代わりにエンジン設計者は(AABB)Axis Alignedバウンディングボックスまたはバウンディング球のような近似バウンディングボリュームを使用します、これは実際のメッシュを使用するほど正確ではないかもしれませんが、精度の違いは実際のメッシュで確認する手間をかける価値はありません。
境界ボリュームを使用しても、実際に各ボリュームをチェックする必要はありません。代わりに、境界ボリューム階層を構築して以前のカリングを実行できます。これを使用すると、シーンの複雑さに大きく依存します。
これは、より小型のエンジンに適したシンプルな手法であり、これまで使用したすべてのエンジンでほぼ使用されています。エンジンで非常に複雑なシーンをレンダリングする必要がない場合は、階層なしで「通常の」境界ボリューム/錐台チェックを使用することをお勧めします。
背面カリング
これは必須です、とにかく見えない顔を描くのはなぜですか?レンダリングAPIは、背面カリングのオン/オフを切り替えるインターフェースを提供します。特定の状況で背面を描画する必要がある一部のCADアプリケーションのように、オンにしない強力な理由がない限り、これは必須のことです。
オクルージョンカリング
Zバッファを使用すると、可視性の決定を解決できます。しかし、問題は、Zバッファーはパイプラインの後の段階でしか解決できないため、Zバッファーのパフォーマンスが常に優れているとは限らないことです。 Zテストに失敗する前のカラーバッファー。
オクルージョンカリングは、レンダリング錐台にあるオクルードされたオブジェクトをカリングするためにいくつかの初期テストを行うことにより、これを解決します。オクルージョンカリングの実用的な実装の1つは、ポイントベースのクエリを使用して、特定のオブジェクトが特定のポイントビューから見えるかどうかを確認することです。これは、最終イメージに寄与しないライトをカリングするためにも使用できます。これは、遅延エンジンレンダラーで特に役立ちます。
このような手法の実例としては、GTA5があります。GTA5では、摩天楼が都市の中心に戦略的に配置され、装飾だけでなく、オクルーダーとしても機能し、都市の残りの部分を効果的に塞ぎ、ラスタライズ。
詳細度
詳細レベルは広く使用されている手法であり、メッシュがシーンにあまり寄与していない場合に、よりシンプルなバージョンのメッシュを使用するという考え方です。2つの一般的な実装があります。大きく貢献しなくなった場合、単純にメッシュを単純なものに切り替えるだけです。メッシュは、距離やメッシュが占めるピクセル数(画面上の領域)などの要因に基づいて選択されます。もう1つのバージョンはメッシュを動的にテッセレーションします。これはテレインレンダリングで広く使用されています。
これらのすべてが機能しなかった場合はどうなりますか?
まあ、それは良い質問です。
最初に行う必要があるのは、グラフィックスプロファイラーを使用してアプリケーションのプロファイルを作成し、ボトルネックがどこにあるかを判断することです。レンダリングされるコンテンツが変更されると、ボトルネックが変わる可能性があることに注意してください。ボトルネックもCPUで実行されるコードの一部である可能性があるため、それも測定する必要があります。
その後、ボトルネックの最適化を行う必要がありますが、これには正しい答えはなく、ハードウェアごとに異なることに注意してください。
一般的なGPU最適化のコツ:
- シェーダーでの分岐を避けます。
- たとえば
{VNT}
、同じ配列または{V},{N},{T}
異なる配列でインターリーブされた異なる頂点構造を試してください。
- シーンを前面から背面に描画します。
- たとえば、画像がZテストを必要としない場合、いくつかのポイントでZバッファをオフにします。
- 圧縮テクスチャを使用します。
一般的なCPU最適化のコツ:
- 小さな関数にはインライン関数を使用します。
- 可能な場合は、SIMD(単一命令複数データ)を使用します。
- キャッシュが不親切なメモリジャンプを避ける。
- 「適切な」量のデータでVBOを使用します。(ハードウェアによって異なります)が、通常は描画呼び出しは少ない方が良いです。
しかし、ボトルネックが遅延シェーディングにあった場合はどうでしょうか?
この場合、遅延シェーディングはライトに関心があるため、最も明白な部分は実際のシェーディング計算を最適化することです。注目すべきポイントのいくつか:
- 最終画像に実際に影響するライトをレンダリングします。言い換えると、寄与しないライトをカリングします。これは、前述のオクルージョンカリングを使用して効果的に実装できます。
- このライトには鏡面反射光またはその他のコンポーネントが必要ですか?そうでないかもしれない。
- この光は影を落としますか?一部のライトは、影を落とす必要がありません。
- この軽い寄与は事前に計算できますか?動いていない場合、おそらくいくつかの側面を事前に計算できます。