Problem with glDrawElements() via VBOs

For some reason if I comment out the two glBindBuffer() calls in Renderer::Display() right before the call to glDrawElements(), I see the geometry in the VBO successfully. As far as I know, I need to bind both the vertices and the indices before calling glDrawElements()? Otherwise, how will the driver know which list of elements refer to which list of vertices?


// Helper macros...

    // For calculating buffer offsets for server side objects...
    #define BUFFER_OFFSET(bytes)    ((GLubyte *) NULL + (bytes))

// Constructor...
Renderer::Renderer()
{
    // Set the clear colour...
    glClearColor(0.0, 0.0, 0.0, 0.0);

    // Set shading model to smooth...
    glShadeModel(GL_SMOOTH);

    // Lighting...
    
        // Light 0: Diffuse and specular colours...
        GLfloat const WhiteLight[] = { 1.0, 1.0, 1.0, 1.0 };
        glLightfv(GL_LIGHT0, GL_DIFFUSE, WhiteLight);
        glLightfv(GL_LIGHT0, GL_SPECULAR, WhiteLight);
            
        // Toggle ambient lighting model...
        GLfloat const AmbientLightModel[] = { 0.3, 0.3, 0.3, 1.0 };
        glLightModelfv(GL_LIGHT_MODEL_AMBIENT, AmbientLightModel);

    // Lighting related calculations to enable...
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_DEPTH_TEST);
    
    // Antialiasing related calculations to enable...
    glEnable(GL_MULTISAMPLE);
    glEnable(GL_BLEND);
    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_POLYGON_SMOOTH);
    
    // Performance hints...
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
    glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
    glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
    
    // Initialize vertex buffer objects...
    
        // Allocate...
        glGenBuffers(BufferNames, BufferObjects);
        
        // Initialize ramp buffer objects...
        
            // Select vertices vertex buffer object...
            glBindBuffer(GL_ARRAY_BUFFER, BufferObjects[VBO_RampFaceVertices]);
            
            // Load vertices...
                
                // The vertices...
                GLfloat const RampVertices[][3] = 
                {
                    // Clockwise from top left of outer vertices looking down...
                    {-7.0, -0.5, -7.0}, 
                    { 7.0, -0.5, -7.0}, 
                    { 7.0, -0.5,  7.0}, 
                    {-7.0, -0.5,  7.0},
                    
                    // Clockwise from top left of inner vertices looking down...
                    {-5.0,  0.0, -5.0},
                    { 5.0,  0.0, -5.0},
                    { 5.0,  0.0,  5.0},
                    {-5.0,  0.0,  5.0}
                };

                // Upload data to card...
                glBufferData(GL_ARRAY_BUFFER, sizeof(RampVertices), 
                    RampVertices, GL_STATIC_DRAW);

                // Specify how to access the geometry within that data...
                glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));

                // Enable vertex arrays...
                glEnableClientState(GL_VERTEX_ARRAY);

            // Select indices vertex buffer object...
            glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, BufferObjects[VBO_RampFaceIndices]);
            
            // Load indices...
            
                // The indices for each quad...
                GLubyte const RampIndices[][4] =
                {
                    // Rear face...
                    {0, 4, 5, 1},
                    
                    // Right face...
                    {1, 5, 6, 2},
                    
                    // Front face...
                    {7, 3, 2, 6},
                    
                    // Left face...
                    {0, 3, 7, 4}
                };
                
                // Upload data to card...
                glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(RampIndices), 
                    RampIndices, GL_STATIC_DRAW);
}

// Display...
void Renderer::Display()
{
    // Variables...
    GLenum ErrorCode = 0;

    // Clear the colour and depth buffers...
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Select model-view transformation and reset...
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    
    // Setup viewing transformation matrix...
    m_Camera.PolarView();

    // Move light into position...
    GLfloat const LightPosition[] = { 5.0, 5.0, 5.0, 0.0 };
    glLightfv(GL_LIGHT0, GL_POSITION, LightPosition);

    // Draw ramps...
    
        // Select vertex buffer objects for vertices and indices...
        glBindBuffer(GL_ARRAY_BUFFER, BufferObjects[VBO_RampFaceVertices]);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, BufferObjects[VBO_RampFaceIndices]);
        
        // Draw...
        glDrawElements(GL_QUADS, 4 * 4, GL_UNSIGNED_BYTE, BUFFER_OFFSET(0));
        
    glutSolidTeapot(1.0);

    // Begin flushing command queue and swap the frame buffers...
    glutSwapBuffers();
    
    // Verify no errors...
    while((ErrorCode = glGetError()) != GL_NO_ERROR)
        std::cerr << "OpenGL Error: " << gluErrorString(ErrorCode) << std::endl;
}

// Window resizing...
void Renderer::Reshape(int Width, int Height)
{
    // Viewport matrix transformation...
    glViewport(0, 0, (GLsizei) Width, (GLsizei) Height);
    
    // Projection matrix transformation...
        
        // Select...
        glMatrixMode(GL_PROJECTION);
        
        // Reset...
        glLoadIdentity();
        
        // Apply perspective transformation...
        gluPerspective(60.0, (GLfloat) Width / (GLfloat) Height, 1.0, 30.0);
}

// Deconstructor...
Renderer::~Renderer()
{
    // For completion sake, cleanup vertex buffer objects...
    glDeleteBuffers(BufferNames, BufferObjects);
}

Thanks for any help.

Kip

You only need to bind the element buffer.

                // Specify how to access the geometry within that data...
                glVertexPointer(3, GL_FLOAT, 0, BUFFER_OFFSET(0));

                // Enable vertex arrays...
                glEnableClientState(GL_VERTEX_ARRAY);

Whenever you call a glPointer function, you are causing whatever buffer object is bound to GL_ARRAY_BUFFER at the time of this call to be used to get that vertex attribute data. Any changes made to the GL_ARRAY_BUFFER binding are meaningless unless you call the same glPointer function again.

That’s why your code doesn’t need to bind the GL_ARRAY_BUFFER buffer. It does need to bind the GL_ELEMENT_ARRAY_BUFFER. However, since you never unbounded previously, it is still bound to that slot. So there’s no need for you to bind it again.

It’s still good practice to do the binds and gl*Pointer calls before each rendering. If you were rendering multiple objects, you will need to do this setup work each time.

Thanks Alfonse. I don’t totally catch what you are saying, but I removed the call in Display() to bind the vertex data, but not the indices, and it renders fine.