PDA

View Full Version : Vertex buffers



statu
02-02-2012, 09:53 AM
Hi,

how many vertex buffers can I use simultaneously? I have a scene with many objects and each object has his own vertex buffer.

OpenGL doesn't return any error but when I execute the program OpenGL draws only the last bufferVertex that I create.

Thanks for any help.

menzel
02-02-2012, 10:19 AM
You can fetch attributes from up to MAX_ATTRIB_LOCATIONS different VBOs at the same time (often 16) assuming you read one attribute per VBO. Those will be used for one rendercall.
But that might not be what you meant, so i guess you want to render a lot of VBOs in sequence:

activate VBO_0
draw model
activate VBO_1
draw model
...

there is no real limit to that (to be pedantic, you could get an out-of-memory or run out of names for the VBOs, but GLuint is 32bits...).

Maybe you bind your VBOs and _then_ try to render? In that case only the last one will be bound during the render calls.
Can you share some code so we can see how you try to render your scene?

statu
02-02-2012, 11:00 AM
Thanks for the answer. I'm binding each VBO before draw it like your example.

The code is this:
main.cpp


void display() {
glMatrixMode(GL_MODELVIEW);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
t->draw();
glutSwapBuffers();
}

T* t = new T();

int main() {
glutInit...

glutDisplayFunc(display);

}


T.cpp


T::T() {
for (unsigned int i = 0; i < 15; i++)
for (unsigned int j = 0; j < 15; j++)
items.push_back(new T2(i, j)); //items is an attribute of the class. His type is std::list<T2>
}

void T::draw() {
std::list<T2>::iterator it;

for (it = items.begin(); it < items.end(); it++)
it->draw();
}


T2.cpp


T2::T2(int i, int j) {
float *vertexBuffer = getMyVertexArray(i, j);
unsigned int *indexBuffer = getMyIndexArray(i, j);

glGenBuffer(1, &amp;vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, numVertex * 3 * sizeof(float), vertexBuffer, GL_STREAM_DRAW);
glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)((char*)NULL));
glEnableClientState(GL_VERTEX_ARRAY);

glGenBuffer(1, &amp;indexBufferID);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, numIndexElements * sizeof(unsigned int), indexBuffer, GL_STREAM_DRAW);
glIndexPointer(GL_INT, 0, (GLvoid*)((char*)NULL));
}

void T2::draw() {
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
glDrawElements(GL_TRIANGLE_STRIP, numIndexElements, GL_UNSIGNED_INT, (GLvoid*)((char*)NULL));
}


The trace of the program should be

CreateVertexBuffer1
CreateIndexBuffer1
CreateVertexBuffer2
CreateIndexBuffer2
CreateVertexBuffer3
CreateIndexBuffer3
CreateVertexBuffer4
CreateIndexBuffer4
...
Later, when I draw
BindVertexBuffer1
BindIndexBuffer1
drawElements
BindVertexBuffer2
BindIndexBuffer2
drawElements
BindVertexBuffer3
BindIndexBuffer3
drawElements
...

And OpenGL draws only the vertexBuffer4 (supposing it is the last vertex buffer created)

Thanks for any help

menzel
02-02-2012, 11:23 AM
Buffer creation looks ok, but the glDrawElements will draw numIndexElements vertices as a tri-strip from the set vertex pointers/index pointer. those were defined in your constructor and implicitly used the currently bound VBOs as additional parameters to define the source of the data.
So your constructors are overriding each other with the definition of what OpenGL should draw so each drawElements call will draw the same geometry. Binding the VBOs does not change what you draw. The glVertexPointer/glEnableClientState/glIndexPointer calls need to be called in your draw() method as well.

If you switch to GL3 you can use VAOs which encapsulate all information needed for OpenGL to draw from VBOs, so with VAOs you would only need 2 calls for drawing: binding the VAO and a drawElements call. But first I would suggest fixing your draw function to understand how drawing works with just the elements you have now.

Alfonse Reinheart
02-02-2012, 11:24 AM
glIndexPointer(GL_INT, 0, (GLvoid*)((char*)NULL));

Never call `glIndexPointer`. It absolutely does not do what you think it does. That's not your problem, but you shouldn't be calling it.

In any case, your problem is that you're not quite understanding how buffer objects work with vertex data.

This:



glGenBuffer(1, &amp;vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, numVertex * 3 * sizeof(float), vertexBuffer, GL_STREAM_DRAW);

is an example of how to create a buffer object (though unless you are actually streaming vertex data, which you aren't, you shouldn't be using GL_STREAM_DRAW. You should use GL_STATIC_DRAW). You create the buffer object, allocate a particular size, and copy some data into it. All well and good.

The problem is what you do next.



glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)((char*)NULL));
glEnableClientState(GL_VERTEX_ARRAY);


This is the correct code, but it shouldn't be here. This is not initialization-time code. This is code you use to draw with a particular buffer object.

See, because of legacy BS of the API, how you render with buffer objects is slightly convoluted. The buffer you bind to GL_ARRAY_BUFFER does not get used for rendering. To specify how to render data from a buffer object, you need two things: the buffer object itself, and the vertex format. The latter is provided by `glVertexPointer` for position data, coupled with `glEnableClientState(GL_VERTEX_ARRAY)`.

So, when it comes time to draw, you have to provide both the buffer object and its format. So the above code isn't initialization code; it is rendering code:



glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID);
glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)((char*)NULL));
glEnableClientState(GL_VERTEX_ARRAY);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID);
glDrawElements(GL_TRIANGLE_STRIP, numIndexElements, GL_UNSIGNED_INT, (GLvoid*)((char*)NULL));

statu
02-03-2012, 07:49 AM
It's that!! Thanks for the help!