1

D3D に組み込まれた実行中の 3D エンジンがあります (SlimDX 経由)。レンダリング パイプラインの中断を避けるために、同じマテリアルを持つ多くのオブジェクトをより大きなメッシュにまと​​めました (状態の切り替えを減らすため)。これはうまく機能し、私のニーズに適したパフォーマンスレベルを提供します.

私が直面している問題は、実行時に、これらの大きなバッチ メッシュのサブセットのマテリアル プロパティを変更する必要があることです。そのために属性バッファを使用していますが、かなりうまく機能しています。以前は限られた数のアクティブ アトリビュート (メッシュあたり約 5 つ) を使用していましたが、今ではマテリアルにさらに多くのバリエーション (不透明度/カラーブレンドのさまざまな色合い) が必要であり、最終的には 100 以上の組み合わせになる可能性があります。これらの変更は実行時に発生するため、レンダリングが開始される前にそれらをまとめることはできません。確かにメッシュを再構築することはできましたが、それは遅く、マテリアル間の切り替えはインタラクティブな速度で行う必要があるため、そうではありません。

だから私の質問は、どのルートを取るのが最善ですか?

  • 必要に応じて使用可能な属性 ID で顔を動的にマスクし、完了したらリセットする、より堅牢な属性処理システムを実装する必要がありますか? アトリビュート バッファのフラグメンテーションがパフォーマンス ヒットを追加することを聞いたことがあります。また、間にマテリアル スイッチがある後続の DrawSubset() 呼び出しのパフォーマンス ヒットについても確信が持てません (つまり、いつが多すぎて、いつアトリビュート配列を最適化する必要がありますか?)。これについて経験のある人はいますか?

  • 私のもう 1 つのアイデアは、パラメーター化されたピクセル シェーダーを使用することです。派手なエフェクトは必要ありません。最低限必要なだけです (現在は、色のみで一部のオブジェクトが透明な組み込みのフラット シェーダーです)。そのため、シェーダー モデル 1 で十分です。ここでのアイデアは、1 つの汎用シェーダーを使用し、呼び出し間でマテリアルを切り替える代わりに、いくつかのシェーダー パラメーターを変更することです。しかし、これがマテリアルの切り替えよりも速いかどうか、および/またはプログラム可能なシェーダーがビルドインシェーダーよりも遅いかどうかはわかりません(同じ結果が与えられた場合)。

また、メッシュの切り替えと 1 つの大きなメッシュでの異なるサブセットの描画との間のパフォーマンス ヒットの違いについても興味があります (両方のケースで同じ数のマテリアル スイッチが与えられた場合)。

これらの質問は、GFXカードとそれぞれのパフォーマンス/年齢によって多少異なる場合があることを理解していますが、ここでは、何に最も力を注ぐべきかについての一般的なガイドラインを探しています (つまり、どのタイプの状態スイッチ/ CPU 干渉が最大のGPU ヒット)。メモリも懸念事項であるため、メッシュ全体 (または大部分) を複製する実装は私には不可能です。

私の焦点は、古い (5 歳)/機能の少ない/統合された GFX カードでのパフォーマンスであり、必ずしも最上位のゲーマー カードやワーク ステーション カード (Quadro など) ではありません。特定のボードでシェーダーのパフォーマンスがどれだけ優れているかに応じて、シェーダーを使用したソリューションを成功または失敗させる可能性があると思います。

すべての提案とフィードバックは大歓迎です。

よろしくお願いします!

4

1 に答える 1

3

シェーダーパラメータの変更も同様に遅くなります。理想的には、属性バッファーの大部分をグラフィックカードにアップロードするシェーダー2ベースのシェーダーを作成する必要があります。次に、適切な属性バッファを選択できる頂点ごとの属性フィールドがあります。

パフォーマンスの問題は、使用するドローコールの数に起因します。使用するドローコールが多いほど、パフォーマンスが低下します。シェーダー定数またはテクスチャを変更するには、新しいDIP呼び出しが必要になります。実行したいのは、シェーダー定数の変更の数とDIP呼び出しの数を最小限に抑えることです。

それはかなり複雑なプロセスマインドになります。

たとえば、64個のボーンを含む骨格モデルを処理している場合、2つのオプションがあります。1各ボーンのメッシュデータのワールドマトリックスを設定し、DIPを呼び出します。または、一度にできるだけ多くのボーンマトリックスをロードし、頂点の値を使用して使用するボーンを選択し、DIPを1回呼び出します。2番目の方が速くなります。この方法でも、マルチボーンベースのスキニングを非常に簡単に実行できることがわかるでしょう。

これは、シェーダーの定数を変更するすべての場合に当てはまります。固定機能パイプラインを使用する場合でも、最新のグラフィックハードウェア(つまり、2002年にリリースされたRadeon 9700以降のもの)は、固定機能をシェーダーベースに変換するため、同じパフォーマンスの問題が適用されることに注意してください。

基本的に、何よりも避けるべきことは、別のDIP呼び出しを行う原因となるものです。明らかに、すべてに対してこれを行うことを避けることは非現実的であり、特定の変更はより安価です。大まかな経験則として、費用の順に避けるべきことは次のとおりです:(私がこれをテストしてからしばらく経っているので、この主題についていくつかのテストと代替の読書をしたいかもしれません)

1)シェーダーを変更し
ます2)テクスチャを変更します
3)シェーダー定数を変更します
4)頂点バッファーを変更し
ます5)インデックスバッファーを変更します

1は断然最も高価です。

4と5は、他の部分と比較するとかなり安価ですが、頂点の形式が異なると、シェーダーが変更される可能性があるため、より大きな問題が発生する可能性があります。

編集:定数を変更することがなぜそれほど痛いのか完全にはわかりません。私はそのような変更がうまくパイプラインするだろうと思ったでしょう。たぶん現代のハードウェアではそれほど問題ではありません。一部の初期のハードウェアでは、定数がシェーダーにコンパイルされていたため、定数を変更するとシェーダーが完全に変更されました。

何でもそうですが、試してみて何が起こるかを確認するのが最善です。

すべての呼び出しをソートするための興味深い解決策は、上位8ビットがシェーダーIDを提供するソートキーを使用することです。テクスチャなどの次の10ビット。次に、通常の数値ソートを実行すると、さまざまなソート順で簡単に遊んで、最高のパフォーマンスが得られるものを確認できます:)

Edit2:ピクセルシェーダーの状態を変更するものは、パイプラインの奥深くにあるため、頂点バッファーの状態を変更するよりもコストがかかることに注意してください。したがって、それが泡立つのに時間がかかります...

于 2009-11-20T10:45:35.133 に答える