在構建圖形引擎時,我正在通過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。
好的,這樣做更有意義。我有一個小細節,我仍然有點模糊。比方說,我用VAO 1調用glBindVertexArray,它記得調用glVertexAttribPointer時VBO 1被綁定。然後我調用glBindBuffer與VBO 2,然後調用glDrawArrays。應該使用哪個緩衝區,VBO 1或VBO 2?我不相信這是通常會做的事情,我只是想確保我明白髮生了什麼。 –
將使用VBO 1。請注意,無論您是否使用VAO,情況都是如此。你也可能綁定了幾個VBO,同時你有VAO綁定(對於每個屬性可能是不同的)。一旦你調用了glVertexAttribPointer,當時的緩衝區就會被使用。 – GuyRT
太棒了,知道這很好!謝謝你的澄清! –