firstly, outside the VAO, it only “remembers” the last vertex attribute bindings (and the VBO binding for the index buffer ( GL_ELEMENT_ARRAY_BUFFER_BINDING
), if one exists). Therefore, it does not remember the offsets in glDrawElements()
, you need to call later when using VAO. This laso does not stop you from using alternating vertex arrays. Let me explain:
int vbo[3]; glGenBuffers(3, vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); glBufferData(GL_ARRAY_BUFFER, data0, size0); glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); glBufferData(GL_ARRAY_BUFFER, data1, size1); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); glBufferData(GL_ELEMENT_ARRAY_BUFFER, data2, size2); // create some buffers and fill them with data int vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); // create a VAO { glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); // not saved in VAO glVertexAttribPointer(0, 3, GL_FLOAT, false, 3 * sizeof(float), NULL); // this is VAO saved state glEnableVertexAttribArray(0); // this is VAO saved state // sets up one vertex attrib array from vbo[0] (say positions) glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); // not saved in VAO glVertexAttribPointer(1, 3, GL_FLOAT, false, 5 * sizeof(float), NULL); // this is VAO saved state glVertexAttribPointer(2, 2, GL_FLOAT, false, 5 * sizeof(float), (const void*)(2 * sizeof(float))); // this is VAO saved state glEnableVertexAttribArray(1); // this is VAO saved state glEnableVertexAttribArray(2); // this is VAO saved state // sets up two more VAAs from vbo[1] (say normals interleaved with texcoords) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo[2]); // this is VAO saved state // uses the third buffer as the source for indices } // set up state that VAO "remembers" glBindVertexArray(0); // bind different vaos, etc ...
Later...
glBindVertexArray(vao); // bind our VAO (so we have VAAs 0, 1 and 2 as well as index buffer) glDrawElements(GL_TRIANGLE_STRIP, 57, GL_UNSIGNED_INT, NULL); glDrawElements(GL_TRIANGLE_STRIP, 23, GL_UNSIGNED_INT, (const void*)(57 * sizeof(unsigned int))); // draws two parts of the mesh as triangle strips
So you see ... you can draw alternating vertex arrays using glDrawElements
, using one VAO and one or more VBOs.
To answer the second part of your question, you can have different VAO and VBOs for different parts of the grid (so drawing separate parts is easy), or you can combine all into one VAO VBO pair (so you don't need to call glBind*()
) and use several glDraw*()
calls to draw individual parts of the grid (as you can see from the code above - imagine that the first glDrawElements()
draws a ship and the second draws a turret, you just update some matrix form between calls).
Since shaders can contain multiple modelview matrices in uniforms, you can also encode the grid identifier as another vertex attribute and let the vertex shader choose which matrix to use for transforming the vertex based on this attribute. This idea can also be expanded by using several matrices at one vertex with some weights assigned to each matrix. This is commonly used when animating organic objects such as a player’s character (see “skinning”).
As homogeneous buffer objects, the only advantage is that you can pack a lot of data into them and that they can be easily shared between shaders (just attach UBO to any shader that can use it). There is no real advantage in using them for you, unless you have objects with 1OOOs matrices.
In addition, I wrote the source code from memory. Let me know if there are any errors / problems ...