2013-06-21 8 views
7

Ich arbeite durch die exzellenten Tutorials unter arcsynthesis beim Aufbau einer Grafik-Engine und habe entdeckt, dass ich VAOs nicht so sehr verstehe, wie ich dachte Ich hatte.Vertex Array Objects - Verwirrung in Bezug auf genau welche Statusinformationen über den aktuell gebundenen Vertexpuffer gespeichert werden

aus dem Tutorial Chapter 5. Objects In Depth

Buffer Verband Bindung und Attribut

Sie werden feststellen, dass glBindBuffer (GL_ARRAY_BUFFER) ist nicht auf dieser Liste, obwohl es für das Rendering Teil des Attributs Setup ist. Die Bindung an GL_ARRAY_BUFFER ist nicht Teil eines VAO, da beim Aufruf von glBindBuffer (GL_ARRAY_BUFFER) die Zuordnung zwischen einem Pufferobjekt und einem Vertex-Attribut nicht erfolgt. Diese Verknüpfung erfolgt beim Aufruf von glVertexAttribPointer.

Wenn Sie glVertexAttribPointer aufrufen, übernimmt OpenGL den Puffer, der zum Zeitpunkt des Aufrufs an GL_ARRAY_BUFFER gebunden ist, und verknüpft ihn mit dem angegebenen Vertex-Attribut. Stellen Sie sich die GL_ARRAY_BUFFER-Bindung als globalen Zeiger vor, den glVertexAttribPointer liest. Es steht Ihnen also frei, GL_ARRAY_BUFFER zu binden, nachdem Sie einen glVertexAttribPointer-Aufruf durchgeführt haben. Es wird nichts in der endgültigen Wiedergabe beeinflussen. VAOs speichern also, welche Pufferobjekte welchen Attributen zugeordnet sind. aber sie speichern die GL_ARRAY_BUFFER-Bindung nicht selbst.

Ich verpasste zunächst die letzte Zeile "... aber sie speichern nicht die Bindung GL_ARRAY_BUFFER selbst". Bevor ich diese Zeile bemerkte, dachte ich, dass der aktuell gebundene Puffer gespeichert wurde, sobald glVertexAttribPointer aufgerufen wurde. Als ich dieses Wissen vermisste, baute ich eine Mesh-Klasse und war in der Lage, eine Szene mit einer Anzahl von Meshes richtig zu rendern.

Ein Teil dieses Codes ist unten aufgeführt. Beachten Sie, dass ich glBindBuffer nicht in der Zeichenfunktion aufrufen.

// MESH RENDERING 

/* ...   */ 
/* SETUP FUNCTION */ 
/* ...   */ 

// Setup vertex array object 
glGenVertexArrays(1, &_vertex_array_object_id); 
glBindVertexArray(_vertex_array_object_id); 

// Setup vertex buffers 
glGenBuffers(1, &_vertex_buffer_object_id); 
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id); 
glBufferData(GL_ARRAY_BUFFER, _vertices.size() * sizeof(vertex), &_vertices[0], GL_STATIC_DRAW); 

// Setup vertex attributes 
glEnableVertexAttribArray(e_aid_position); 
glEnableVertexAttribArray(e_aid_normal); 
glEnableVertexAttribArray(e_aid_color); 
glEnableVertexAttribArray(e_aid_tex); 

glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, pos)); 
glVertexAttribPointer(e_aid_normal, 3, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, norm)); 
glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, col)); 
glVertexAttribPointer(e_aid_tex,  2, GL_FLOAT, GL_FALSE, sizeof(vertex), (GLvoid*)offsetof(vertex, tex)); 

/* ...   */ 
/* DRAW FUNCTION */ 
/* ...   */ 

glBindVertexArray(_vertex_array_object_id); 
glDrawArrays(GL_TRIANGLES, 0, _vertices.size()); 

Jetzt, wo ich bin über die Beleuchtung starten ich einige Debug-Zeichnung bis bekommen wollte, so konnte ich alle meine Normalen korrekt sind überprüfen. Momentan speichere ich einfach alle Zeilen, die für ein Bild in einem Vektor gerendert werden sollen. Da diese Daten wahrscheinlich jeden Rahmen ändern werden, verwende ich GL_DYNAMIC_DRAW und spezifiziere die Daten, bevor ich sie rendere.

Wenn ich das zuerst gemacht habe, würde ich Mülllinien bekommen, die einfach ins Unendliche zeigen würden. Die problematischen Code ist unten:

// DEBUG DRAW LINE RENDERING 

/* ...   */ 
/* SETUP FUNCTION */ 
/* ...   */ 

// Setup vertex array object 
glGenVertexArrays(1, &_vertex_array_object_id); 
glBindVertexArray(_vertex_array_object_id); 

// Setup vertex buffers 
glGenBuffers(1, &_vertex_buffer_object_id); 
glBindBuffer(GL_ARRAY_BUFFER, _vertex_buffer_object_id); 
    // Note: no buffer data supplied here!!! 

// Setup vertex attributes 
glEnableVertexAttribArray(e_aid_position); 
glEnableVertexAttribArray(e_aid_color); 

glVertexAttribPointer(e_aid_position, 3, GL_FLOAT, GL_FALSE, sizeof(line_vertex), (GLvoid*)offsetof(line_vertex, pos)); 
glVertexAttribPointer(e_aid_color, 4, GL_FLOAT, GL_FALSE, sizeof(line_vertex), (GLvoid*)offsetof(line_vertex, col)); 

/* ...   */ 
/* DRAW FUNCTION */ 
/* ...   */ 

glBindVertexArray(_vertex_array_object_id); 
    // Specifying buffer data here instead!!! 
glBufferData(GL_ARRAY_BUFFER, _line_vertices.size() * sizeof(line_vertex), &_line_vertices[0], GL_DYNAMIC_DRAW); 
glDrawArrays(GL_LINES, 0, _line_vertices.size()); 

Nach ein wenig Jagd, sowie der Suche nach dem Detail, das ich oben verpasst haben, fand ich, dass, wenn ich glBindBuffer vor glBufferData in der Auslosung Funktion aufrufen, alles in Ordnung ausarbeitet.

Ich bin verwirrt, warum meine Mesh-Rendering in erster Linie funktionierte. Muss ich glBindBuffer nur noch einmal aufrufen, wenn ich die Daten im Puffer ändere? Oder ist Verhalten nicht definiert, wenn du den Puffer nicht bindest und ich hatte nur Pech und hatte es funktioniert?

Beachten Sie, dass ich auf OpenGL-Version 3.0 ausgerichtet bin.

Antwort

10

Muss ich nur glBindBuffer wieder anrufen, wenn ich die Daten im Puffer ändern?

Ja, das VAO Objekt merkt sich, welche Puffer jedes Mal, wenn glVertexAttribPointer während genannt gebunden waren, dass VAO gebunden war, so dass man in der Regel nicht glBindBuffer müssen wieder anrufen. Wenn Sie jedoch die Daten im Puffer ändern möchten, muss OpenGL wissen, welchen Puffer Sie ändern. Daher müssen Sie glBindBuffer aufrufen, bevor Sie glBufferData aufrufen. Es ist unerheblich, welches VAO-Objekt an diesem Punkt gebunden ist.

+2

Ok, das macht mehr Sinn. Ich habe ein kleines Detail, dass ich noch ein wenig verschwommen bin. Nehmen wir an, ich rufe glBindVertexArray mit VAO 1 auf, das sich erinnert, dass VBO 1 gebunden war, als glVertexAttribPointer aufgerufen wurde. Dann rufe ich glBindBuffer mit VBO 2 auf, gefolgt von glDrawArrays. Welcher Puffer sollte verwendet werden, VBO 1 oder VBO 2? Ich glaube nicht, dass dies etwas ist, was man normalerweise tun würde, ich möchte nur sicherstellen, dass ich verstehe, was vor sich geht. –

+2

VBO 1 wird verwendet. Beachten Sie, dass dies gilt, unabhängig davon, ob Sie VAOs verwenden oder nicht. Sie könnten auch mehrere VBOs gebunden haben, während Sie die VAO-Grenze hatten (vielleicht eine andere für jedes Attribut). Sobald Sie glVertexAttribPointer aufgerufen haben, wird der zu diesem Zeitpunkt gebundene Puffer verwendet. – GuyRT

+1

Super, das ist gut zu wissen! Vielen Dank für die Klärung! –