VBO's

Started by
9 comments, last by SirOnion 18 years, 8 months ago
Hi, Could somebody help me with Vertex Buffer Objects? It's the first time I use them so... The first thing I should do is setup such a VBO. One of the problems is that I don't know where the indices start (you need to use offsets right?). If I'm right, there's first the vertices, then the normals, color, texcoords... and then? How large is the indices part, 16 bits, 32 bits?

glBufferSubDataARB( GL_ARRAY_BUFFER_ARB, VBO_indicesOffset, VBO_indicesSize, indicesList ); // What's the offset and size?
When that stuff is completed, I want to call my buffer. From what I've seen its almost the same as using a normal array, but now you bind to this VBO ID. What to use for the 'data' parameter? The offset like this:?

  glEnableClientState( GL_VERTEX_ARRAY );
  glVertexPointer( 3, GL_FLOAT, 0, VBO_vtxOffset );
If I want to use glDrawElements, is it nescesary to fill the 'count' parameter? I red that glDrawRangeElements was faster but what to use for the Astart and Aend parameters? 0, indicesCount-1 or something? BTW, I would really appriciate it if someone could point me a demo that uses indices! Greetings, Rick
Advertisement
This may be more information then you wanted, but here's what I've done to do my VBOs

When I first create an object/model:
void Objects::ReserveVBOs(void){	// Vertex    glGenBuffersARB(1, &VertexName);    glBindBufferARB(GL_ARRAY_BUFFER, VertexName);    glBufferDataARB(GL_ARRAY_BUFFER, VertexCurrentSize * 3 * sizeof(float), pVertex, GL_DYNAMIC_DRAW);    // Color    glGenBuffersARB(1, &ColorName);    glBindBufferARB(GL_ARRAY_BUFFER, ColorName);    glBufferDataARB(GL_ARRAY_BUFFER, VertexCurrentSize * 4 * sizeof(unsigned char), pColor, GL_DYNAMIC_DRAW);    // Normal    glGenBuffersARB(1, &NormalName);    glBindBufferARB(GL_ARRAY_BUFFER, NormalName);    glBufferDataARB(GL_ARRAY_BUFFER, VertexCurrentSize * 3 * sizeof(float), pNormal, GL_DYNAMIC_DRAW);    // Texture    glGenBuffersARB(1, &TexCoordName);    glBindBufferARB(GL_ARRAY_BUFFER, TexCoordName);    glBufferDataARB(GL_ARRAY_BUFFER, VertexCurrentSize * 2 * sizeof(float), pTexCoord, GL_DYNAMIC_DRAW);    // Points    glGenBuffersARB(1, &Points.VBOName);    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Points.VBOName);    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, Points.IndexCurrentSize * sizeof(unsigned int), Points.pIndex, GL_DYNAMIC_DRAW);    // Lines    glGenBuffersARB(1, &Lines.VBOName);    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Lines.VBOName);    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, Lines.IndexCurrentSize * sizeof(unsigned int), Lines.pIndex, GL_DYNAMIC_DRAW);    // Triangles    glGenBuffersARB(1, &Triangles.VBOName);    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Triangles.VBOName);    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, Triangles.IndexCurrentSize * sizeof(unsigned int), Triangles.pIndex, GL_DYNAMIC_DRAW);    // Quads    glGenBuffersARB(1, &Quads.VBOName);    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Quads.VBOName);    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, Quads.IndexCurrentSize * sizeof(unsigned int), Quads.pIndex, GL_DYNAMIC_DRAW);}


Whenever I update the data in my object/model, I do this to update my VBOs:
void Objects::UpdateVBOs(void){	// Vertex    glBindBufferARB(GL_ARRAY_BUFFER, VertexName);    glBufferDataARB(GL_ARRAY_BUFFER, VertexCurrentSize * 3 * sizeof(float), pVertex, GL_DYNAMIC_DRAW);    // Color    glBindBufferARB(GL_ARRAY_BUFFER, ColorName);    glBufferDataARB(GL_ARRAY_BUFFER, VertexCurrentSize * 4 * sizeof(unsigned char), pColor, GL_DYNAMIC_DRAW);    // Normal    glBindBufferARB(GL_ARRAY_BUFFER, NormalName);    glBufferDataARB(GL_ARRAY_BUFFER, VertexCurrentSize * 3 * sizeof(float), pNormal, GL_DYNAMIC_DRAW);    // Texture    glBindBufferARB(GL_ARRAY_BUFFER, TexCoordName);    glBufferDataARB(GL_ARRAY_BUFFER, VertexCurrentSize * 2 * sizeof(float), pTexCoord, GL_DYNAMIC_DRAW);    // Points    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Points.VBOName);    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, Points.IndexCurrentSize * sizeof(unsigned int), Points.pIndex, GL_DYNAMIC_DRAW);    // Lines    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Lines.VBOName);    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, Lines.IndexCurrentSize * sizeof(unsigned int), Lines.pIndex, GL_DYNAMIC_DRAW);    // Triangles    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Triangles.VBOName);    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, Triangles.IndexCurrentSize * sizeof(unsigned int), Triangles.pIndex, GL_DYNAMIC_DRAW);    // Quads    glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Quads.VBOName);    glBufferDataARB(GL_ELEMENT_ARRAY_BUFFER, Quads.IndexCurrentSize * sizeof(unsigned int), Quads.pIndex, GL_DYNAMIC_DRAW);}


And when I want to draw, I do this:
    // Bind the vertex data    glBindBufferARB(GL_ARRAY_BUFFER, VertexName);    glVertexPointer(3, GL_FLOAT, 0, 0);    // Bind the color data    glBindBufferARB(GL_ARRAY_BUFFER, ColorName);    glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);    // Bind the normal data    glBindBufferARB(GL_ARRAY_BUFFER, NormalName);    glNormalPointer(GL_FLOAT, 0, 0);    // Bind the texture data    glBindBufferARB(GL_ARRAY_BUFFER, TexCoordName);    glTexCoordPointer(2, GL_FLOAT, 0, 0);	// Draw the Points    if (Points.IndexCurrentSize > 0)    {		glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Points.VBOName);		glDrawRangeElements(GL_POINTS, 		                    0, 		                    Points.IndexCurrentSize, 		                    Points.IndexCurrentSize, 		                    GL_UNSIGNED_INT, 		                    NULL);    }	// Draw the Lines    if (Lines.IndexCurrentSize > 0)    {        glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Lines.VBOName);		glDrawRangeElements(GL_LINES, 		                    0, 		                    Lines.IndexCurrentSize, 		                    Lines.IndexCurrentSize, 		                    GL_UNSIGNED_INT, 		                    NULL);    }	// Draw the Triangles    if (Triangles.IndexCurrentSize > 0)    {        glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Triangles.VBOName);		glDrawRangeElements(GL_TRIANGLES, 		                    0, 		                    Triangles.IndexCurrentSize, 		                    Triangles.IndexCurrentSize, 		                    GL_UNSIGNED_INT, 		                    NULL);    }	// Draw the Quads    if (Quads.IndexCurrentSize > 0)    {        glBindBufferARB(GL_ELEMENT_ARRAY_BUFFER, Quads.VBOName);        glDrawRangeElements(GL_QUADS,                             0,                             Quads.IndexCurrentSize,                             Quads.IndexCurrentSize,                             GL_UNSIGNED_INT,                             NULL);    }


You can modify the call to glDrawRangeElements() to draw only portions of the VBO by changing the 4th parameter to the number of verticies you want to draw (in the example above, you can see all the verticies are drawn) and changing the last parameter to a buffer offset. Here's an example of how I do that case:
glDrawRangeElements(GL_TRIANGLES, 			        0, 			        Triangles.IndexCurrentSize, 			        (size * 3), 			        GL_UNSIGNED_INT, 			        BUFFER_OFFSET((start * 3) * sizeof(unsigned int)));

where BUFFER_OFFSET is #define BUFFER_OFFSET(i) ((char *)NULL + (i)). 'size' is the number of triangles to draw, 'start' is the triangle to begin drawing from.

Hope this helps. VBOs gave (and sometimes still give) me a lot of trouble to get working the first time.
The best source of infomation on VBOs is the spec and the examples at the end : vertex_buffer_object
Thanks very much guys! This should help me a lot!

Greetings
Rick
Allright, I've been able to draw some quads using a simple VBO. However, I have 2 problems:
- The next object that gets rendered is f#cked up. Once if I pass some vertices to the VBO, it goes wrong with the next model
- I can't use indices. Even when I don't use them (only initialize them), the program crashes after a few seconds, error in 'nvogint.dll' or something.

Here's the initializing code:
<BTW, this is Delphi code, but its pretty much the same>		vc := length( vertices ); // amount of vertices, 8 in my case (2 quads)		{ Create a VBO ID }	glGenBuffersARB( 1, @VBO_ID );	glBindBufferARB( GL_ARRAY_BUFFER_ARB, VBO_ID );	{ Send the vertex data }//! If I use NULL for data, the next object isn't affected, otherwise it is.	glBufferDataARB( GL_ARRAY_BUFFER_ARB,			vc * VBO_V3F_SIZE,	// amount of vertices * 12 (I'm only using vector3, GL_V3F			vertices,		// An array with 8 vertices, each vertex is 3 times a float			GL_STATIC_DRAW_ARB			);	{ Create the indices buffer }	glGenBuffersARB( 1, @IND_VBO_ID );             	glBindBufferARB(  GL_ELEMENT_ARRAY_BUFFER_ARB, IND_VBO_ID );	//! Calling this function below will crash the program after a few seconds,// except if i use NULL for the data parameter. Even passing 1 index is enough// to crash	glBufferDataARB(  GL_ELEMENT_ARRAY_BUFFER_ARB,			indSize * SizeOf(GLuint),	// 8 indices                              			indices,				// list with 8 ints			GL_STATIC_DRAW_ARB			);           


The rendering part doesn't matter now, the problems are already there without rendering the VBO. But notice that the rendering itself just works (not with indices but with glDrawArrays( GL_QUADS... ). Anyway, the program crashes if I pass something to the index buffer. I also tried it with "glMapBufferARB" but even if I didn't affect the data, it was enough to let the program crash...

As for the other problem, the object that comes next (not using a VBO) looks like a small crumpled paper instead of a terrain piece, except if I use NULL for the vertex data in the VBO. This OpenGL code is called immidiatly after the VBO initialization code above:
	{ Draw test terrain (no shaders or other materials used, just vertex data) }	glEnableClientState( GL_VERTEX_ARRAY );	glVertexPointer( 3, GL_FLOAT, 0, vertices );	glDrawElements( GL_TRIANGLES, indCount, GL_UNSIGNED_INT, indices );

Did I forget to enable/disable/unmap/whatever something? I guess so, glBinfBufferARB is still on that VBO. If that's the case, how to switch back to 'normal' rendering without VBO's?

Greetings,
Rick

[Edited by - spek on August 4, 2005 8:53:19 PM]
you can turn of VBO using glBindBufferARB(GL_ARRAY_BUFFER_ARB,0); Remember that you have to turn off indices VBO separately.
For the rendering code itself, are you sure that you pass offsets to the buffers instead of real adresses when using vbo?
Thanks man, disabling worked and it also solved the crash with the indices. I guess the program tried to use indices on a wrong way because that buffer was still enabled.

One last question, I can use
-glDrawElements
-glDrawRangeElements
-glDrawRangeElementsEXT

Which one is the fastest and what's the difference? I'm using it for quads (a large set of quads representing grass).

Thanks!
Rick
glDrawRangeElements is the same as glDrawRangeElementsEXT, except that it was promoted to core OpenGL in version 1.2. glDrawRangeElements might allow the driver to optimize the rendering. I'm not sure if you'll get an actual improvement over glDrawElements, but you could try.
I have a question with VBOs, why would my program crash when glBindBuffer is called? I copied the SuperBibles example for using VBOs w/o using glMapBuffer exactley and just randomly commenting lines when I get rid of all glBindBuffer(and DrawArrays() so it doesn't try to draw empty memory location) it will run.
Quote:Original post by SirOnion
I have a question with VBOs, why would my program crash when glBindBuffer is called? I copied the SuperBibles example for using VBOs w/o using glMapBuffer exactley and just randomly commenting lines when I get rid of all glBindBuffer(and DrawArrays() so it doesn't try to draw empty memory location) it will run.

I think a similar question was asked here recently. Try searching a little. Otherwise, write up a new thread and give us the details, including the offending code.

This topic is closed to new replies.

Advertisement