Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm writing a generic ShaderProgram class that compiles a set of Shader objects, passes args to the shader (like vertex position, vertex normal, tex coords etc), then links the shader components into a shader program, for use with glDrawArrays.

My vertex data already exists in a VertexBufferObject that uses the following data structure to create a vertex buffer:

class CustomVertex
{
public:
float   m_Position[3];      // x, y, z      // offset 0, size = 3*sizeof(float)
float   m_TexCoords[2];     // u, v         // offset 3*sizeof(float), size = 2*sizeof(float)
float   m_Normal[3];        // nx, ny, nz;
float   colour[4];          // r, g, b, a
float   padding[20];        // padded for performance
};

I've already written a working VertexBufferObject class that creates a vertex buffer object from an array of CustomVertex objects. This array is said to be interleaved. It renders successfully with the following code:

void VertexBufferObject::Draw()
{
if( ! m_bInitialized )
    return;

glBindBuffer( GL_ARRAY_BUFFER,          m_nVboId );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER,  m_nVboIdIndex );

glEnableClientState( GL_VERTEX_ARRAY );
glEnableClientState( GL_TEXTURE_COORD_ARRAY );
glEnableClientState( GL_NORMAL_ARRAY );
glEnableClientState( GL_COLOR_ARRAY );  

glVertexPointer( 3, GL_FLOAT, sizeof(CustomVertex), ((char*)NULL + 0) );
glTexCoordPointer(3, GL_FLOAT, sizeof(CustomVertex), ((char*)NULL + 12));
glNormalPointer(GL_FLOAT, sizeof(CustomVertex), ((char*)NULL + 20));
glColorPointer(3, GL_FLOAT, sizeof(CustomVertex), ((char*)NULL + 32));  

glDrawElements( GL_TRIANGLES, m_nNumIndices, GL_UNSIGNED_INT, ((char*)NULL +  0) );

glDisableClientState( GL_VERTEX_ARRAY );
glDisableClientState( GL_TEXTURE_COORD_ARRAY );
glDisableClientState( GL_NORMAL_ARRAY );
glDisableClientState( GL_COLOR_ARRAY );

glBindBuffer( GL_ARRAY_BUFFER,          0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER,  0 );
}

Back to the Vertex Array Object though. My code for creating the Vertex Array object is as follows. This is performed before the ShaderProgram runtime linking stage, and no glErrors are reported after its steps.

// Specify the shader arg locations (e.g. their order in the shader code)
for( int n = 0; n < vShaderArgs.size(); n ++)   
    glBindAttribLocation( m_nProgramId, n, vShaderArgs[n].sFieldName.c_str() ); 

// Create and bind to a vertex array object, which stores the relationship between 
// the buffer and the input attributes
glGenVertexArrays( 1, &m_nVaoHandle );
glBindVertexArray( m_nVaoHandle );

// Enable the vertex attribute array (we're using interleaved array, since its faster)  
glBindBuffer( GL_ARRAY_BUFFER,          vShaderArgs[0].nVboId );    
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER,  vShaderArgs[0].nVboIndexId );

// vertex data
for( int n = 0; n < vShaderArgs.size(); n ++ )
{
    glEnableVertexAttribArray(n);

    glVertexAttribPointer( 
        n, 
        vShaderArgs[n].nFieldSize,
        GL_FLOAT,
        GL_FALSE,
        vShaderArgs[n].nStride,
        (GLubyte *) NULL + vShaderArgs[n].nFieldOffset
    );

    AppLog::Ref().OutputGlErrors();
}

This doesn't render correctly at all. I get a pattern of white specks onscreen, in the shape of the terrain rectangle, but there are no regular lines etc. Here's the code I use for rendering:

void ShaderProgram::Draw()
{
using namespace AntiMatter;

if( ! m_nShaderProgramId || ! m_nVaoHandle )
{
    AppLog::Ref().LogMsg("ShaderProgram::Draw() Couldn't draw object, as initialization of ShaderProgram is incomplete");
    return;
}   

glUseProgram( m_nShaderProgramId );
glBindVertexArray( m_nVaoHandle );  
glDrawArrays( GL_TRIANGLES, 0, m_nNumTris );

glBindVertexArray(0);
glUseProgram(0);
}

Can anyone see errors or omissions in either the VAO creation code or rendering code?

thanks!

share|improve this question
1  
Why is a class called ShaderProgram responsible for storing and rendering a mesh? There seems to be some confusion about what should be responsible for what here. –  Nicol Bolas Nov 11 '11 at 0:18
    
Yes, you're absolutely right, there is confusion there. The source is in an early iteration, and now that you & Sam H have pointed me in the right direction, I see the error in my design. I'm sure I'll address it! –  user3643 Nov 11 '11 at 2:06
1  
What on earth got you to insert a padding of 20 floats (80 bytes)? Such a large memory-overconsumption surely kills any possible alignment benefits. 4 floats (16 bytes) would have sufficed for a 64 byte alignment, which should be enough (if even neccessary). –  Christian Rau Nov 11 '11 at 21:37
1  
GPUs usually want 128-bit aligned data (that's 32 bytes, or 4 floats). No padding is necessary here. It is possible that freefallr confused bits and bytes. –  Sam Hocevar Nov 12 '11 at 2:10
add comment

1 Answer

up vote 5 down vote accepted

If you want to use VAOs with index buffers, you need glDrawElements() instead of glDrawArrays(). What you are seeing is probably all your vertices being rendered as triangles, as if there was no index buffer.

share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.