2013-01-10 8 views
19

Ich schreibe eine kleine Grafik-Engine mit OpenGL (über OpenTK mit C#).OpenGL, VAOs und mehrere Puffer

Um Vertex-Attribute zu definieren, habe ich eine VertexDeclaration-Klasse mit einem Array von VertexElement-Strukturen, die glEnableVertexAttribArray/glVertexAttribPointer-Aufrufe zugeordnet sind.

Um mehrere Vertex-Streams zu unterstützen, habe ich eine spezielle Struktur, die einen Vertex-Puffer, eine Vertex-Deklaration, einen Vertex-Offset und eine Instanzfrequenz enthält (wie die VertexBufferBinding-Struktur des XNA).

Wenn ein Zeichnungsaufruf aufgerufen wird, Iteriere ich über alle vertex Knotenströme und binden ihre Vertexpuffer, wenden Vertexdeklarationen an, deaktivieren nicht verwendete Vertexattribute und zeichnen die Grundelemente.

Ich möchte VAOs verwenden, um die glEnableVertexAttribArray-Aufrufe in sie zu cachen, und immer wenn ein Vertex-Stream angewendet wird, binden Sie den VAO und ändern Sie seine Array-Puffer-Bindung.

Ist das eine korrekte Verwendung von VAOs?

Antwort

34

Ist das eine korrekte Verwendung von VAOs?

No .

glVertexAttribPointeruses the buffer object that was bound to GL_ARRAY_BUFFERat the moment the function was called. So können Sie nicht tun:

glVertexAttribPointer(...); 
glBindBuffer(GL_ARRAY_BUFFER, bufferObject); 
glDrawArrays(...); 

Dies wird nicht Verwendung bufferObject; Es wird verwendet, was an GL_ARRAY_BUFFER gebunden war, wenn glVertexAttribPointer ursprünglich aufgerufen wurde.

VAOs erfassen diesen Status. Der VAO speichert also für jedes Vertex-Attribut, welches Pufferobjekt beim Aufruf an GL_ARRAY_BUFFER gebunden war. Dies ermöglicht Ihnen, solche Dinge zu tun:

glBindVertexArray(VAO); 
glBindBuffer(GL_ARRAY_BUFFER, buffer1); 
glVertexAttribPointer(0, ...); 
glVertexAttribPointer(1, ...); 
glBindBuffer(GL_ARRAY_BUFFER, buffer2); 
glVertexAttribPointer(2, ...); 

Attribute 0 und 1 wird von buffer1 kommen, und 2 von buffer2 kommen zuzuschreiben. VAO erfasst nun diesen ganzen Staat. Zu machen, können Sie dies nur tun:

glBindVertexArray(VAO); 
glDraw*(); 

Kurz gesagt, wenn Sie ändern möchten, in denen die Lagerung eines Attributs aus in OpenGL kommt, müssen Sie auch ändern es ist Format. Auch wenn es das gleiche Format hat, müssen Sie erneut glVertexAttribPointer aufrufen.

: Diese Diskussion nimmt Sie nicht mit dem neuen ARB_vertex_attrib_binding sind. Oder, wie es sonst bekannt ist, "Exactly how Direct3D does vertex attribute binding." Wenn Sie eine Implementierung verwenden, die diese Erweiterung bietet, können Sie effektiv das tun, worüber Sie sprechen, weil das Attributformat nicht mit dem Speicher des Pufferobjekts verknüpft ist. Auch die gequälte Logik von glVertexAttribPointer ist weg.

Im Allgemeinen lösen wir das in der OpenGL-Welt so, dass wir so viele Dinge wie möglich in dasselbe Pufferobjekt einfügen. Wenn dies nicht möglich ist, verwenden Sie für jedes Objekt nur einen VAO.

+0

Danke für diese großartige Antwort.Wo kommt dann der 'glBufferData'-Schritt zum Tragen? Müssen Sie die Daten nicht zuerst puffern, bevor Sie den 'glVertexAttribPointer' verwenden? Tut mir leid, ich bin sehr neu in OpenGL –