Jeder glDraw * ist ein Draw-Aufruf.
1 glDrawArrays ist 1 Draw Call.
1 glDrawElements ist 1 Draw Call.
Es spielt keine Rolle (was die Anzahl der Draw Calls betrifft), wie viele Eckpunkte oder Indizes Sie verwenden. 1 glDraw * ist 1 Draw Call.
Die einfachen Fälle des Zeichnens von Quads (vorausgesetzt, die von Ihnen verwendete GL-Version hat Quads nicht entfernt) oder Dreiecke sind kein gutes Beispiel für den Vergleich dieser Quadrate, da eine Liste von Quads oder eine Liste von Dreiecken mit einem einzigen Aufruf gezeichnet werden kann. und glDrawArrays erscheinen effizienter, da sie keinen zusätzlichen Aufwand für die Indizierung haben.
Nehmen wir einen etwas komplexeren Fall, der jedoch für ein realistischeres Szenario repräsentativ ist. Stellen Sie sich vor, Sie haben ein Modell, das aus mehreren Dreiecksstreifen und Lüftern besteht:
glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);
glDrawArrays (GL_TRIANGLE_STRIP, .....);
glDrawArrays (GL_TRIANGLE_FAN, .....);
In diesem Beispiel erhalten Sie mit glDrawArrays insgesamt 6 Zeichenaufrufe für das Modell. Sowohl Streifen als auch Lüfter können jedoch problemlos in indizierte Dreiecke konvertiert werden. Fügen Sie also Indizes hinzu, und es wird:
glDrawElements (GL_TRIANGLES, .....);
Das ist ein Draw Call für das gesamte Modell.
Die Vorteile von glDrawElements gegenüber glDrawArrays sind mehr als nur das Speichern von Speicher, was die naive Art der Messung ist. Es besteht die Möglichkeit, Speicherplatz zu sparen, wenn Scheitelpunkte wiederverwendet werden können, da ein Index normalerweise kleiner als ein Scheitelpunkt ist (selbst wenn Sie viele Indizes im Gleichgewicht haben, sind sie kleiner). Weitere Vorteile sind jedoch:
Reduzierte Anzahl von Draw Calls. Jeder Draw-Aufruf verursacht einen gewissen Overhead durch das Überprüfen des Status, das Einrichten von Dingen usw., und ein Großteil dieses Overheads geschieht auf der CPU-Seite. Durch die Reduzierung der Anzahl der Draw Calls vermeiden wir einen Großteil dieses Overheads.
Vertex-Wiederverwendung. Dies ist viel mehr als nur Speicherplatzersparnis. Ihre GPU verfügt wahrscheinlich über einen Hardware-Vertex-Cache, in dem kürzlich transformierte Vertices gespeichert werden können. Wenn derselbe Scheitelpunkt erneut eingeht und sich im Cache befindet, kann er aus dem Cache wiederverwendet werden, anstatt erneut transformiert werden zu müssen. Ihre Hardware überprüft den Cache durch Vergleichen von Indizes. In OpenGL-Begriffen können Sie den Cache also nur mit glDrawElements verwenden.
Um Ihre spezifischen Fragen zu beantworten:
Wie könnte glDrawElements Draw Calls speichern ...? In dem von Ihnen verwendeten Beispiel ist dies nicht der Fall. Jeder hat einen Draw Call. Wie ich oben diskutiere, ist dieses Beispiel ein sehr schlechtes Beispiel für den Vergleich der beiden.
Wie würde die Verwendung von glDrawElements Platz sparen ...? Weil Indizes kleiner als Eckpunkte sind. Ein 16-Bit-Index besteht aus zwei Bytes, ein Positions- / Farb- / Texcoord-Scheitelpunkt aus 24 Bytes. 6 Eckpunkte sind 144 Bytes, 4 Eckpunkte plus 6 Indizes sind 108 Bytes.
Beim Zeichnen eines Quadrats aus 2 Dreiecken ...? Eins und eins. Ein glDraw * -Aufruf ist ein Draw-Aufruf. Die Anzahl der verwendeten Eckpunkte oder Indizes ist für diese Messung irrelevant. Aber ich muss noch einmal betonen, dass dies ein sehr schlechtes Beispiel für den Vergleich der beiden ist.
Und nur um die Sache ein wenig zu komplizieren, während glDrawElements mit Dreiecken der optimale Pfad auf Desktop-GPUs ist, kann es auf Mobilgeräten sehr unterschiedlich sein. Einige mobile GPUs bevorzugen möglicherweise glDrawArrays mit GL_TRIANGLE_STRIP (in diesem Fall würden Sie entartete Dreiecke hinzufügen, um Grundelemente zu verketten), und ich habe noch nicht einmal fortgeschrittenere Themen wie primitiven Neustart oder Multi-Draw angesprochen.