[SOLVED] I can't see anything rendered with my VBO but I get no errors anywhere

Started by
8 comments, last by Simulacrum 15 years, 5 months ago
Hello, I've spent the last week attempting to leverage vertex buffer objects within my resource management framework. I am not able to get anything to render with the vertex buffer objects I've created. My suspicion is that I am doing something wrong with glBufferSubDataARB when I create my vbo's because when I use glGetBufferSubDataARB I get something back that looks like a single element instead of an array of data when I step through my code with msvc's debugger. Still glGetError doesn't detect anything is wrong and my application is stable so it doesn't crash and give me any clues what I'm doing wrong. I can see anything I render in immediate mode but my vbo's simply won't cooperate with me :( Below I've provided the code for when I create and use my vbos. The code isn't in final state since I just wanted to see something get to screen before I get too far along. Any ideas as to where I am messing up would be much appreciated.
void OglVbo_Resource::Create()
                {
                        /************************************************************************/
                        /* If the resource is already initialized then avoid doing costly work  */
                        /* for no purpose.                                                      */
                        /************************************************************************/
                        if ( this->_initialized )
                        {
                                return;
                        }//end if

                        /************************************************************************/
                        /* Initialize function pointers to Opengl extensions                    */
                        /************************************************************************/
                        GLenum glewStatus = glewInit();
                        if ( glewStatus != GLEW_OK )
                        {
                                assert( glewStatus != GLEW_OK && "Problem: glewInit failed, something is seriously wrong." );
                                return;
                        }//end if

                        /************************************************************************/
                        /* Convert MetaData to usable form                                      */
                        /************************************************************************/

                        /************************************************************************/
                        /* calculate how many bytes the primary buffer in the VBO will store.   */
                        /************************************************************************/
                        GLsizeiptr  totalBytes( 0 );
                        unsigned int NumSubBuffers( this->_metadata->_subBufferCount );
                        std::vector<GLsizeiptr> bytesPerBuffer( NumSubBuffers );

                        //run through the subBuffer data
                        for ( unsigned int i = 0; i < NumSubBuffers; ++i )
                        {
                                /************************************************************************/
                                /* Calculate the number of bytes in the SubbBuffer.                     */
                                /************************************************************************/
                                if ( this->_metadata->_subBufferInfo[0] == "float" || this->_metadata->_subBufferInfo[0] == "GLfloat" )
                                {
                                        bytesPerBuffer = sizeof( GLfloat ) * 
                                                stringToNumeric<unsigned int>( this->_metadata->_subBufferInfo[1] );
                                }
                                else if ( this->_metadata->_subBufferInfo[0] == "double" || this->_metadata->_subBufferInfo[0] == "GLdouble" )
                                {
                                        bytesPerBuffer = sizeof( GLdouble ) * 
                                                stringToNumeric<unsigned int>( this->_metadata->_subBufferInfo[1] );
                                }
                                else if ( this->_metadata->_subBufferInfo[0] == "int" || this->_metadata->_subBufferInfo[0] == "GLint" )
                                {
                                        bytesPerBuffer = sizeof( GLint ) * 
                                                stringToNumeric<unsigned int>( this->_metadata->_subBufferInfo[1] );
                                }
                                else if ( this->_metadata->_subBufferInfo[0] == "unsigned int" || this->_metadata->_subBufferInfo[0] == "GLuint" )
                                {
                                        bytesPerBuffer = sizeof( GLuint ) * 
                                                stringToNumeric<unsigned int>( this->_metadata->_subBufferInfo[1] );
                                }
                                else if ( this->_metadata->_subBufferInfo[0] == "char" || this->_metadata->_subBufferInfo[0] == "GLbyte" )
                                {
                                        bytesPerBuffer = sizeof( GLbyte ) * 
                                                stringToNumeric<unsigned int>( this->_metadata->_subBufferInfo[1] );
                                }
                                else
                                {
                                        bytesPerBuffer = sizeof( GLubyte ) * 
                                                stringToNumeric<unsigned int>( this->_metadata->_subBufferInfo[1] );
                                }//end if

                                /************************************************************************/
                                /* Update the number of bytes in the primary buffer as a whole.         */
                                /************************************************************************/
                                totalBytes += bytesPerBuffer;
                        }//end for

                        /************************************************************************/
                        /* Select proper data transfer mode.                                    */
                        /************************************************************************/
                        GLenum transferMode;
                        if ( this->_metadata->_transferMode == "GL_STATIC_DRAW" )
                        {
                                transferMode = GL_STATIC_DRAW_ARB;
                        }
                        else if ( this->_metadata->_transferMode == "GL_STREAM_DRAW" )
                        {
                                transferMode = GL_STREAM_DRAW_ARB;
                        }
                        else
                        {
                                transferMode = GL_DYNAMIC_DRAW_ARB;
                        }//end if

                        /************************************************************************/
                        /* Instantiate vertex buffer object.                                    */
                        /************************************************************************/
                        GLuint vboID( 0 );
                        glGenBuffersARB( 1,&vboID );
                        glBindBufferARB( GL_ARRAY_BUFFER_ARB,vboID );
                        glBufferDataARB( 
                                GL_ARRAY_BUFFER_ARB,
                                totalBytes,
                                NULL,
                                transferMode
                                );

                        /************************************************************************/
                        /* Initialize vertex buffer object                                      */
                        /************************************************************************/
                        //run through the SubBuffers
                        GLintptr offset( 0 );
                        for ( unsigned int i = 0; i < this->_metadata->_subBufferCount ; ++i )
                        {
                                glBufferSubDataARB(
                                        GL_ARRAY_BUFFER_ARB,
                                        offset,
                                        bytesPerBuffer,
                                        static_cast<void *>( this->_metadata->_subBufferData.get() )
                                        );

                                offset += bytesPerBuffer;
                        }//end for

                        boost::shared_array<GLfloat> dataPtr( new GLfloat[offset/sizeof(GLfloat)] );
                        glGetBufferSubDataARB( GL_ARRAY_BUFFER_ARB,0,offset/sizeof(GLfloat),(void*)dataPtr.get() );
                        assert( glGetError() == 0 );

                        /************************************************************************/
                        /* Instantiate and initialize index buffer object                         */
                        /************************************************************************/
                        GLuint indexID( 0 );
                        if ( this->_metadata->_indexBufferData.size() )
                        {
                                glGenBuffersARB( 1,&indexID );
                                glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB,indexID );
                                glBufferDataARB(
                                        GL_ELEMENT_ARRAY_BUFFER_ARB,
                                        sizeof( unsigned int ) * this->_metadata->_indexBufferData.size(),
                                        static_cast<void *>( &this->_metadata->_indexBufferData[0] ),
                                        transferMode
                                        );
                        }//end if

                        /************************************************************************/
                        /* Reset client state                                                   */
                        /************************************************************************/
                        glBindBufferARB( GL_ARRAY_BUFFER_ARB,0 );
                        glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB,0 );

                        /************************************************************************/
                        /* Create the resource handle.                                          */
                        /************************************************************************/
                        this->_realResourceInstance = 
                                Resource<std::pair<GLuint,GLuint> >::ResInstance( new std::pair<GLuint,GLuint>( vboID,indexID ) );

                        /************************************************************************/
                        /* Set the signal flag stating the Resource is initialized.             */
                        /************************************************************************/
                        this->_initialized = true;
                }



void OglDisplayWindow::draw()
                {
                        if ( !GlWindow::valid() )
                        {
                                /************************************************************************/
                                /* Just tell the global manager to create any "gl" resources here :)     */
                                /* The needed contexts will be active here etc.                         */
                                /* Here's another tip! :)                                               */
                                /* You can use the member Create of Resource to Create VBOs OR to act   */
                                /* as an Opengl init routine!  Just like I do :)                        */
                                /*                                                                      */
                                /* Checkout the OglInitializer_Resource class too see how to virtualize    */
                                /* init methods.                                                        */
                                /************************************************************************/
                                GlobalResourceManager::GetSingleton()->CreateResources( ResourceInfo::Ogl );
                        }
 

                        /************************************************************************/
                        /* Have the Render Manager instruct all Renderers to draw their portion */
                        /* of the scene.                                                        */
                        /************************************************************************/

                        //temp code to see something
                        // clear buffer
                        glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT );

                        static GLfloat zAngle( 0 );
                        static GLfloat xAngle( 0 );
                        static cml::vector3f zAxis( 0,0,1 );
                        static cml::vector3f xAxis( 1,0,0 );
                        static cml::vector3f position( 0,5,0 );

                        glPushMatrix();

                        GlRotateTraits<GLfloat>::rotate( ( zAngle < 360 ) ? zAngle +=1.5f : zAngle = 0,zAxis );
                        //GlRotateTraits<GLfloat>::rotate( ( xAngle < 360 ) ? xAngle +=.5f : xAngle = 0,xAxis );
                        //GlTranslateTraits<GLfloat>::translate( position );

                        glBegin( GL_TRIANGLES );
                        glColor3f( 1,0,0 );
                        glVertex3f( 1,-1,0 );
                        glColor3f( 0,1,0 );
                        glVertex3f( 0,1,0 );
                        glColor3f( 0,0,1 );
                        glVertex3f( -1,-1,0 );
                        glEnd();
                        glBegin( GL_TRIANGLES );
                        glColor3f( 0,0,1 );
                        glVertex3f( -1,-1,0 );
                        glColor3f( 0,1,0 );
                        glVertex3f( 0,1,0 );
                        glColor3f( 1,0,0 );
                        glVertex3f( 1,-1,0 );
                        glEnd();

                        glPopMatrix();

                        glPushMatrix();

                        GlRotateTraits<GLfloat>::rotate( ( xAngle < 360 ) ? xAngle +=.5f : xAngle = 0,xAxis );
                        //GlTranslateTraits<GLfloat>::translate( position );

                        boost::shared_ptr<ResourceManager_Impl_MapBased<OglVbo_Resource> > VBOManager = VBOManager->GetSingleton();
                        boost::shared_ptr<OglVbo_Resource> TriangleVBO = VBOManager->GetResourceWrapper<OglVbo_Resource>( "Triangle" );
                        OglVbo_Resource::MetaData * VBO_MetaData = 
                                static_cast<OglVbo_Resource::MetaData *>( TriangleVBO->GetMetaData().get() );

                        /************************************************************************/
                        /* Extract the data transfer mode                                       */
                        /************************************************************************/
                        static GLenum transferMode;
                        if ( VBO_MetaData->_transferMode == "GL_STATIC_DRAW" )
                        {
                                transferMode = GL_STATIC_DRAW_ARB;
                        }
                        else if ( VBO_MetaData->_transferMode == "GL_STREAM_DRAW" )
                        {
                                transferMode = GL_STREAM_DRAW_ARB;
                        }
                        else
                        {
                                transferMode = GL_DYNAMIC_DRAW_ARB;
                        }//end if

                        /************************************************************************/
                        /* Bind to the vertex buffer object                                     */
                        /************************************************************************/
                        std::pair<GLuint,GLuint>  VBO_IDS = *static_cast<std::pair<GLuint,GLuint> *>( TriangleVBO->GetResInstance().get() );
   
                        assert( glIsBufferARB( VBO_IDS.first ) );
                        glBindBufferARB( GL_ARRAY_BUFFER_ARB,VBO_IDS.first );

                        //run through the SubBuffers
                        static unsigned int stride;
                        static unsigned int byteCount;
                        byteCount = 0;
                        static std::stringstream converter;
                        converter.clear();
                        converter.str( "" );
                        static unsigned int NumElements;
                        static GLenum DataType;
                        static unsigned int componentsPerElem;
                        componentsPerElem = 0;
                        static unsigned int i;
                        for ( i = 0; i < VBO_MetaData->_subBufferCount ; ++i )
                        {
                                /************************************************************************/
                                /* Select the DataType and proper stride                                */
                                /************************************************************************/
                                if ( VBO_MetaData->_subBufferInfo[0] == "float" || VBO_MetaData->_subBufferInfo[0] == "GLfloat" )
                                {
                                        DataType = GL_FLOAT;
                                        stride = sizeof( GLfloat );
                                }
                                else if ( VBO_MetaData->_subBufferInfo[0] == "double" || VBO_MetaData->_subBufferInfo[0] == "GLdouble" )
                                {
                                        DataType = GL_DOUBLE;
                                        stride = sizeof( GLdouble );
                                }
                                else if ( VBO_MetaData->_subBufferInfo[0] == "int" || VBO_MetaData->_subBufferInfo[0] == "GLint" )
                                {
                                        DataType = GL_INT;
                                        stride = sizeof( GLint );
                                }
                                else if ( VBO_MetaData->_subBufferInfo[0] == "unsigned int" || VBO_MetaData->_subBufferInfo[0] == "GLuint" )
                                {
                                        DataType = GL_UNSIGNED_INT;
                                        stride = sizeof( GLuint );
                                }
                                else if ( VBO_MetaData->_subBufferInfo[0] == "char" || VBO_MetaData->_subBufferInfo[0] == "GLbyte" )
                                {
                                        DataType = GL_BYTE;
                                        stride = sizeof( GLbyte );
                                }
                                else
                                {
                                        DataType = GL_UNSIGNED_BYTE;
                                        stride = sizeof( GLubyte );
                                }//end if

                                /************************************************************************/
                                /* Extract the number of elements in the SubBuffer                      */
                                /************************************************************************/
                                converter<<VBO_MetaData->_subBufferInfo[1];
                                converter>>NumElements;
                                converter.clear();
                                converter.str( "" );

                                /************************************************************************/
                                /* Create the correct gl*Pointers and set the proper client state       */
                                /************************************************************************/
                                converter<<VBO_MetaData->_subBufferInfo[2];
                                converter>>componentsPerElem;
                                converter.clear();
                                converter.str( "" );
                                componentsPerElem = NumElements / componentsPerElem;
                                if (  VBO_MetaData->_subBufferInfo[3] == "vertex" )
                                {
                                        glEnableClientState( GL_VERTEX_ARRAY );

                                        glVertexPointer(
                                                componentsPerElem,
                                                DataType,
                                                stride,
                                                static_cast<void *>( &byteCount )
                                                );
                                }
                                else if ( VBO_MetaData->_subBufferInfo[3] == "normal" )
                                {
                                        glEnableClientState( GL_NORMAL_ARRAY );

                                        glNormalPointer(
                                                componentsPerElem,
                                                stride,
                                                static_cast<void *>( &byteCount )
                                                );

                                }
                                else if ( VBO_MetaData->_subBufferInfo[3] == "color" )
                                {
                                        glEnableClientState( GL_COLOR_ARRAY );

                                        glColorPointer(
                                                componentsPerElem,
                                                DataType,
                                                stride,
                                                static_cast<void *>( &byteCount )
                                                );

                                }
                                else if ( VBO_MetaData->_subBufferInfo[3] == "texture" )
                                {
                                        //need a texture manager and a texture resource.
                                        //glEnableClientState( GL_TEXTURE_COORD_ARRAY );

                                        continue;
                                }

                                /************************************************************************/
                                /* update the byte count                                                */
                                /************************************************************************/
                                byteCount += NumElements * stride;
                        }//end for

                        /************************************************************************/
                        /* Draw what's in the vertex buffer object                              */
                        /************************************************************************/
                        if ( !VBO_MetaData->_indexBufferData.size() )
                        {
                                glDrawArrays(
                                        GL_TRIANGLES,
                                        0,
                                        6
                                        );
                        }
                        else
                        {
                                assert( glIsBufferARB( VBO_IDS.second ) );
                                glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB,VBO_IDS.second );
                                glDrawElements(
                                        GL_TRIANGLES,
                                        VBO_MetaData->_indexBufferData.size(),
                                        GL_UNSIGNED_INT,
                                        NULL
                                        );
                        }//end if

                        /************************************************************************/
                        /* Reset the client state                                               */
                        /************************************************************************/
                        for ( i = 0; i < VBO_MetaData->_subBufferCount ; ++i )
                        {
                                if (  VBO_MetaData->_subBufferInfo[3] == "vertex" )
                                {
                                        glDisableClientState( GL_VERTEX_ARRAY );
                                }
                                else if ( VBO_MetaData->_subBufferInfo[3] == "normal" )
                                {
                                        glDisableClientState( GL_NORMAL_ARRAY );
                                }
                                else if ( VBO_MetaData->_subBufferInfo[3] == "color" )
                                {
                                        glDisableClientState( GL_COLOR_ARRAY );
                                }
                                else if ( VBO_MetaData->_subBufferInfo[3] == "texture" )
                                {
                                        //need a texture manager and a texture resource.
                                        //glDisableClientState( GL_TEXTURE_COORD_ARRAY );
                                }
                        }//end for

                        glBindBufferARB( GL_ARRAY_BUFFER_ARB,0 );
                        glBindBufferARB( GL_ELEMENT_ARRAY_BUFFER_ARB,0 );

                        glPopMatrix();
                }







[Edited by - Simulacrum on October 30, 2008 11:14:23 AM]
The difference between a dream and reality is only what you choose to do about either of them.
Advertisement
Perhaps I can ask my question another way. What are some of the lesser known gotchas about vbos that you simply need to know about because the server won't tell you about them?
The difference between a dream and reality is only what you choose to do about either of them.
That's not such a good place to call glewInit(). Call glewInit() once you create the GL context.
The code is difficult to read but perhaps you are making a mistake somewhere or the object is simply not onscreen.
Make sure that stride is correct.
Example :
glVertexPointer(), in this case, most people use x, y, z so the call looks something like
glVertexPointer(3, GL_FLOAT, sizeof(float)*3, pointer)

If they are using a struct,
glVertexPointer(3, GL_FLOAT, sizeof(MyStruct), pointer)
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
Thanks for responding.

I am sorry if the code is hard to read...I'll try to answer any questions anyone has.

I do mean to only call glewInit once. That call is there right now as a sanity check and will be removed once I figure out what is going on here along with a few other superfluous lines of code :)

Onto your suggestion:

All the vertex,color,normal and texture data are in tightly packed arrays i.e. std::vector's at the moment.

Here's the structure that contains the "metadata" referenced in my original post.

struct MetaData                         {                                unsigned int _subBufferCount;                                std::string _transferMode;                                std::vector<std::vector<std::string> > _subBufferInfo;                                std::vector<boost::shared_ptr<void> > _subBufferData;                                std::vector<unsigned int> _indexBufferData;                        };


This is used to create my vbo's after I've read this metadata from file. Once my vbo's are created I have the option of purging portions of this object from memory but another rationale for it's existence is that all my vbo's first exist within files on the HDD rather than being hard coded. That way I can using scripting techniques to dynamically alter my vbo's with ease.

I updated my code with your stride suggestion. I still don't see anything on screen as of yet but I'm glad this bug is at least gone. The object should be on screen because it is an exact replica of the triangles I render in immediate mode except for the fact I rotate them on a different axis. They are just not showing up for some reason and I really wish Opengl would complain about something so I could fix it :)

I've a question.

The offset I pass into gl*pointer calls is in bytes right? When in look at documentation for these calls it describes the behavior taken when glDrawArrays is used but I'm using glDrawElements and I've gathered from forum posts that an offset in bytes is supposed to be used as the last parameter into these calls instead of a pointer to your data.

Do I understand that correctly? I'm trying to get re-acquainted with Opengl so thank you to anyone for insight they can provide.

[Edited by - Simulacrum on October 27, 2008 1:31:11 PM]
The difference between a dream and reality is only what you choose to do about either of them.
Just an update:

I've confirmed all my data is in my vbo's and the index buffer is also loaded to the server.

This leaves me with problems with my gl*pointer calls or with glDrawElements itself.
The difference between a dream and reality is only what you choose to do about either of them.
update 2:

I am about 99% sure something is wrong with how I setup glpointers. I just don't know what.

Here is how the data in my vbo is laid out:

|-vertex-|-normal-|-color-|-texture-|

Like data is packed with like data but all data except the index buffer is placed in an vbo. The index buffer is loaded into it own buffer as is should be.

I've confirmed with glGetBufferSubDataARB that data has been placed into my vbo's and that the data in them is not corrupt.

I am attempting to render with the following call:

glDrawElements(                                GL_TRIANGLES,                                VBO_MetaData->_indexBufferData.size(),                                GL_UNSIGNED_INT,                                NULL                                );


where VBO_MetaData->_indexBufferData is std::vector<unsigned int>.

I already confirmed the index buffer is good with glGetBufferSubDataARB so the above code should work but it doesn't. I can only look to how I am setting up my glpointers as I am fresh out of any other ideas.

Here is how I attempt to set up the vertex pointer.

glVertexPointer(                                                3,                                                GLfloat,                                                0,                                                &byteCount                                                );


where byteCount is a unsigned int and provides the offset into the vbo that I need to supply. If 36 bytes of data need to be skipped before you hit the "contiguous" vertex data then byteCount would be 36.

Since all the vertex data itself is contiguous I shouldn't need to supply a stride since vertex data and ONLY vertex data is packed together before you hit the next type of data.

This isn't working so either I am misunderstanding something or my perhaps my ICD has a bug.

I'm nearly at my wits end. Can anyone point out my audacious buffoonery here?
The difference between a dream and reality is only what you choose to do about either of them.
Update 3:

Seems I've been guessing right...almost.

I can now see something get rendered to screen if I pass in NULL for the last parameter to all gl*pointer calls.

However, the geometry displayed isn't what I expect it to be and secondly without the ability to pass an offset into the gl*pointer functions I can't specify which data should be used for what.

For example my color data is currently being read as vertex data which isn't desirable.
The difference between a dream and reality is only what you choose to do about either of them.
If you vertices are tighly packed, meaning : xyz xyz xyz etc.
then you function call seems fine.

If you have it interleaved with normals : xyz normal:xyz xyz normal:xyz
glVertexPointer(3, GL_FLOAT, sizeof(float)*6, offset)

sizeof(float)*6 is the stride in bytes.
Sig: http://glhlib.sourceforge.net
an open source GLU replacement library. Much more modern than GLU.
float matrix[16], inverse_matrix[16];
glhLoadIdentityf2(matrix);
glhTranslatef2(matrix, 0.0, 0.0, 5.0);
glhRotateAboutXf2(matrix, angleInRadians);
glhScalef2(matrix, 1.0, 1.0, -1.0);
glhQuickInvertMatrixf2(matrix, inverse_matrix);
glUniformMatrix4fv(uniformLocation1, 1, FALSE, matrix);
glUniformMatrix4fv(uniformLocation2, 1, FALSE, inverse_matrix);
That's just it V-man...if I pass in anything other than NULL for an offset nothing gets rendered.

My verts are tightly packed as you describe in your first example.

My data is normally arranged like so:

xyz xyz xyz normal normal normal rgb rgb rgb uv uv uv.

Right now I only have vert and color data in the vbo for easier testing. I can ascertain that my verts are arranged okay but my colors are off. I think I have an off by one error but still I'm a little perplexed as to how the call to glDrawElements even knows where my vertex data ended and my color data began without me supplying some sort of offset information to glVertexPointer and glColorPointer. I suspect glDrawElements doesn't know that and I'm only lucky in this moment.

It appears I have a good amount of old fashioned reading to do vs. jumping back into programming with this API.

[Edited by - Simulacrum on October 29, 2008 8:47:59 PM]
The difference between a dream and reality is only what you choose to do about either of them.
I finally figured out what was wrong.

Turns out I've been looking in the wrong place for the source of my errors all this time.

Nothing is wrong with the code but instead there was in error in the file format I was using i.e. the file was placing data in the wrong place so my parser blindly loaded the wrong data into the wrong buffers. Once I corrected the error on file everything works as you expect it to.

Thanks V-man for at least trying to help. Much appreciated.
The difference between a dream and reality is only what you choose to do about either of them.

This topic is closed to new replies.

Advertisement