Was sind Vertex-Array-Objekte?

113

Ich fange gerade erst an, OpenGL aus diesem Tutorial zu lernen: http://openglbook.com/the-book/
Ich komme zu Kapitel 2, wo ich ein Dreieck zeichne, und ich verstehe alles außer VAOs (ist dieses Akronym in Ordnung?). Das Tutorial hat diesen Code:

glGenVertexArrays(1, &VaoId);
glBindVertexArray(VaoId);

Obwohl ich verstehe, dass der Code notwendig ist, habe ich keine Ahnung, was er tut. Obwohl ich VaoId nach diesem Punkt nie mehr benutze (außer um es zu zerstören), funktioniert der Code ohne ihn nicht. Ich gehe davon aus, dass dies daran liegt, dass es gebunden werden muss, aber ich weiß nicht warum. Muss dieser genaue Code nur Teil jedes OpenGL-Programms sein? Das Tutorial erklärt VAOs wie folgt:

Ein Vertex-Array-Objekt (oder VAO) ist ein Objekt, das beschreibt, wie die Vertex-Attribute in einem Vertex-Pufferobjekt (oder VBO) gespeichert werden. Dies bedeutet, dass der VAO nicht das eigentliche Objekt ist, in dem die Scheitelpunktdaten gespeichert sind, sondern der Deskriptor der Scheitelpunktdaten. Vertex-Attribute können durch die Funktion glVertexAttribPointer und ihre beiden Schwesterfunktionen glVertexAttribIPointer und glVertexAttribLPointer beschrieben werden, von denen die erste im Folgenden untersucht wird.

Ich verstehe nicht, wie die VAO die Scheitelpunktattribute beschreibt. Ich habe sie in keiner Weise beschrieben. Erhält es die Informationen vom glVertexAttribPointer? Ich denke das muss es sein. Ist die VAO lediglich ein Ziel für die Informationen von glVertexAttribPointer?

Ist das Tutorial, dem ich folge, akzeptabel? Gibt es etwas, auf das ich achten sollte, oder ein besseres Tutorial, dem ich folgen kann?

Patrick
quelle

Antworten:

99

"Vertex Array Object" wird Ihnen vom OpenGL ARB-Unterausschuss für alberne Namen zur Verfügung gestellt.

Stellen Sie es sich als ein Geometrieobjekt vor. (Als SGI Performer-Programmierer aus alter Zeit nenne ich sie Geosets.) Die Instanzvariablen / -elemente des Objekts sind Ihr Scheitelpunktzeiger, normaler Zeiger, Farbzeiger, Attribut-N-Zeiger, ...

Wenn ein VAO zum ersten Mal gebunden wird, weisen Sie diese Mitglieder durch Aufrufen zu

glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer...;
glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer...;

und so weiter. Welche Attribute aktiviert sind und welche Zeiger Sie angeben, werden im VAO gespeichert.

Wenn Sie danach den VAO erneut binden, werden alle diese Attribute und Zeiger ebenfalls aktuell. Ein glBindVertexArrayAufruf entspricht also dem gesamten Code, der zuvor zum Einrichten aller Attribute benötigt wurde. Es ist praktisch, um Geometrie zwischen Funktionen oder Methoden weiterzugeben, ohne eigene Strukturen oder Objekte erstellen zu müssen.

(Einmaliges Setup, Mehrfachverwendung ist der einfachste Weg, VAOs zu verwenden. Sie können Attribute jedoch auch ändern, indem Sie sie binden und mehr Aktivierungs- / Zeigeraufrufe ausführen. VAOs sind keine Konstanten.)

Weitere Informationen als Antwort auf Patricks Fragen:

Die Standardeinstellung für eine neu erstellte VAO ist, dass sie leer ist (AFAIK). Überhaupt keine Geometrie, nicht einmal Scheitelpunkte. Wenn Sie also versuchen, sie zu zeichnen, wird ein OpenGL-Fehler angezeigt. Dies ist ziemlich vernünftig, wie in "Alles auf False / NULL / Null initialisieren".

Sie müssen nur, glEnableClientStatewenn Sie Dinge einrichten. Der VAO merkt sich den Aktivierungs- / Deaktivierungsstatus für jeden Zeiger.

Ja, die VAO speichert glEnableVertexAttribArrayund glVertexAttrib. Die alten Vertex-, Normal-, Color-, ... -Arrays sind dieselben wie die Attribut-Arrays, Vertex == # 0 usw.

Hugh
quelle
62
"Vertex Array Object" wird Ihnen vom OpenGL ARB-Unterausschuss für alberne Namen zur Verfügung gestellt. Ja, so ein dummer Name für ein Objekt , das Vertex- Array- Bindungen speichert .
Nicol Bolas
2
Auch sind VAOs überhaupt verwandt mitglVertexAttribPointer
Patrick
2
Bitte fügen Sie einige Informationen zur Verwendung generischer Scheitelpunktattribute für die Personen hinzu, die das Kernprofil verwenden.
Oskar
8
@NicolBolas Ein besserer Name wäre VertexArrayMacrooder ähnliches.
Bobobobo
7
@NicolBolas "Vertex Array Object" ist ein schrecklicher Name. Es geht darum , Daten an Attribute zu binden . Es geht nicht um ein Array von Eckpunkten, wie der Name schon sagt. Der Name enthält keinen Verweis auf Bindungen oder Attribute, und da "Vertex-Array" selbst ein getrenntes Konzept ist, wird das Verständnis noch schwieriger. IMHO ist "(Vertex) Attribute Binding Object" leichter zu verstehen. Auch Geometrieobjekt ist besser: Ich mag es nicht, aber zumindest ist es nicht überladen.
AkiRoss
8

Vertex-Array-Objekte sind wie Makros in Textverarbeitungsprogrammen und dergleichen. Eine gute Beschreibung finden Sie hier .

Makros nur daran erinnern , die Aktionen , die Sie haben, wie activate dieses Attribut, binden diesen Puffer, usw. Wenn Sie anrufen glBindVertexArray( yourVAOId ), es ist einfach Replays diese Attribut Zeiger Bindungen und Bindungen puffern.

Ihr nächster Aufruf zum Zeichnen verwendet also alles, was von der VAO gebunden wurde.

VAOs speichern keine Scheitelpunktdaten . Nein , die Eckendaten in einem Scheitelpunkt gespeichert Puffern oder in einer Reihe von Client - Speicher.

Bobobobo
quelle
19
-1: Sie sind nicht wie Makros. Wenn dies der Fall wäre, würde das Binden eines neuen VAO die von einem vorherigen VAO aktivierten Vertex-Arrays nicht deaktivieren, es sei denn, das neue VAO hat aufgezeichnet, dass Sie diese Arrays explizit deaktiviert haben. VAOs halten wie alle OpenGL-Objekte den Status und keine Befehle. Befehle ändern einfach den Status, aber für Objekte wird der Standardstatus festgelegt. Aus diesem Grund werden durch das Binden eines neu erstellten VAO immer alle Attribute deaktiviert.
Nicol Bolas
6

Ich denke immer an VAO als ein Array von Datenpuffern, die von OpenGL verwendet werden. Mit modernem OpenGL erstellen Sie VAO- und Vertex-Pufferobjekte.

Geben Sie hier die Bildbeschreibung ein

//vaoB is a buffer
glGenVertexArrays(1, vaoB); //creates one VAO
glBindVertexArray(vao.get(0));
glGenBuffers(vbo.length, vbo, 0); //vbo is a buffer
glBindVertexArray(vao.get(1));
glGenBuffers(vbo1.length, vbo1, 0); //vbo1 is a buffer
glBindVertexArray(vao.get(2));
glGenBuffers(vbo2.length, vbo2, 0); //vbo2 is a buffer

Der nächste Schritt besteht darin, Daten an einen Puffer zu binden:

glBindBuffer(GL_ARRAY_BUFFER, vbo[0]);
glBufferData(GL_ARRAY_BUFFER,vertBuf.limit()*4, vertBuf, GL_STATIC_DRAW); //vertf buf is a floatbuffer of vertices

An diesem Punkt sieht OpenGL:

Geben Sie hier die Bildbeschreibung ein

Jetzt können wir glGertexAttribPointer verwenden, um OpenGL mitzuteilen, was die Daten im Puffer darstellen:

glBindBuffer(GL_ARRAY_BUFFER, 0); //bind VBO at 0
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0); //each vertex has 3 components of size GL_FLOAT with 0 stride (space) between them and the first component starts at 0 (start of data)

Geben Sie hier die Bildbeschreibung ein

OpenGL hat jetzt die Daten im Puffer und weiß, wie die Daten in Eckpunkten organisiert sind. Der gleiche Prozess kann auf Texturkoordinaten usw. angewendet werden, aber für Texturkoordinaten gibt es zwei Werte.

glBindBuffer(GL_ARRAY_BUFFER, vbo[1]);
glBufferData(GL_ARRAY_BUFFER,coordBuf.limit()*4, coordBuf, GL_STATIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, false, 0, 0);

Als nächstes können Sie Texturen binden und Arrays zeichnen. Sie möchten einen Vert- und Frag-Shader erstellen, kompilieren und an ein Programm anhängen (hier nicht enthalten).

glActiveTexture(textureID); //bind our texture
glBindTexture(GL_TEXTURE_2D, textureID);
glDrawArrays(GL_TRIANGLES,0,6); //in this case 6 indices are used for two triangles forming a square
Vasmos
quelle
5

VAO ist ein Objekt, das die Vertex-Abrufphase der OpenGL-Pipeline darstellt und zur Bereitstellung von Eingaben für den Vertex-Shader verwendet wird.

Sie können ein Vertex-Array-Objekt wie folgt erstellen

GLuint vao;
glCreateVertexArrays(1, &vao);
glBindVertexArray(vao);

Lassen Sie uns zuerst ein einfaches Beispiel machen. Betrachten Sie einen solchen Eingabeparameter in einem Shader-Code

layout (location = 0) in vec4 offset; // input vertex attribute

Um dieses Attribut auszufüllen, können wir verwenden

glVertexAttrib4fv(0, attrib); // updates the value of input attribute 0

Obwohl das Vertex-Array-Objekt diese statischen Attributwerte für Sie speichert, kann es viel mehr.

Nach dem Erstellen des Vertex-Array-Objekts können wir beginnen, seinen Status auszufüllen. Wir werden OpenGL bitten, es automatisch mit den Daten zu füllen, die in einem von uns bereitgestellten Pufferobjekt gespeichert sind. Jedes Vertex-Attribut kann Daten aus einem Puffer abrufen, der an eine von mehreren Vertex-Pufferbindungen gebunden ist. Zu diesem Zweck verwenden wir glVertexArrayAttribBinding(GLuint vao, GLuint attribindex, GLuint bindingindex). Wir verwenden die glVertexArrayVertexBuffer()Funktion auch, um einen Puffer an eine der Vertex-Pufferbindungen zu binden. Wir verwenden die glVertexArrayAttribFormat()Funktion, um das Layout und Format der Daten zu beschreiben, und schließlich ermöglichen wir das automatische Ausfüllen des Attributs durch Aufrufen glEnableVertexAttribArray().

Wenn ein Vertex-Attribut aktiviert ist, gibt OpenGL dem Vertex-Shader Daten basierend auf den Format- und Standortinformationen, die Sie mit glVertexArrayVertexBuffer()und angegeben haben, zu glVertexArrayAttribFormat(). Wenn das Attribut deaktiviert ist, erhält der Vertex-Shader die statischen Informationen, die Sie bei einem Aufruf angeben glVertexAttrib*().

// First, bind a vertex buffer to the VAO
glVertexArrayVertexBuffer(vao, 0, buffer, 0, sizeof(vmath::vec4));

// Now, describe the data to OpenGL, tell it where it is, and turn on automatic
// vertex fetching for the specified attribute
glVertexArrayAttribFormat(vao, 0, 4, GL_FLOAT, GL_FALSE, 0);

glEnableVertexArrayAttrib(vao, 0);

Und Code in einem Shader

layout (location = 0) in vec4 position;

Immerhin müssen Sie anrufen glDeleteVertexArrays(1, &vao).


Sie können OpenGL SuperBible lesen , um es besser zu verstehen.

Yola
quelle
3
Es ist gut zu sehen, dass Leute für die Verwendung von OpenGL im DSA-Stil werben.
Nicol Bolas