Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

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?

share|improve this question

2 Answers 2

up vote 7 down vote accepted

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 brand new format attribute separation system added in GL 4.3. NVIDIA's 4.3 drivers are still only beta, and AMD doesn't even have beta support for this, so I wouldn't suggest it. But 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.

share|improve this answer
1  
The NV GL4.3 drivers are now full release. –  Darth Satan Jan 2 '13 at 11:38
    
Thank you very much for explaining the way glVertexAttribPointer works. That was enlightening and explains why and how it works. –  Martijn Courteaux Jan 2 '13 at 15:14

The VAO stores the glVertexAttribPointer state. Changing the VAO does not affect the current glBindBuffer, nor does changing the glBindBuffer affect the VAO. Only the glVertexAttribPointer call affects the VAO, by recording the buffer in use at the call.

So the answer to your question is no.

One option if you want to reduce the number of objects is to put all your mesh data into one large VBO and specify where the mesh data lives in the VBO in the glDrawArrays call using the 'first' and 'count' arguments.

share|improve this answer
    
All the articles on the internet on VAO's show that binding a VAO automatically binds the VBO. So, I think a VAO is a configuration that holds both glVertexAttribPointer states and the glBindBuffer state. And yes, binding a VBO when a VAO is bound changes the VAO. I'm telling this because I tested this and it effectively does. From where does this information come from? –  Martijn Courteaux Jan 1 '13 at 23:56
1  
@MartijnCourteaux: "All the articles on the internet on VAO's show that binding a VAO automatically binds the VBO." No, they don't. The OpenGL Wiki on vertex specification does not. Indeed, show me a single article on the internet that says that any glBindBuffer state except GL_ELEMENT_ARRAY_BUFFER is changed by binding a VAO. –  Nicol Bolas Jan 2 '13 at 4:27
    
The other answer explained good how the glVertexAttribPointer method works. It uses the VBO bound at that time. You are right! Thanks, I understand right now. –  Martijn Courteaux Jan 2 '13 at 15:11

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.