On all the tutorials I can find about VAO's (Vertex Array Objects), they show on how to use them by configuring vertex attributes and binding a VBO (Vertex Buffer Object). But I want to create a VAO that will be configured for a set of VBO's in combination with a fixed shader, where each buffer uses the same data pattern (vertex, uv, color, etc). So, I want to create one VAO for multiple VBO's that will be drawn using one shader.
I couldn't find any demo on this, so I decided to just give it a try. But it doesn't work and crashes on the glDrawArray
call. It looks like the VBO isn't bound. Here is the code I'm using:
Rendering:
/* Prepare vertex attributes */
glBindVertexArrayOES(vao);
/* Upload the buffer to the GPU */
glBindBuffer(GL_ARRAY_BUFFER, pool->next());
glBufferSubData(GL_ARRAY_BUFFER, 0, parts * buffer.stride() * 6, buffer.getBuffer());
/* Draw the triangles */
glDrawArrays(GL_TRIANGLES, 0, parts * 6);
glBindVertexArrayOES(0);
VAO Creation:
glBindVertexArrayOES(vao);
glEnableVertexAttribArray(ls.position);
glVertexAttribPointer(ls.position, 2, GL_FLOAT, GL_FALSE, buffer.stride(), 0);
glEnableVertexAttribArray(ls.color);
glVertexAttribPointer(ls.color, 3, GL_FLOAT, GL_FALSE, buffer.stride(), GL_BUFFER_OFFSET(buffer.dataTypeSize * 2));
glBindVertexArrayOES(0);
Where ls
is a simple struct
that holds the attribute locations.
In the Rendering part, swapping the glBindBuffer
and the glBindVertexArrayOES
around didn't work either.
So, the question is: Is it even possible to do so, or will I have to create for each buffer a VAO? And if I have to create a VAO for each VBO, is it possible to update the VBO's data using glBufferSubData
in combination with a VAO?
Answer
VAOs do not contain "glBindBuffer" state, with the exception of GL_ELEMENT_ARRAY_BUFFER
's binding state. What you're not understanding is that glBindBuffer(GL_ARRAY_BUFFER)
doesn't do anything. Well, it doesn't do anything as far as rendering is concerned. Try it; right before calling glDraw*, call glBindBuffer(GL_ARRAY_BUFFER, 0)
; your rendering will work just fine.
The way glVertexAttribPointer
works is that it looks at what is bound to GL_ARRAY_BUFFER at the time glVertexAttribPointer
is called. Not at render time. Not later. Right at that exact moment. It takes whatever buffer object was there and stores it in another piece of OpenGL state, which is encapsulated within the VAO.
In general, you have two options, one of them that's new and probably shouldn't be used at this point in time.
Your first option is to put all objects that use the same vertex format (ie: everything except the buffer object and offset) in the same buffer object. Basically, build a giant array that contains all the vertices for all object that use the same format.
When it comes time to render, you can render a portion of the vertices. glDrawArrays
takes a range of elements to render, and you can adjust your indices in glDrawElements
to do the same. Alternatively, you can use glDrawElementsBaseVertex
to bias the vertices, so that an offset is added to each index. This offset is the number of vertices before that vertex in the big array.
The other alternative is to use the relatively new format attribute separation system added in GL 4.3. It would allow you to change buffers without resetting the format. Thus you would bind a single VAO, then just substitute in different buffers as needed with glBindVertexBuffer
. This is also available in ES 3.1.
No comments:
Post a Comment