Sign in to follow this  
spek

VBO's

Recommended Posts

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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
I ended up skipping the lesson and checked out Occlusion Queries and it worked well, then it hit me that I probally mispelled something and the compiler ignored it because it was proper syntax. I had wglGetProcAddress("glBindBuffers");
So it would pointer to a non-existant location :( That was the problem.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this