すべてにインスタンス化を使用しますか?


16

インスタンス化は、同じメッシュの複数のコピーを一度にレンダリングするとき(大幅に)パフォーマンスを(大幅に)向上させます。しかし、1回の描画呼び出しで正確に1つのコピーをレンダリングする場合、オーバーヘッドはどれくらいありますか?エンジンによってレンダリングされたすべてのジオメトリにインスタンス化を使用するのは良い考えですか、悪い考えでしょうか?

編集:FPSゲームを作成しているとしましょう。ほとんどのオブジェクトには、ナイフ、銃、機関銃、建物、電波塔という1つのインスタンスしかありません。しかし、複数のインスタンスを持つオブジェクトもあります:木(例:数百のインスタンスを持つ3種類の木)、草など...つまり、1つのインスタンスオブジェクトを「伝統的な」方法でレンダリングするのではなく、インスタンス化を使用して草を作成する場合、インスタンス化を使用してすべてをレンダリングします。したがって、無線タワーにはインスタンスが1つしかなく(その情報はインスタンスデータバッファーに格納されます)、DrawInstanced()インスタンスカウントが等しいコールを使用してそのタワーをレンダリングします1。他のすべてのオブジェクトと同じです(もちろん、木や草には複数のインスタンスがあります)。

だから私の質問は次のとおりです。インスタンス化を使用してオブジェクトの単一インスタンスを描画するのは悪い考えですか?インスタンス化のオーバーヘッド(メモリおよびパフォーマンスの面)が大きすぎるのか、それともシングルインスタンスオブジェクトのレンダリングに望ましくないのですか?

回答:


19

XPDMを使用したD3D9では、ほぼ確実に可能な限りインスタンス化することができます。ドローコールのオーバーヘッドは非常に高いため、理にかなっています。このシナリオでは、クロスオーバーポイントは2インスタンスまたは3インスタンスまで低くすることができます。

特定のメッシュのインスタンスが1つしかない場合、表面上ではインスタンス化されていない状態で描画したくなるかもしれません。ただし、何が関係しているかを見てください。

  • インスタンスごとのバッファへのデータのロードからシェーダー定数のアップロードに切り替える必要があります。
  • 頂点シェーダーの2つのコピーを保持する必要があります。1つはインスタンス用、もう1つは非インスタンス用です。
  • 同様に、レンダリングコードのコピーを2つ保持する必要があります。
  • シェーダーを切り替える必要があります。
  • 頂点フォーマットを切り替える必要があります。
  • 頂点バッファを切り替える必要がある場合があります。
  • そして、次のメッシュグループのインスタンス化された描画に戻る場合は、もう一度やり直す必要があります。

単一のメッシュ(FPSの銃モデルなど)しか持っていない場合でも、インスタンス化が役立つ場合があります。フォワードレンダラーでz-prepassを使用してマルチパスライトアキュムレーションを実行するとします。各ライトの追加パスの代わりに、ライトをインスタンスごとのデータにして、インスタンス化して描画します。

最初のシナリオに基づいて、物語の教訓は、オブジェクトクラスがインスタンス化を使用できる場合、そのクラスのすべてのオブジェクトに対して常にインスタンス化を使用することが理にかなっているということです。

2番目のシナリオに基づくと、このストーリーの教訓は、インスタンス化には「20本の木を描く必要がある」というだけでなく、非自明な用途があるということです。


あなたが与えた理由は、そもそも私にこの質問をさせたのと同じ理由です。ありがとうございました。
NPS

12

(私のシステムでは、他のどこでもテストしませんでした)GLでは、1つのメッシュのインスタンス化(カウント= 1で描画)にオーバーヘッドがありますが、どこから来たのかわかりません。しないことを強くお勧めします。

数か月前に実際のアプリケーションでこれをテストしました。私は、Crytek Sponzaシーンでいくつかのグローバルイルミネーションアルゴリズムをコーディングしました。これは、約350メッシュ(正確には覚えていない)で構成され、そのうちのいくつかは少数のインスタンスを共有します。最初は、すべてをインスタンス化し、インスタンスカウント1で残りを描画するように提案しました。レンダリングコードが少し単純化されたためです。

後でレンダラーを最適化するときに、count = 1オブジェクトのインスタンス化から通常の方法でのサブミットに切り替えるだけで、i7 3770k(およびGTX 770)で1フレームあたり約3.5ミリ秒の時間を節約できました。複数のインスタンスを持つメッシュを従来の方法で行うだけに切り替えると、さらに0.5ミリ秒節約できました。全体として、アプリケーションは約120 FPSから約230 FPSになりました。

もちろん、これらの数値は常にアプリケーションのボトルネックの場所に依存します。後者の0.5ミリ秒は、ドローコールが非常に多いアプリケーションで実際にスローダウンになる可能性があります。しかし、そうでなければ、私の経験では、一度に多くのものを描画していない場合、インスタンス化にはいくつかの厄介なオーバーヘッドがあります。


おもしろいですが、AMDとIntelのドライバーのデータも見るといいのですが、そうでなければ、「In GL」ではなく「On system」と言う必要があります。一方、他の実装の問題ではない場合でも、それを使用していない場合は、インスタンス化を回避するのに十分な理由があります。
bcrist

2

インスタンス化された単一のオブジェクトの描画は、通常、単一のオブジェクトの描画よりもコストがかかることを確信できます。インスタンス化のために、GPUは大量のオブジェクトを準備していますが、この準備は単一のオブジェクトの準備とは異なります。ただし、このパフォーマンスのギャップがどれだけ大きいかは、実験によってのみ見つけることができ、実際のレンダリング設定に大きく依存します。確実に知る唯一の方法は、自分でテストすることです。単一のドローコールのベンチマークを行うのは難しいのですが、ここではいくつかのアイデアを進めます。


2

4年が経ちました ...そして、1で「インスタンス化された」描画呼び出しを送信するのは完全に問題ないと思います。お気付きかもしれませんが、新しいAPI DX12Vkは両方とも0からNUM_INSTANCES。また、DrawIndexed(...)がないことに注意してください。

編集

注意点として、この最新のAPIではおそらく上記で問題ありません。Gl<3.3のような古いものを使用したり、DX11では他のユーザーが述べたようにプロファイリングが必要になる場合があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.