Jump to content
  • Advertisement
Sign in to follow this  
Mantear

"invisible" VBOs

This topic is 4912 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
Advertisement
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
Hrm, it looks like I may be generating my normals incorrectly. What happens if I draw a VBO object without specifying normals?

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
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!