"invisible" VBOs

Started by
16 comments, last by Mantear 19 years, 1 month ago
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.
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.
Hrm, it looks like I may be generating my normals incorrectly. What happens if I draw a VBO object without specifying normals?
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.
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
When General Patton died after World War 2 he went to the gates of Heaven to talk to St. Peter. The first thing he asked is if there were any Marines in heaven. St. Peter told him no, Marines are too rowdy for heaven. He then asked why Patton wanted to know. Patton told him he was sick of the Marines overshadowing the Army because they did more with less and were all hard-core sons of bitches. St. Peter reassured him there were no Marines so Patton went into Heaven. As he was checking out his new home he rounded a corner and saw someone in Marine Dress Blues. He ran back to St. Peter and yelled "You lied to me! There are Marines in heaven!" St. Peter said "Who him? That's just God. He wishes he were a Marine."
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!
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.
Hrm, so, it needs to be something like:
// Initialization CodeglGenBuffers( 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 codeglEnableClientState(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.
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'sinline char* BUFFER_OFFSET(int i){	return (char *)(NULL + i);}


Do this first before you worry about dynamic data in a VBO. Small steps...
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.

This topic is closed to new replies.

Advertisement