glDrawArraysとglDrawElementsの違い


12

OpenGL ESの上で私の心をリフレッシュしている間、私は出くわしたglDrawArraysglDrawElements

私はそれらがどのように使用されるかを理解し、なぜそれらが異なるのかを理解しています。

私が理解していないように見えるのは、glDrawElements描画呼び出しを保存する方法がわからないということです(描画呼び出しの保存は、私が読んだほとんどの本で言及されている説明なので、ここで言及します)。

2つの三角形を使用して正方形を描こうとした単純なシナリオを想像してみてください。

を使用するglDrawArraysときに使用する6つの頂点のセットglDrawElementsが必要です。6つの要素を持つインデックス配列に加えて、4つだけ必要です。

上記を踏まえて、ここに私が理解していないものがあります:

  1. glDrawElementsインデックス配列(正方形の場合は6つのインデックス)を使用して、4つの要素(6回)を持つ頂点配列にインデックスを付ける必要がある場合、どのように描画呼び出しを保存できますか?言い換えれば、glDrawElementsそれでも合計6回の描画呼び出しが必要になるということglDrawArraysですか?
  2. glDrawElementsそれでも2つの配列、つまり頂点とインデックスの2つの配列が必要な場合、どのように保存スペースを使用しますか?
  3. 2つの三角形から正方形を描画する場合、簡単にするために、glDrawElements(頂点配列に4項目、インデックス配列にglDrawArrays6項目)および(頂点配列にのみ6項目)の描画呼び出しを個別に何回行う必要がありますか?

ありがとう。

回答:


16

各glDraw *は描画呼び出しです。

1つのglDrawArraysは1つの描画呼び出しです。
1つのglDrawElementsは1つの描画呼び出しです。

(描画呼び出し数に関する限り)使用する頂点またはインデックスの数は関係ありません。1つのglDraw *は1つの描画呼び出しです。

四角形のリストまたは三角形のリストはいずれかを1回呼び出すだけで描画できるため、四角形(使用するGLバージョンで四角形が削除されていないと想定)または三角形を描画する単純なケースは、これらを比較する良い例ではありません。また、インデックス作成の追加のオーバーヘッドがないため、glDrawArraysはより効率的に表示されます。

もう少し複雑なケースを考えてみましょう。ただし、より現実的なシナリオを代表するものです。複数の三角形のストリップとファンで構成されるモデルがあるとします。

glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);

この例では、glDrawArraysを使用すると、モデルに対して合計6つの描画呼び出しが行われます。ただし、ストリップとファンはどちらもインデックス付きの三角形に簡単に変換できるため、インデックスを追加すると次のようになります。

glDrawElements (GL_TRIANGLES, .....);

これは、モデル全体の1つの描画呼び出しです。


glDrawArraysに対するglDrawElementsの利点は、それを測定する単純な方法である単なるメモリ節約以上のものです。インデックスは通常、頂点よりも小さいので(したがって、多くのインデックスがバランスしていても、インデックスは小さくなるため)、頂点を再利用できるメモリ節約の可能性がありますが、他の利点は次のとおりです。

  • ドローコール数の削減。各描画呼び出しでは、状態の検証、設定などからオーバーヘッドが発生し、このオーバーヘッドの多くはCPU側で発生します。描画呼び出しの数を減らすことにより、このオーバーヘッドの多くを回避します。

  • 頂点の再利用。これは単なるメモリ節約以上のものです。GPUにはハードウェアの頂点キャッシュがあり、最近変換された頂点を保存できます。同じ頂点が再び入ってきて、それがキャッシュにある場合、再度変換する必要はなく、キャッシュから再利用できます。ハードウェアはインデックスを比較してキャッシュをチェックするため、OpenGL用語では、キャッシュを使用する唯一の方法はglDrawElementsを使用することです。


特定の質問に答えるために:

  1. glDrawElementsはどのように描画呼び出しを保存できますか?使用する例では、そうではありません。それぞれに1つの描画呼び出しがあります。上記で説明したように、この例は2つを比較するには非常に悪い例です。

  2. glDrawElementsを使用するとどのようにスペースを節約できますか?インデックスは頂点よりも小さいからです。16ビットインデックスは2バイト、位置/色/ texcoord頂点は24バイトです。6つの頂点は144バイト、4つの頂点と6つのインデックスは108バイトです。

  3. 2つの三角形から正方形を描く場合...?一つずつ。glDraw *呼び出しは1つの描画呼び出しであり、使用される頂点またはインデックスの数はこの測定には関係ありません。しかし、改めて強調しなければなりません。これは、2つを比較する非常に悪い例です。


最後に、少し複雑にすることは重要ですが、三角形の付いたglDrawElementsはデスクトップGPUでは最適なパスですが、モバイルでは非常に異なる場合があります。一部のモバイルGPUはGL_TRIANGLE_STRIPを備えたglDrawArraysを好む場合があり(この場合、縮退した三角形を追加してプリミティブを連結します)、プリミティブの再起動やマルチ描画などのより高度なトピックについても触れていません。


フィードバックをありがとうございます。私はあなたが共有したものを読むのに少し時間をかけています。私はあなたの返事を認めました。再度、感謝します。
Unheilig '19年

6つのDrawTriangleFans呼び出しとDrawTriangleStrips呼び出しを1つのDrawTriangles呼び出しに変換する例では、これは本当にいくつかのパフォーマンスを向上させますか?私は100個の三角形で構成される三角形ストリップを描画理解に個別に100個の三角形を描画するよりもはるかに効率的であり、かつ簡単に任意のペナルティを相殺する利点は、6回の関数呼び出しではなく、1使用してから発生した
サミュエル・リーの

@SamuelLi 6-to-1は大きな改善にはなりませんが、単に原理を説明することを目的としています。また、私が示したように、ストリップは通常、1998年以降のデスクトップハードウェアのインデックス付きリストに勝るパフォーマンスではありません。ストリップの使用を勧めている文書の日付を確認してください。
Maximus Minimus

明確にしていただきありがとうございます。@MaximusMinimus
Samuel Li
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.