Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing different vertex attributes in different VBO's

Tags:

c++

opengl

vbo

Is it possible to store different vertex attributes in different vertex buffers?

All the examples I've seen so far do something like this

float data[] = 
{
//position
   v1x, v1y, v1z,
   v2x, v2y, v2z,
   ...
   vnx, vny, vnz,

//color
   c1r, c1g, c1b,
   c2r, c2g, c2b,
   ...
   cnr, cng, cnb,   
};
GLuint buffname;
glGenBuffers(1, &buffname);
glBindBuffer(GL_ARRAY_BUFFER, buffname);
glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);

And the drawing is done something like this:

glBindBuffer(GL_ARRAY_BUFFER, buffname);
glEnableVertexAttrib(position_location);
glEnableVertexAttrib(color_location);
glVertexAttribPointer(position_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(color_location, 3, GL_FLOAT, GL_FALSE, 0, (void*)(3*n));

glDrawArrays(GL_TRIANGLES, 0, n/3);

glDisableVertexAttrib(position_location);
glDisableVertexAttrib(color_location);
glBindBuffer(GL_ARRAY_BUFFER, 0);

Isn't it possible to store position data and color data in different VBOs? The problem is I don't understand how this would work out because you can't bind two buffers at once, can you?

If there is a simple but inefficient solution, I would prefer it over a more complicated but efficient solution because I am in primary learning state and I don't want to complicate things too much.

Also, if what I'm asking is possible, is it a good idea or not?

To clarify: I do understand how I could store different attributes in different VBO's. I don't understand how I would later draw them.

like image 334
Armen Tsirunyan Avatar asked Aug 28 '11 20:08

Armen Tsirunyan


1 Answers

The association between attribute location X and the buffer object that provides that attribute is made with the glVertexAttribPointer command. The way it works is simple, but unintuitive.

At the time glVertexAttribPointer is called (that's the part a lot of people don't get), whatever buffer object is currently bound to GL_ARRAY_BUFFER becomes associated with the attribute X, where X is the first parameter of glVertexAttribPointer.

So if you want to have an attribute that comes from one buffer and an attribute that comes from another, you do this:

glEnableVertexAttrib(position_location);
glEnableVertexAttrib(color_location);
glBindBuffer(GL_ARRAY_BUFFER, buffPosition);
glVertexAttribPointer(position_location, 3, GL_FLOAT, GL_FALSE, 0, 0);
glBindBuffer(GL_ARRAY_BUFFER, buffColor);
glVertexAttribPointer(color_location, 3, GL_FLOAT, GL_FALSE, 0, 0);

As for whether you should split attributes into different buffers... I would say that you should only do it if you have a demonstrable need.

For example, let's say you're doing a dynamic height-map, perhaps for some kind of water effect. The Z position of each element changes, but this also means that the normals change. However, the XY positions and the texture coordinates do not change.

Efficient streaming often requires either double-buffering buffer objects or invalidating them (reallocating them with a glBufferData(NULL) or glMapBufferRange(GL_INVALIDATE_BIT)). Either way only works if the streamed data is in another buffer object from the non-streamed data.

Another example of a demonstrable need is if memory is a concern and several objects share certain attribute lists. Perhaps objects have different position and normal arrays but the same color and texture coordinate arrays. Or something like that.

But otherwise, it's best to just put everything for an object into one buffer. Even if you don't interleave the arrays.

like image 72
Nicol Bolas Avatar answered Nov 16 '22 01:11

Nicol Bolas