24未満の頂点を持つキューブを構築することは可能ですか


14

Minecraftのようなキューブベースの世界があり、24個未満の頂点を持つキューブを構築してメモリ使用量を削減する方法があるかどうか疑問に思っています。

私には2つの理由で不可能だと思われます。法線が正しく出ないことと、面ごとのテクスチャが機能しないことです。

これは事実ですか、それとも間違っていますか?たぶん助けることができるいくつかの派手な新しいDX11技術がありますか?

編集:明確にするために、2つの要件があります:適切な照明を行うために各キューブフェースの表面法線が必要であり、各キューブフェースのテクスチャ配列の異なるインデックスに対処する方法が必要です


1
グラフィックカードのメモリ使用量またはRAM使用を減らしますか?
-doppelgreener

1
頂点データは現在RAMとGPUに保存されているため、削減すると両方が削減されます。
テラノール

回答:


9

フェースごとの法線のみが必要で、フェースのテックス座標が厳密に0 / 0、0 / 1、1 / 0、1 / 1(またはレイアウトに似ている)である場合、8つの頂点を持つキューブを構築できます。および30(再起動を伴うストリップ)または36(リスト)インデックス。頂点シェーダーでSV_VertexIDに基づく定数配列ルックアップを使用して、法線とテックス座標を取得します。

これを行うと、頂点バッファーにtexcoordや法線を含める必要さえなくなり、さらにメモリを節約できます。

さらに進むと、キューブごとに24頂点まで移動できますが、インスタンス化も使用できます。各キューブは頂点バッファー内の固定サイズ(1x1x1)になり、インスタンスごとのデータとしてスケーリングファクターと位置(キューブが回転しないと仮定すると、マトリックス)があります。回転しない場合、1回限りのコストは24頂点になりますが、各キューブを完全に指定するには6つのフロートが必要です。回転するケースでは16個のフロートを見ていますが、それでもかなりの節約になります(この場合、マトリックス変換でCPU側のボトルネックになる可能性が高くなります。頂点シェーダー-頂点ごとに行われたとしても、非常に高速なので、心配する必要はありません)。

顔ごとのテクスチャの場合、テクスチャ配列を使用します。もちろん、配列内のそのような各テクスチャが同じサイズであることを確認する必要があり、配列自体を変更する必要がある場合は現在のバッチを中断する必要がありますが、そうでなければ問題なく動作します。3番目のtexcoordを頂点定義に追加して、各面に使用する配列スライスを定義します。

これでGSは必要ありません。ジオメトリシェーダーステージを有効にすると、独自のオーバーヘッドが追加されるため、GSを使用するよりも高速に実行する必要があります。

このメソッドを使用して大量のキューブを描画するだけのエンジンでベンチマークコードを実行しました。比較的ローエンドのGPUで60fpsをクリアしながら、プロセスを最適化するために他に何もすることなく、300,000個以上のキューブを簡単に噛むことができます。確かに私はそれらをライティングもテクスチャリングもしていませんが、アルファブレンディングを有効にし、バックフェースカリングを無効にしており、全体的に「最適化のために他に何もしない」部分とバランスが取れているので、この方法で打つことができる球場。


1
以前はインスタンス化を使用していましたが、40k未満のキューブに最適です。しかし、少なくとも256kのキューブがあり、インスタンス化でも処理されませんでした。ただし、ルックアップでSV_VertexIDを使用することは非常に有望です。
テラノール

インスタンスごとのバッファーの大きさは?それらをすべて巨大なバッファーに詰め込もうとすると、GPUが窒息する可能性があります。私は通常、インスタンスごとのバッファーを64kオブジェクトに十分なスペースに保持し(必要に応じて描画呼び出しを分割します)、破棄/上書きなしパターンを使用し、中間配列からコピーする代わりにマップされたポインターに直接書き込みます。 。
マキシマスミニマス

また、マップの数を少なく保つことは不可欠です。1つのキューブのマッピング/書き込み/ 40k回のマッピング解除は、40kキューブのマッピング/書き込み/ 1回のマッピング解除よりもはるかに遅くなります。前者を行っていた場合は、後者に切り替えてみてください。
マキシマスミニマス

15

あなたができる主な最適化は、すべてのキューブが実際に24個の頂点すべてを必要とするわけではないという事実に基づいていると思います。実際、24個の頂点を必要とするキューブは、空中に浮遊しているキューブのみであり、これはおそらくまれにしか発生しません。

一般に、空気と接触している面に対してのみ四角形を生成します。つまり、2つのキューブが互いに接触している場合、それらが接触している面の頂点を生成する必要はありません。

以下の画像は、この概念を示していますが、理解しやすいように2Dで示しています。画像には11個の占有ブロック(塗りつぶされた灰色の円で表されます)があり、通常4 x 11 = 44のエッジを表す必要があります(キューブではなく正方形であるため4)。しかし、ご覧のとおり、実際にエッジを描画する必要があるのは、空の正方形(この場合は8つのエッジ)と接触している場合のみです。

ここに画像の説明を入力してください

2Dのこのような単純な例で44エッジを8エッジに減らすことができた場合、大規模な3Dワールドでのゲインを想像してみてください...

これはこの記事で説明されているアプローチであり、OpenGLを対象としていますが、読むことをお勧めします。しかし、概念はかなり普遍的でなければなりません。

また、ジオメトリシェーダーを使用してGPUで頂点をオンザフライで生成し、それらをメモリに保存する必要をなくすこともできますが、私はそれを経験しておらず、大規模な場合にどれだけうまく機能するかわかりません世界。


1
非常に興味深い記事。私はすでにエッジの最適化を行っています。これは確かに多くの助けになります。ジオメトリシェーダーを試して、うまくいくかどうかを確認します。
テラノール

ジオメトリシェーダーと外積を使用して法線を計算しますか?私はそれを使用することを考えていました。たとえば、平らな表面用に別のプログラムを作成します(テクスチャーは関係ありません)。
-dreta

@dretaそれだけでなく、立方体の重心をポイントリストとして送信するだけで、すべての頂点がGSによって放出されます。おそらく、いくつかの隣接する情報をポイントにエンコードして、シェーダーが本当に必要な面のみを生成するようにしますが、私はその方法を考えていません。
デイヴィッドゴーベイア

望むパフォーマンスであれば、ジオメトリシェーダーを使用しないでください。彼らは完全にパイプラインを台無しにします。GPUでジオメトリを生成する場合は、コンピューティングシェーダーまたはopenCLを使用してください
ロバートフレイザー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.