4

少なくとも Vertex Array を使用するように常に言われます。しかし、私は3D世界にオブジェクトを配置するためにglPushMatrix()withを使用しているので、それは良い考えではないと思います.glTranslatef/glRotatef

では、世界の回転/移動された頂点位置の使用をやめてglPushMatrix()「手動で」計算し、頂点データを頂点配列にプッシュして一度にレンダリングする必要がありますか?

しかし、深度ソートされている画面上のすべてのオブジェクトに異なるテクスチャ サーフェスを使用すると、これらすべてがさらに混乱します。

そう:

  1. 各オブジェクトにテクスチャ サーフェス ID も格納する必要があります。
  2. 表示されているすべてのオブジェクトを Z 位置で並べ替えます (ゲームはトップダウンでのみ表示され、すべてのオブジェクトはフラットです)。
  3. この並べ替えられた配列を調べます。
  4. 新しいバッファーを作成し、頂点/texcoord/color/normal のみをこのバッファーにコピーします。
  5. テクスチャ サーフェス ID が以前の ID から変更されるたびに、正しいテクスチャ ID にバインドします。
  6. 収集した頂点データをアップロードします。
  7. 一時的な頂点配列に使用されているバッファーを解放します。
  8. 最初に並べ替えたすべてのデータを処理するまで、手順 4 ~ 7 を繰り返します。
  9. 並べ替えた配列データを解放し、手順 1 ~ 9 を繰り返します。

私はそれを正しくやっていますか?

また、ソートするオブジェクトのデータ構造をどのように設計すればよいですか? 例えば、std::vector各オブジェクトの頂点データを保存するために使用するのは良いですか? または、より良い代替手段はありますか?std::vectorこのすべてのデータを保存するには、次のようになると考えていました。

struct GameObject {
    int TexID;
    float z; // we will sort by this
    vector<VTCNStruct> VertexData; // store each point of the object here (including color/normal/texcoord points).
};

vector<GameObject> GameObjectBuffer; // push all sortable objects here

std::vectorまた、ステップ 4:この場合、既存のものを使用することは可能ですか? 頂点配列を GPU に送信する場合のように、未加工の配列を使用する必要があるという考えがありました。または、テクスチャ ID が変更されるたびに新しいバッファーを作成せずに、何らかの方法で (効率的に) ここでnew float[100]並べ替えられた既存の配列を使用できますか?std::vector

4

2 に答える 2

10

glBegin/glEnd廃止され、OpenGL-4 から削除されました。頂点バッファ オブジェクトを使用する場合は、頂点配列を確実に使用する必要があります。

即時モード (glBegin/glEnd) を使用すると、OpenGL ドライバーは関数呼び出しから頂点配列を構築する必要があります。いくつの頂点が到着するかは明らかではないため、最終的にはメモリを複数回再割り当てします (glBegin/glEnd の間の呼び出しを GPU が直接実行した時間はかなり過ぎています)。

頂点配列を使用すると、即時モードよりもパフォーマンスが低下することはありません。複数のオブジェクトのジオメトリを 1 つの頂点配列に入れても問題ありません。頂点インデックス リストを使用してそれらを分離できます。頂点インデックス リストもバッファ オブジェクトに格納できます。

次に、オブジェクトを描画する間にモデルビュー マトリックスを調整します。

ソート順は次のようになります。

  1. 不透明なオブジェクトと半透明のオブジェクトに分割します。不透明を並べ替える
  2. GL オブジェクトの切り替えは最もコストがかかるため、opqaues を GL オブジェクト (テクスチャ、シェーダー、マテリアルなど) で並べ替えます。
  3. 異なる GL オブジェクト グループごとに、近くから遠くに並べ替え、その順序で描画します
  4. 半透明を遠いものから近いものへと並べ替え、その順に描画します

バッファのアップ/ダウンロードをいじってはいけません。頂点データを 1 回アップロードしてから、インデックス配列とそれらが送信される順序を調整するだけです。利用可能な OpenGL メモリについて心配する必要はありません。制限はありません。データが GPU RAM に収まらない場合、ドライバーはそれをシステム メモリにスワップする責任があります。これが、最初に OpenGL オブジェクトでソートする必要がある理由でもあります。これは、OpenGL オブジェクト (glBindTexture、glBindBuffer など) を切り替えるたびに、ドライバーがスワップする必要があるため、これらのスワップ操作を最小限に抑えたいと考えています。インデックス配列の形式で GPU に送信されるデータの量は、最小で即時モード呼び出しによって送信されるものよりもはるかに少なくなります。

  • インデックス配列: 頂点あたり 16 ビット (16 ビット サイズのインデックスが最もパフォーマンスが高い)。

  • 即時モード呼び出し: 頂点ごとに 4*32 ビット

于 2010-12-14T09:57:44.173 に答える
2

オブジェクトごとに 1 つの頂点配列を保持する必要があります。glTranslatef/glRotatef などを使用しないでください。代わりに、変換を 1 つのマトリックスにまとめます。そのマトリックスを使用して、オブジェクトを深さで並べ替えます。次に、オブジェクト変換マトリックスをプッシュし、頂点配列を描画してから、変換マトリックスをポップすることにより、オブジェクトを前から後ろに描画します。

このアプローチは、頂点データを格納するために配列を常に作成および解放していないことを意味します。

std::vector の使用に関しては、ほとんどの実装では生の C 配列を内部で使用するため、 &myVec[0] を実行してその配列を取得できます。ただし、 std::vector がその配列を再割り当てし、永続化されたポインターが無効になる可能性があるため、そのポインターを永続化しようとしないでください。

于 2010-12-13T04:25:11.983 に答える