Sign in to follow this  

"invisible" VBOs

This topic is 4661 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm working on moving my little engine over to using VBOs and came across something that has me scratching my head. Whenever I draw the object, it seems to take on the color of the background. I can only make out the outline of the object (in my case, a sphere) when I see other objects (non-VBO) go behind it. Here's my code:
// Enable client states for vertex, color, and normal
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);	

// Bind the data
glBindBuffer(GL_ARRAY_BUFFER, pObject[0].VertexName);
glVertexPointer(3, GL_FLOAT, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, pObject[0].ColorName);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, pObject[0].NormalName);
glNormalPointer(GL_FLOAT, 0, 0);

// Draw the Points
if (pObject->Points.IndexCurrentSize > 0)
   glDrawElements(GL_POINTS, pObject[0].Points.IndexCurrentSize, GL_UNSIGNED_INT, pObject[0].Points.Index);

// Draw the Lines
if (pObject->Lines.IndexCurrentSize > 0)
   glDrawElements(GL_LINES, pObject[0].Lines.IndexCurrentSize, GL_UNSIGNED_INT, pObject[0].Lines.Index);

// Draw the Triangles
if (pObject->Triangles.IndexCurrentSize > 0)
   glDrawElements(GL_TRIANGLES, pObject[0].Triangles.IndexCurrentSize, GL_UNSIGNED_INT, pObject[0].Triangles.Index);

// Draw the Quads
if (pObject->Quads.IndexCurrentSize > 0)
   glDrawElements(GL_QUADS, pObject[0].Quads.IndexCurrentSize, GL_UNSIGNED_INT, pObject[0].Quads.Index);

// Disable the client states
glDisableClientState( GL_VERTEX_ARRAY );				
glDisableClientState( GL_COLOR_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
I have a vertex, color, and normal array for each object, and I have separate index arrays for each primitive type. *.IndexCurrentSize indicates the number of vertex indicies used by Points, Lines, etc. Whenver I change the background color, the sphere takes on that color. Light doesn't appear to be affecting it either. GL_LIGHTING is enable, I've set the color (glColor4fv), etc. Any ideas? Thanks.

Share this post


Link to post
Share on other sites
Hmm... only thing I can think of is that you might be enabling blending somewhere and forgetting to disable it.

Could you upload a screenshot somewhere and link to it here? Also post anymore code you think might be a problem.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mantear
Hrm, it looks like I may be generating my normals incorrectly. What happens if I draw a VBO object without specifying normals?


I believe it would just use whatever the last specified normal is. I'm not 100% sure though, I haven't gotten into using VBOs too much yet.

Share this post


Link to post
Share on other sites
It depends, if you have done glEnableClientState(GL_NORMAL_ARRAY) it should either crash with an access violation (if youve used glNormalPointer() at another time) or it should use the last specified normal (with glNormalPointer()) if that memory is still valid. If you have not called glEnableClientState() then it will use the last normal from glNormal3f() (it may also look for the last from glNormalPointer() if glNormal3f() has not been called,but im not sure about that, more likely it will just have some random normal if glNormal3f() has never been called)

hope that helps
-Dan

Share this post


Link to post
Share on other sites
I'm missing something in how to set up my VBOs, and I think I'm just confusing myself more, so I'll post what I have and ask for help!

After generating my object, I do this:
glGenBuffers( 1, &Object.VertexName);
glBindBuffer( GL_ARRAY_BUFFER, Object.VertexName);
glBufferData( GL_ARRAY_BUFFER, Object.VertexCurrentSize*3*sizeof(float), Object.Vertex, GL_STATIC_DRAW);

glGenBuffers( 1, &Object.ColorName );
glBindBuffer( GL_ARRAY_BUFFER, Object.ColorName );
glBufferData( GL_ARRAY_BUFFER, Object.VertexCurrentSize*4*sizeof(unsigned char), Object.Color, GL_STATIC_DRAW);

glGenBuffers( 1, &Object.NormalName );
glBindBuffer( GL_ARRAY_BUFFER, Object.NormalName );
glBufferData( GL_ARRAY_BUFFER, Object.VertexCurrentSize*3*sizeof(float), Object.Normal, GL_STATIC_DRAW);


Then, when I want to draw, I do this:
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, Object.VertexName);
glVertexPointer(3, GL_FLOAT, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, Object.ColorName);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, Object.NormalName);
glNormalPointer(GL_FLOAT, 0, 0);

glDrawElements(GL_TRIANGLES, Object.Triangles.IndexCurrentSize, GL_UNSIGNED_INT, Object.Triangles.Index);


Let's see, to make some things clear, IndexCurrentSize is the size of the array holding vertex indicies. Vertex/Color/Normal-Name are the IDs of the buffers. Object.Vertex/Color/Normal are the actual arrays that contain the data. Object.Vertex looks like 'float Vertex[some_size][3]', Object.Color is 'unsigned char Color[some_size][4]', etc.

It draws the shape, so either the vertices are getting set up correctly, or that part is working on a fluke. The color and/or normals aren't working, though. The object still takes on the color of whatever the background is set to. Anyone able to see my error(s)? Thanks!

Share this post


Link to post
Share on other sites
I can see what's wrong:

When creating a buffer object, it's really a window into another address space on the GL server. The problem is that that all the gl*Pointer methods are directed into the current VBO. There is only 1 bound at any given time.

You've created seperate VBOs for vertex, color, and normals each. When you finally render, the normal buffer is bound, so it's used as the source of *ALL* data (colors and vertices included). To solve this, you need to include all the relevant data (all 3 types), in a single contiguous chunk of memory, and use just 1 VBO (with the proper indexes into it).

ie, if you have 100 vertices, you would create a single VBO of size:
(6*sizeof(float)+4*sizeof(unsigned char))*100.

Share this post


Link to post
Share on other sites
Hrm, so, it needs to be something like:
// Initialization Code
glGenBuffers( 1, &Object.VBOName);
glBindBuffer( GL_ARRAY_BUFFER, Object.VBOName);
glBufferData( GL_ARRAY_BUFFER, Object.VertexCurrentSize * ((6*sizeof(float)) + (4*sizeof(unsigned char))), Object.Vertex, GL_STATIC_DRAW);

...

// Drawing code
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, Object.VBOName);
glVertexPointer(3, GL_FLOAT, 0, 0);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);
glNormalPointer(GL_FLOAT, 0, 0);

glDrawElements(GL_TRIANGLES, Object.Triangles.IndexCurrentSize, GL_UNSIGNED_INT, Object.Triangles.Index);



Then, I need to make sure Object.Color comes right after Object.Vertex, and Object.Normal after that? Also, what determines the order of the elements? Does the order of enabling client states or the gl*Pointer order determine which comes after vertex data (color or normal) or is it pre-defined?

Hmmm, this may cause issues for me, since I'm making my data dynamically allocatable (I want to be able to generate/edit/delete my objects) and this means the pointers are going to be moving all over the place (I know I don't want to use GL_STATIC_DRAW, but for now, my data is static, so it doesn't really matter). How do people generally get around this, or are VBOs generally used with less dynamic data (with the pointers staying put)?

One more thing! If/when I alter my data by adding/removing/editing vertices, what do I need to do to update the VBO? My guess would be, if I edit the current data, to bind the VBO and then call glBufferData (or glBufferSubData). But if I change the size of the VBO, I'll have to delete the current one and create a new one. Is this correct?

Lots of questions, I know, I'm a newb. But if I do something I want to do it right, and for general purposes, that means VBOs.

EDIT: Hmm, I think I just realized, I could do
glColorPointer(4, GL_UNSIGNED_BYTE, 0, &Object.Color);

to handle my moving pointers.

Share this post


Link to post
Share on other sites
Quote:
Original post by Mantear
Hrm, so, it needs to be something like:
*** Source Snippet Removed ***

Then, I need to make sure Object.Color comes right after Object.Vertex, and Object.Normal after that? Also, what determines the order of the elements? Does the order of enabling client states or the gl*Pointer order determine which comes after vertex data (color or normal) or is it pre-defined?

Hmmm, this may cause issues for me, since I'm making my data dynamically allocatable (I want to be able to generate/edit/delete my objects) and this means the pointers are going to be moving all over the place (I know I don't want to use GL_STATIC_DRAW, but for now, my data is static, so it doesn't really matter). How do people generally get around this, or are VBOs generally used with less dynamic data (with the pointers staying put)?

One more thing! If/when I alter my data by adding/removing/editing vertices, what do I need to do to update the VBO? My guess would be, if I edit the current data, to bind the VBO and then call glBufferData (or glBufferSubData). But if I change the size of the VBO, I'll have to delete the current one and create a new one. Is this correct?

Lots of questions, I know, I'm a newb. But if I do something I want to do it right, and for general purposes, that means VBOs.

EDIT: Hmm, I think I just realized, I could do
glColorPointer(4, GL_UNSIGNED_BYTE, 0, &Object.Color);

to handle my moving pointers.


One thing at a time grasshoper. Just get your VBOs working with static data first. What I do is, I have a struct called Vertex. This struct holds all my vertex data e.g. vertex x,y,z then normal x,y,z then texcoords x,y. Now you have to put information into all that data based on what you want in that struct vertex positions, normals, texcoords ect... Then I use offsets to determine the starting positions of each subgroup.


nVertexStride = sizeof(Vertex);
nOffsetForNormals = sizeof(float) * 3;




you then use those offsets when you call these functions


glVertexPointer(3, GL_FLOAT, nVertexStride, BUFFER_OFFSET(0));
glEnableClientState(GL_VERTEX_ARRAY);
glNormalPointer(GL_FLOAT, nVertexStride, BUFFER_OFFSET(nOffsetForNormals));
glEnableClientState(GL_NORMAL_ARRAY);




Here is the offset function I made it inline

//function for byte offsets for VBO's
inline char* BUFFER_OFFSET(int i)
{
return (char *)(NULL + i);
}



Do this first before you worry about dynamic data in a VBO. Small steps...

Share this post


Link to post
Share on other sites
Quote:
Original post by RichardS
I can see what's wrong:

When creating a buffer object, it's really a window into another address space on the GL server. The problem is that that all the gl*Pointer methods are directed into the current VBO. There is only 1 bound at any given time.

You've created seperate VBOs for vertex, color, and normals each. When you finally render, the normal buffer is bound, so it's used as the source of *ALL* data (colors and vertices included). To solve this, you need to include all the relevant data (all 3 types), in a single contiguous chunk of memory, and use just 1 VBO (with the proper indexes into it).

ie, if you have 100 vertices, you would create a single VBO of size:
(6*sizeof(float)+4*sizeof(unsigned char))*100.


I'm afraid this is incorrect. You are allowed to use different buffers:
Quote:
From Specs: http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_buffer_object.txt
In the case of vertex arrays, this extension defines not merely one
binding for all attributes, but a separate binding for each
individual attribute. As a result, applications can source their
attributes from multiple buffers. An application might, for example,
have a model with constant texture coordinates and variable geometry.
The texture coordinates might be retrieved from a buffer object with
the usage mode "STATIC_DRAW", indicating to the GL that the
application does not expect to update the contents of the buffer
frequently or even at all, while the vertices might be retrieved from
a buffer object with the usage mode "STREAM_DRAW", indicating that
the vertices will be updated on a regular basis.

Share this post


Link to post
Share on other sites
MAR_999, sounds like you're talking about using interleaved data arrays. I've thought about using those, but for now, I want to stick with non-interleaved.

Since I'm using Object.Triangles.Index, an array of vertex indicies, I must have to use GL_ELEMENT_ARRAY_BUFFER somewhere, right? Do I need to glGenBuffer and get a buffer for Object.Triangles.Index? Something like:
// Initialization Code
glGenBuffers( 1, &Object.Triangles.VBOName);
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, Object.Triangles.VBOName);
glBufferData( GL_ELEMENT_ARRAY_BUFFER, Object.Triangles.IndexCurrentSize*sizeof(unsigned int), Object.Triangles.Index, GL_STATIC_DRAW);

glGenBuffers( 1, &Object.VertexName);
glBindBuffer( GL_ARRAY_BUFFER, Object.VertexName);
glBufferData( GL_ARRAY_BUFFER, Object.VertexCurrentSize*3*sizeof(float), Object.Vertex, GL_STATIC_DRAW);

glGenBuffers( 1, &Object.ColorName );
glBindBuffer( GL_ARRAY_BUFFER, Object.ColorName );
glBufferData( GL_ARRAY_BUFFER, Object.VertexCurrentSize*4*sizeof(unsigned char), Object.Color, GL_STATIC_DRAW);

glGenBuffers( 1, &Object.NormalName );
glBindBuffer( GL_ARRAY_BUFFER, Object.NormalName );
glBufferData( GL_ARRAY_BUFFER, Object.VertexCurrentSize*3*sizeof(float), Object.Normal, GL_STATIC_DRAW);

// Draw Code
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

glBindBuffer(GL_ARRAY_BUFFER, Object.VertexName);
glVertexPointer(3, GL_FLOAT, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, Object.ColorName);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);

glBindBuffer(GL_ARRAY_BUFFER, Object.NormalName);
glNormalPointer(GL_FLOAT, 0, 0);

glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, Object.Triangles.VBOName);

glDrawElements(GL_TRIANGLES, Object.Triangles.IndexCurrentSize, GL_UNSIGNED_INT, Object.Triangles.Index);


If I'm thinking of this right, I'm setting the gl*Pointers to their correct buffers, binding the array of vertex indices, then drawing. Am I on the right track?






Share this post


Link to post
Share on other sites
I had this exact same problem early last week. It looks to me like the code you have in your third and most recent post (other then what rick_appleton pointed out) should work just fine. The only way this wouldn't work is if your normals were messed up, or if something was wrong with your lighting. To check the first you might want to try drawing in intermediate mode (the usual glVertex3f stuff) and make sure your normals are correct.

After that, I would guess (as this is what my problem was) that something is wrong with your lighting somewhere. I'm afraid I've forgotten exactly what my problem was, but I'm certain it had something to do with lighting.

I'm sorry I don't have a quick answer for you, but your code seems to be correct. This leads me to believe the problem is somewhere other then the VBOs. Especially since I had this same problem.

Share this post


Link to post
Share on other sites
I've verified by hand that the normals are correct, and the lighting works for my non-VBO objects. My last post is code I have yet to try out, so I don't know if it works yet. Just to be sure, am I using GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER in the correct places? Thanks everyone for their input.

Share this post


Link to post
Share on other sites
Hmm, things are still not working correctly. If I try:
// Loading
// Triangles
glGenBuffers(1, &pEngine->NewObject[ObjectIndex].Triangles.VBOName);
glBindBuffer(GL_ARRAY_BUFFER, pEngine->NewObject[ObjectIndex].Triangles.VBOName);
glBufferData(GL_ARRAY_BUFFER, pEngine->NewObject[ObjectIndex].Triangles.IndexCurrentSize * sizeof(unsigned int), pEngine->NewObject[ObjectIndex].Triangles.Index, GL_STATIC_DRAW);

// Vertex
glGenBuffers(1, &pEngine->NewObject[ObjectIndex].VertexName);
glBindBuffer(GL_ARRAY_BUFFER, pEngine->NewObject[ObjectIndex].VertexName);
glBufferData(GL_ARRAY_BUFFER, pEngine->NewObject[ObjectIndex].VertexMaxSize * 3 * sizeof(float), pEngine->NewObject[ObjectIndex].Vertex, GL_STATIC_DRAW);

// Color
glGenBuffers(1, &pEngine->NewObject[ObjectIndex].ColorName);
glBindBuffer(GL_ARRAY_BUFFER, pEngine->NewObject[ObjectIndex].ColorName);
glBufferData(GL_ARRAY_BUFFER, pEngine->NewObject[ObjectIndex].VertexMaxSize * 4 * sizeof(unsigned char), pEngine->NewObject[ObjectIndex].Color, GL_STATIC_DRAW);

// Normal
glGenBuffers(1, &pEngine->NewObject[ObjectIndex].NormalName);
glBindBuffer(GL_ARRAY_BUFFER, pEngine->NewObject[ObjectIndex].NormalName);
glBufferData(GL_ARRAY_BUFFER, pEngine->NewObject[ObjectIndex].VertexMaxSize * 3 * sizeof(float), pEngine->NewObject[ObjectIndex].Normal, GL_STATIC_DRAW);

...

// Drawing
// Enable client states for vertex, color, and normal
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);

// Bind the vertex data
glBindBuffer(GL_ARRAY_BUFFER, pObject->VertexName);
glVertexPointer(3, GL_FLOAT, 0, 0);

// Bind the color data
glBindBuffer(GL_ARRAY_BUFFER, pObject->ColorName);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, 0);

// Bind the normal data
glBindBuffer(GL_ARRAY_BUFFER, pObject->NormalName);
glNormalPointer(GL_FLOAT, 0, 0);

// Draw the Triangles
glBindBuffer(GL_ARRAY_BUFFER, pObject->Triangles.VBOName);
glDrawElements(GL_TRIANGLES, pObject->Triangles.IndexCurrentSize, GL_UNSIGNED_INT, pObject->Triangles.Index);

I thought when Binding and loading the buffer data, I should use GL_ELEMENT_ARRAY_BUFFER instead of GL_ARRAY_BUFFER for pObject->Triangles.Index, but if I do that, nothing shows up. With the posted code, I'm only seeing an object with the same color as the background color.

pObject->Triangles.Index is an a array of unsigned int, indicating the index location of the vertex/color/normal. pObject->Vertex is an array of float[3], pObject->Color is an array of unsigned char[4], and pObject->Normal is an array of float[3].
For a cube, IndexCurrentSize of the Vertex/Color/Normal arrays would be 8 (one for each vertex), and the size of Quads.Index would be 24 (6 quads * 4 vertices each).

*scratches his head*

Any ideas?

Share this post


Link to post
Share on other sites
Quote:
Original post by rick_appleton

I'm afraid this is incorrect. You are allowed to use different buffers:
Quote:
From Specs: http://oss.sgi.com/projects/ogl-sample/registry/ARB/vertex_buffer_object.txt
In the case of vertex arrays, this extension defines not merely one
binding for all attributes, but a separate binding for each
individual attribute. As a result, applications can source their
attributes from multiple buffers. An application might, for example,
have a model with constant texture coordinates and variable geometry.
The texture coordinates might be retrieved from a buffer object with
the usage mode "STATIC_DRAW", indicating to the GL that the
application does not expect to update the contents of the buffer
frequently or even at all, while the vertices might be retrieved from
a buffer object with the usage mode "STREAM_DRAW", indicating that
the vertices will be updated on a regular basis.


Yikes! I have to apologize then. That's a heck of a mistake, and I went and looked at the extension doc specifically to confirm that it would work the way I thought it did. You learn something useful every day...

Share this post


Link to post
Share on other sites
If I do use different buffers for each, does that add any overhead? Is glBindBuffer fast enough that it shouldn't matter that I call it once for each buffer I'm using?

I finally figured out what I was doing wrong. I had GL_TEXTURE_2D enabled when I went to draw my VBO object. It's working great now. Thanks everyone!

Share this post


Link to post
Share on other sites

This topic is 4661 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

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