Aus einer einfachen Perspektive können Sie sich ein Array mit zwei Teilen vorstellen:
Informationen zu Größe, Form und Typ des Arrays (z. B. 32-Bit-Gleitkommazahlen mit Vektorreihen mit jeweils vier Elementen).
Die Array-Daten, die kaum mehr als ein großer Byte-Blob sind.
Obwohl das Low-Level-Konzept größtenteils gleich geblieben ist, hat sich die Art und Weise, wie Sie Arrays angeben, im Laufe der Jahre mehrmals geändert.
OpenGL 3.0 / ARB_vertex_array_object
So sollten Sie heute wahrscheinlich vorgehen. Es ist sehr selten, dass Leute gefunden werden, die OpenGL 3.x nicht ausführen können und dennoch Geld für Ihre Software haben.
Ein Pufferobjekt in OpenGL ist ein großer Bitklumpen. Stellen Sie sich den "aktiven" Puffer nur als globale Variable vor, und es gibt eine Reihe von Funktionen, die den aktiven Puffer anstelle eines Parameters verwenden. Diese globalen Statusvariablen sind die hässliche Seite von OpenGL (vor dem direkten Statuszugriff, der unten behandelt wird).
GLuint buffer;
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, sizeof(points), points, GL_STATIC_DRAW);
Jetzt verwendet Ihr typischer Vertex-Shader Scheitelpunkte als Eingabe, keinen großen Bit-Blob. Sie müssen also angeben, wie der Bit-Blob (der Puffer) in Scheitelpunkte dekodiert wird. Das ist die Aufgabe des Arrays. Ebenso gibt es ein "aktives" Array, das Sie sich nur als globale Variable vorstellen können:
GLuint array;
glGenVertexArrays(1, &array);
glBindVertexArray(array);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glVertexAttribPointer(attr, 4, GL_FLOAT, GL_FALSE, 0, 0);
glEnableVertexAttribArray(attr);
OpenGL 2.0 (der alte Weg)
In OpenGL 2.x gab es keine Vertex-Arrays und die Daten waren nur global. Sie haben noch zu nennen glVertexAttribPointer()
und glEnableVertexAttribArray()
, aber man musste sie anrufen , jedes Mal , dass Sie einen Puffer verwendet. In OpenGL 3.x haben Sie das Array nur einmal eingerichtet.
Zurück zu OpenGL 1.5, Sie könnten tatsächlich Puffer verwenden, aber Sie haben eine separate Funktion verwendet, um jede Art von Daten zu binden. Zum Beispiel glVertexPointer()
für Scheitelpunktdaten und glNormalPointer()
für normale Daten. Vor OpenGL 1.5 gab es keine Puffer, aber Sie konnten Zeiger in Ihren Anwendungsspeicher verwenden.
OpenGL 4.3 / ARB_vertex_attrib_binding
In 4.3 oder wenn Sie die Erweiterung ARB_vertex_attrib_binding haben, können Sie das Attributformat und die Attributdaten separat angeben. Dies ist hilfreich, da Sie auf einfache Weise ein Scheitelpunktarray zwischen verschiedenen Puffern wechseln können.
GLuint array;
glGenVertexArrays(1, &array);
glBindVertexArray(array);
glEnableVertexAttribArray(loc_attrib);
glEnableVertexAttribArray(normal_attrib);
glEnableVertexAttribArray(texcoord_attrib);
glVertexAttribFormat(loc_attrib, 3, GL_FLOAT, GL_FALSE, 0);
glVertexAttribFormat(normal_attrib, 3, GL_FLOAT, GL_FALSE, 12);
glVertexAttribFormat(texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
glVertexAttribBinding(loc_attrib, 0);
glVertexAttribBinding(normal_attrib, 0);
glVertexAttribBinding(texcoord_attrib, 0);
glBindVertexBuffer(0, buffer, 0, 32);
glBindVertexBuffer(0, buffer2, 0, 32);
OpenGL 4.5 / ARB_direct_state_access
In OpenGL 4.5 oder wenn Sie die Erweiterung ARB_direct_state_access haben, müssen Sie nicht mehr aufrufen glBindBuffer()
oder glBindVertexArray()
nur noch Dinge einrichten ... Sie geben die Arrays und Puffer direkt an. Sie müssen das Array nur am Ende binden, um es zu zeichnen.
GLuint array;
glCreateVertexArrays(1, &array);
glEnableVertexArrayAttrib(array, loc_attrib);
glEnableVertexArrayAttrib(array, normal_attrib);
glEnableVertexArrayAttrib(array, texcoord_attrib);
glVertexArrayAttribFormat(array, loc_attrib, 3, GL_FLOAT, GL_FALSE, 0);
glVertexArrayAttribFormat(array, normal_attrib, 3, GL_FLOAT, GL_FALSE, 12);
glVertexArrayAttribFormat(array, texcoord_attrib, 2, GL_FLOAT, GL_FALSE, 24);
glVertexArrayAttribBinding(array, loc_attrib, 0);
glVertexArrayAttribBinding(array, normal_attrib, 0);
glVertexArrayAttribBinding(array, texcoord_attrib, 0);
glVertexArrayVertexBuffer(array, 0, buffer, 0, 32);
glVertexArrayVertexBuffer(array, 0, buffer2, 0, 32);
glBindVertexArray(array);
glDrawArrays(...);
ARB_direct_state_access ist aus vielen Gründen nett. Sie können das Binden von Arrays und Puffern vergessen (außer beim Zeichnen), damit Sie nicht an versteckte globale Variablen denken müssen, die OpenGL für Sie verfolgt. Sie können zwischen „Erzeugen Sie einen Namen für ein Objekt“ und „Erstellen eines Objekts“ , weil über den Unterschied vergessen glCreateBuffer()
und glCreateArray()
beides zugleich.
Vulkan
Vulkan geht noch weiter und lässt Sie Code wie den Pseudocode schreiben, den ich oben geschrieben habe. Sie sehen also so etwas wie:
VkVertexInputAttributeDescription attrib[3];
attrib[0].location = 0;
attrib[0].binding = 0;
attrib[0].format = VK_FORMAT_R32G32B32_SFLOAT;
attrib[0].offset = 0;
GL_EXT_direct_state_access
, aber das schließt leider aus, dass Ihr Code auf Mesa-, Intel- oder Apple-Treibern ausgeführt wird: - \ Ich denke jedoch, dass es wichtig ist, darauf hinzuweisen, dass Vertex-Arrays seit GL 1.1 existieren. Das einzige, was sich in GL 2.0 geändert hat, war die Einführung generischer Vertex-Attribut-Slots.glCreateVertexArrays(1, &array)
over verwendenglGenVertexArrays(1, &array)
? Meines Erachtens wird das Vao erst erstellt, wenn Sie es zum ersten Mal mit bindenglGenVertexArrays
, sodass keiner Ihrer glEnableVertexArray * / glVertexArray * -Aufrufe funktionieren würde.Ihre Interpretation des Buches ist nicht ganz richtig. Vertex-Array-Objekte speichern keine Daten. Sie sind eine Klasse von Objekten, die als Container bezeichnet werden, wie z. B. Framebuffer-Objekte. Sie können ihnen andere Objekte anhängen / zuordnen, aber sie speichern niemals Daten selbst. Als solche sind sie keine kontext gemeinsam nutzbare Ressource.
Grundsätzlich kapseln Vertex-Array-Objekte den Vertex-Array-Status in OpenGL 3.0. Beginnend mit OpenGL 3.1 (anstelle von
GL_ARB_compatibility
) und OpenGL 3.2+ Core-Profilen muss jederzeit ein VAO ungleich Null gebunden sein, damit Befehle wieglVertexAttribPointer (...)
oderglDrawArrays (...)
funktionieren. Das gebundene VAO bildet den erforderlichen Kontext für diese Befehle und speichert den Status dauerhaft.In älteren Versionen von GL (und Kompatibilität) war der von VAOs gespeicherte Status Teil der globalen Statusmaschine.
Es ist auch erwähnenswert , dass die „aktuelle“ Bindung für
GL_ARRAY_BUFFER
ist nicht einer der Staaten , dass vaos Spur. Während diese Bindung von Befehlen wie verwendet wirdglVertexAttribPointer (...)
, speichern VAOs die Bindung nicht, sondern nur Zeiger (dieGL_ARB_vertex_attrib_binding
neben GL 4.3 eingeführte Erweiterung erschwert dies ein wenig, lassen Sie uns sie der Einfachheit halber ignorieren).VAOs erinnern sich jedoch daran, woran sie gebunden
GL_ELEMENT_ARRAY_BUFFER
sind, sodass indizierte Zeichenbefehle wieglDrawElements (...)
die erwartete Funktion funktionieren ( z. B. verwenden VAOs den zuletzt gebundenen Elementarray-Puffer wieder).quelle
glVertexAttribPointer
einen Zeiger, der relativ zum Speicher ist, der dem gehört,GL_ARRAY_BUFFER
an den gebunden ist, wenn die Funktion aufgerufen wird. Ehrlich gesagt ist es eine Art dummes Design - in einer API wie D3D würden Sie einfach die ID des Pufferobjekts an das übergebenVertexAttribPointer
und müssten nie etwas binden. In OpenGL gabglVertexPointer (...)
es jedoch mehr als 10 Jahre, bevor VBOs eingeführt wurden, und sie wollten so viel API wie möglich ohne Modifikation wiederverwenden. Sie haben diese Bindung für ein VBO-Erstgeschäft ungleich Null erstellt , um das Hinzufügen eines weiteren Parameters zu vermeiden.Die Beziehung wird beim Aufruf von glVertexAttribPointer erstellt .
GL_VERTEX_ARRAY_BINDING
undGL_ARRAY_BUFFER_BINDING
sind Konstanten, aber sie können auf den globalen Zustand der Bindung verweisen. Ich beziehe mich auf den Zustand, nicht auf die Konstante (orange) im Bild. Verwenden Sie glGet , um Informationen zu verschiedenen globalen Zuständen zu erhalten.VertexArray gruppiert Informationen (einschließlich Array-Puffer) über einen Scheitelpunkt oder viele parallele Scheitelpunkte.
Verwenden Sie
GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING
mit glGetVertexAttrib, um herauszufinden, welcher Attributarraypuffer festgelegt ist.glBindBuffer (GL_ARRAY_BUFFER legt den globalen Status fest
GL_ARRAY_BUFFER_BINDING
glBindVertexArray legt den globalen Status fest
GL_VERTEX_ARRAY_BINDING
quelle
OpenGL ist eine Stateful-Schnittstelle. Es ist schlecht, antiquiert und hässlich, aber das ist ein Vermächtnis für dich.
Ein Vertex-Array-Objekt ist eine Sammlung von Pufferbindungen, mit denen der Treiber die Daten für die Draw-Aufrufe abrufen kann. Die meisten Tutorials verwenden nur das eine und erklären niemals, wie mehrere VAOs verwendet werden.
Eine Pufferbindung weist opengl an, diesen Puffer für verwandte Methoden zu verwenden, insbesondere für die
glVertexAttribPointer
Methoden.quelle
Es gibt keine Beziehung zwischen VertexArray und VBO.
Ein Vertex-Array weist den Speicher im RAM zu und sendet einen Zeiger an die API. VBO weist den Speicher auf der Grafikkarte zu - der Systemspeicher hat keine Adresse dafür. Wenn Sie vom System aus auf die vbo-Daten zugreifen müssen, müssen Sie diese zuerst von vbo auf das System kopieren.
In neueren Versionen von OpenGL werden Vertex-Arrays vollständig entfernt (in 3.0 veraltet, in 3.1 entfernt).
quelle
glVertexAttrib{I|L}Pointer (...)
Ersatz für Dinge wieglVertexPointer (...)
im modernen GL).