2013-06-21 10 views
7

Sto lavorando attraverso le eccellenti esercitazioni a arcsynthesis mentre costruisco un motore grafico e ho scoperto che non capisco i VAO tanto quanto pensavo Avevo.Oggetti Vertex Array - Confusione riguardo esattamente quali informazioni di stato vengono salvate sul buffer di vertici attualmente associato

dal tutorial Chapter 5. Objects In Depth

tampone di legame ed attributi Associazione

Si può notare che glBindBuffer (GL_ARRAY_BUFFER) non è in quella lista, anche se è parte della configurazione di attributo per il rendering. L'associazione a GL_ARRAY_BUFFER non fa parte di un VAO poiché l'associazione tra un oggetto buffer e un attributo vertice non si verifica quando chiami glBindBuffer (GL_ARRAY_BUFFER). Questa associazione si verifica quando chiami glVertexAttribPointer.

Quando si chiama glVertexAttribPointer, OpenGL accetta qualsiasi buffer al momento della chiamata a GL_ARRAY_BUFFER e lo associa all'attributo vertice specificato. Pensa al legame GL_ARRAY_BUFFER come a un puntatore globale letto da glVertexAttribPointer. Quindi sei libero di legare tutto ciò che vuoi o di niente a GL_ARRAY_BUFFER dopo aver fatto una chiamata glVertexAttribPointer; non influenzerà nulla nel rendering finale. Quindi i VAO memorizzano quali oggetti buffer sono associati a quali attributi; ma non memorizzano il GL_ARRAY_BUFFER vincolante stesso.

Inizialmente ho perso l'ultima riga "... ma non memorizzano il GL_ARRAY_BUFFER vincolante". Prima di notare questa riga ho pensato che il buffer attualmente associato fosse stato salvato una volta chiamato glVertexAttribPointer. Mancando questa conoscenza, ho creato una classe mesh e sono riuscito a ottenere una scena con un numero di mesh correttamente visualizzato.

Una parte di tale codice è elencata di seguito. Nota che non chiamo glBindBuffer nella funzione draw.

// 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()); 

ora che sono in procinto di iniziare l'illuminazione volevo ottenere alcuni di debug redazione così ho potuto verificare tutte le mie normali siano corrette. Attualmente conservo solo tutte le linee da renderizzare per un frame in un vettore. Dato che questi dati probabilmente cambieranno ogni fotogramma, sto usando GL_DYNAMIC_DRAW e specificherò i dati giusto prima di renderlo.

Inizialmente, quando lo facevo, ottenevo linee di immondizia che puntavano verso l'infinito. Il codice incriminato è qui sotto:

// 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()); 

Dopo un po 'di caccia, oltre a trovare dettaglio mi mancava in precedenza, ho scoperto che se chiamo glBindBuffer prima glBufferData nella funzione di pareggio, tutto funziona bene.

Sono confuso sul motivo per cui il mio rendering mesh ha funzionato in primo luogo dato questo. Devo chiamare nuovamente glBindBuffer solo se cambio i dati nel buffer? O il comportamento è indefinito se non si vincola il buffer e sono stato sfortunato e ha funzionato?

Nota che il mio obiettivo è OpenGL versione 3.0.

risposta

10

Ho solo bisogno di chiamare di nuovo glBindBuffer se cambio i dati nel buffer ?

Sì, L'oggetto VAO ricorda che tamponi erano legati ogni volta che si chiama glVertexAttribPointer mentre quella VAO era legato, quindi di solito non è necessario chiamare glBindBuffer di nuovo. Se si desidera modificare i dati nel buffer, tuttavia, OpenGL deve sapere quale buffer si sta modificando, quindi è necessario chiamare glBindBuffer prima di chiamare glBufferData. È irrilevante quale oggetto VAO è vincolato a questo punto.

+2

Ok, questo ha più senso. Ho un piccolo dettaglio su cui sono ancora un po 'confuso. Diciamo che chiamo glBindVertexArray con VAO 1 che ricorda che VBO 1 era legato quando veniva chiamato glVertexAttribPointer. Poi chiamo glBindBuffer con VBO 2, seguito da glDrawArrays. Quale buffer dovrebbe essere usato, VBO 1 o VBO 2? Non credo che questo sia qualcosa che normalmente si farebbe, voglio solo assicurarmi di capire cosa sta succedendo. –

+2

VBO 1 verrà utilizzato. Si noti che questo è vero indipendentemente dal fatto che si stiano utilizzando VAO. Inoltre potresti aver associato diversi VBO mentre avevi il vincolo VAO (forse uno diverso per ogni attributo). Una volta che hai chiamato glVertexAttribPointer, il buffer associato in quel momento è quello che verrà utilizzato. – GuyRT

+1

Fantastico, è bello saperlo! Grazie mille per il chiarimento! –

Problemi correlati