Wann sollte ich indizierte Arrays von OpenGL-Vertices verwenden?

Ich versuche eine klare Vorstellung davon zu bekommen, wann ich indizierte Arrays von OpenGL-Vertices verwenden sollte, die mit gl [Multi] DrawElements und dergleichen gezeichnet wurden, und wann ich einfach zusammenhängende Arrays von Vertices verwenden sollte, die mit gl [Multi] gezeichnet wurden DrawArrays.

(Aktualisieren Der Konsens in den Antworten, die ich erhielt, ist, dass man immer indizierte Eckpunkte verwenden sollte.)

Ich bin in dieser Angelegenheit mehrmals hin und her gegangen, daher werde ich mein aktuelles Verständnis skizzieren, in der Hoffnung, dass mir jemand sagen kann, dass ich jetzt mehr oder weniger richtig bin, oder auch darauf hinweisen, wo meine verbleibenden Missverständnisse sind sind. Insbesondere habe ich drei Schlussfolgerungen in Fettdruck. Bitte korrigieren Sie sie, wenn sie falsch sind.

Ein einfacher Fall ist, wenn meine Geometrie aus Maschen besteht, um gekrümmte Oberflächen zu bilden. In diesem Fall haben die Scheitelpunkte in der Mitte des Netzes identische Attribute (Position, Normal, Farbe, Texturkoordinate usw.) für jedes Dreieck, das den Scheitelpunkt verwendet.

Dies lässt mich zu folgendem Schluss kommen:

1. Bei Geometrie mit wenigen Nähten sind indizierte Arrays ein großer Gewinn.

Regel 1 immer befolgen, außer:

Bei einer sehr blockartigen Geometrie, bei der jede Kante eine Naht darstellt, ist der Vorteil von indizierten Arrays weniger offensichtlich. Ein einfaches Beispiel: Obwohl jeder Scheitelpunkt in drei verschiedenen Flächen verwendet wird, können wir keine Scheitelpunkte zwischen ihnen teilen, da für einen einzelnen Scheitelpunkt die Oberflächennormalen (und mögliche andere Dinge wie Farbe und Texturkoordinaten) gelten ) wird auf jedem Gesicht unterschiedlich sein. Daher müssen wir explizit redundante Vertex-Positionen in unser Array einfügen, damit dieselbe Position mehrmals mit unterschiedlichen Normalen usw. verwendet werden kann. Dies bedeutet, dass indizierte Arrays weniger nützlich sind.

z.B. Beim Rendern einer einzelnen Fläche eines Würfels:

 0     1
  o---o
  |\  |
  | \ |
  |  \|
  o---o
 3     2

(Dies kann isoliert betrachtet werden, da die Nähte zwischen dieser Fläche und allen angrenzenden Flächen bedeuten, dass keiner dieser Eckpunkte zwischen den Flächen geteilt werden kann.)

wenn mit GL_TRIANGLE_FAN (oder _STRIP) gerendert wird, kann jede Fläche des Würfels folgendermaßen gerendert werden:

verts  = [v0, v1, v2, v3]
colors = [c0, c0, c0, c0]
normal = [n0, n0, n0, n0]

urch das Hinzufügen von Indizes können wir dies nicht vereinfachen.

araus schließe ic

2. Beim Rendern von Geometrie, bei der es sich um alle Nähte oder hauptsächlich um Nähte handelt, sollte bei Verwendung von GL_TRIANGLE_STRIP oder _FAN niemals indizierte Arrays verwendet werden, sondern immer gl [Multi] DrawArrays.

(Aktualisieren Antworten zeigen an, dass diese Schlussfolgerung falsch ist. Obwohl die Indizes es uns nicht erlauben, die Größe der Arrays hier zu reduzieren, sollten sie dennoch verwendet werden, da andere Leistungsvorteile vorliegen, wie in den Kommentaren beschriebe

Die einzige Ausnahme zu Regel 2 ist:

Bei Verwendung von GL_TRIANGLES (anstelle von Streifen oder Fächern) kann die Hälfte der Scheitelpunkte immer noch zweimal mit identischen Normalen und Farben usw. verwendet werden, da jede Würfelfläche als zwei separate Dreiecke gerendert wird. Wiederum für dieselbe einzelne Würfelfläche:

 0     1
  o---o
  |\  |
  | \ |
  |  \|
  o---o
 3     2

Ohne Indizes wären die Arrays mit GL_TRIANGLES ungefähr so:

verts =   [v0, v1, v2,  v2, v3, v0]
normals = [n0, n0, n0,  n0, n0, n0]
colors =  [c0, c0, c0,  c0, c0, c0]

Da ein Eckpunkt und eine Normale häufig jeweils 3 Floats sind und eine Farbe häufig 3 Bytes umfasst, ergibt sich für jede Würfelfläche Folgendes:

verts   = 6 * 3 floats = 18 floats
normals = 6 * 3 floats = 18 floats
colors  = 6 * 3 bytes  = 18 bytes

= 36 floats and 18 bytes per cube face.

(Ich verstehe, dass sich die Anzahl der Bytes ändern kann, wenn verschiedene Typen verwendet werden. Die genauen Zahlen dienen nur zur Veranschaulichung.)

Mit Indizes können wir dies ein wenig vereinfachen und geben:

verts   = [v0, v1, v2, v3]     (4 * 3 = 12 floats)
normals = [n0, n0, n0, n0]     (4 * 3 = 12 floats)
colors  = [c0, c0, c0, c0]     (4 * 3 = 12 bytes)
indices = [0, 1, 2,  2, 3, 0]  (6 shorts)

= 24 floats + 12 bytes, and maybe 6 shorts, per cube face.

Siehe, wie im letzteren Fall die Eckpunkte 0 und 2 zweimal verwendet werden, aber in jedem der Felder verts, normalals und colors nur einmal dargestellt werden. Das klingt nach einem kleinen Gewinn für die Verwendung von Indizes, selbst im Extremfall, wenn jede einzelne Geometriekante eine Naht ist.

Dies lässt mich zu folgendem Schluss kommen:

3. Wenn Sie GL_TRIANGLES verwenden, sollten Sie immer indizierte Arrays verwenden, auch für Geometrie, bei der es sich ausschließlich um Nähte handelt.

Bitte korrigieren Sie meine Schlussfolgerungen in Fettdruck, wenn sie falsch sind.

Antworten auf die Frage(2)

Ihre Antwort auf die Frage