2013-06-21 58 views
7

在構建圖形引擎時,我正在通過arcsynthesis上的優秀教程進行工作,並且發現我不像我認爲的那樣瞭解VAO我有。頂點數組對象 - 關於確切地保存關於當前綁定頂點緩衝區的狀態信息的混淆

從教程Chapter 5. Objects In Depth

緩衝區綁定和屬性協會

您可能注意到,glBindBuffer(GL_ARRAY_BUFFER)不在名單上,即使它是該屬性設置爲渲染的一部分。與GL_ARRAY_BUFFER的綁定不是VAO的一部分,因爲當您調用glBindBuffer(GL_ARRAY_BUFFER)時,緩衝對象與頂點屬性之間的關聯不會發生。當您調用glVertexAttribPointer時會發生此關聯。

當您調用glVertexAttribPointer時,OpenGL會將此調用綁定到GL_ARRAY_BUFFER時的任何緩衝區與其給定的頂點屬性關聯。將GL_ARRAY_BUFFER綁定看作glVertexAttribPointer讀取的全局指針。因此,在完成glVertexAttribPointer調用之後,您可以自由地將任何您想要的或完全不需要的內容綁定到GL_ARRAY_BUFFER;它不會影響最終渲染。所以VAO確實存儲哪些緩衝對象與哪些屬性相關聯;但它們不存儲GL_ARRAY_BUFFER綁定本身。

我最初錯過了最後一行「...但他們不存儲GL_ARRAY_BUFFER綁定本身」。在我注意到這一行之前,我認爲一旦調用了glVertexAttribPointer,就會保存當前綁定的緩衝區。由於缺乏這方面的知識,我建立了一個網格類,並能夠正確渲染大量網格物體。

該代碼的一部分列在下面。請注意,我不在draw函數中調用glBindBuffer。

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

現在,我即將開始照明,我想要一些調試繪圖,以便我可以驗證我所有的法線是否正確。目前我只是將所有行渲染爲一個向量中的幀。由於這些數據可能會改變每一幀,因此我在使用GL_DYNAMIC_DRAW並在渲染之前指定了數據。

最初,當我這樣做,我會得到垃圾線,只是指向無窮大。有問題的代碼如下:

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

有點狩獵後,也發現我在上面錯過了細節,我發現,如果我在繪製函數glBufferData之前調用glBindBuffer,一切順利的罰款。

我很困惑,爲什麼我的網格渲染工作在這個第一位。如果我更改緩衝區中的數據,是否只需要再次調用glBindBuffer?或者,如果你不綁定緩衝區,行爲是不確定的,我只是不幸運而已。

請注意,我的目標是OpenGL版本3.0。

回答

10

我只需要再次調用glBindBuffer,如果我更改緩衝區中的數據 ?

是的,VAO對象記住哪些緩衝區被束縛在每次叫glVertexAttribPointer,而這VAO被捆綁的時間,所以你通常不需要再次調用glBindBuffer。但是,如果要更改緩衝區中的數據,OpenGL需要知道您正在更改哪個緩衝區,因此在致電glBufferData之前需要致電glBindBuffer。在這一點上,哪個VAO目標受到約束並不重要。

+2

好的,這樣做更有意義。我有一個小細節,我仍然有點模糊。比方說,我用VAO 1調用glBindVertexArray,它記得調用glVertexAttribPointer時VBO 1被綁定。然後我調用glBindBuffer與VBO 2,然後調用glDrawArrays。應該使用哪個緩衝區,VBO 1或VBO 2?我不相信這是通常會做的事情,我只是想確保我明白髮生了什麼。 –

+2

將使用VBO 1。請注意,無論您是否使用VAO,情況都是如此。你也可能綁定了幾個VBO,同時你有VAO綁定(對於每個屬性可能是不同的)。一旦你調用了glVertexAttribPointer,當時的緩衝區就會被使用。 – GuyRT

+1

太棒了,知道這很好!謝謝你的澄清! –

相關問題