9

I'm trying to take my code to the next level. Following some best practices from Apple, I'm trying to implement Vertex Array Objects around my Vertex Buffer Objects (VBO). I setup my VBOs and VAOs like this:

- (void)setupVBOs {  
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArrayOES(0);
    {
        glGenVertexArraysOES(1, &directArrayObject);
        glBindVertexArrayOES(directArrayObject);

    //    GLuint texCoordBuffer;
        glGenBuffers(1, &texCoordBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, texCoordBuffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(DirectVertices), DirectVertices, GL_STATIC_DRAW);

        glVertexAttribPointer(directPositionSlot, 2, GL_FLOAT, GL_FALSE, sizeof(DirectVertex), (GLvoid*)offsetof(DirectVertex, position));
        glEnableVertexAttribArray(directPositionSlot);
        glVertexAttribPointer(texCoordSlot, 2, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(DirectVertex), (GLvoid*)offsetof(DirectVertex, texCoord));
        glEnableVertexAttribArray(texCoordSlot);

        glGenVertexArraysOES(1, &arrayObject);
        glBindVertexArrayOES(arrayObject);

    //    GLuint vertexBuffer;
        glGenBuffers(1, &vertexBuffer);
        glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
        glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);

        glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
        glEnableVertexAttribArray(positionSlot);
        glVertexAttribPointer(colorSlot, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(Vertex), (GLvoid*)offsetof(Vertex, Color));
        glEnableVertexAttribArray(colorSlot);

    //    GLuint indexBuffer;
        glGenBuffers(1, &indexBuffer);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBuffer);
        glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
    }
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindVertexArrayOES(0);
}

which I took from http://www.opengl.org/discussion_boards/ubbthreads.php?ubb=showflat&Number=287977 and then use it like this:

- (void) render:(CADisplayLink*)displayLink {

    glClearColor(0, 104.0/255.0, 55.0/255.0, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glViewport(0, 0, backingWidth, backingHeight);

    [directProgram use];
    glBindVertexArrayOES(directArrayObject);
    glDisable(GL_DEPTH_TEST);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, videoFrameTexture);

//  // Update uniform values
    glUniform1i(videoFrameUniform, 0);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    [program use];
    glBindVertexArrayOES(arrayObject);
    glDisable(GL_TEXTURE_2D);
    glEnable(GL_DEPTH_TEST);

    CC3GLMatrix *projection = [CC3GLMatrix matrix];
    float h = 4.0f * self.frame.size.height / self.frame.size.width;
    [projection populateFromFrustumLeft:-2 andRight:2 andBottom:-h/2 andTop:h/2 andNear:4 andFar:10];
    glUniformMatrix4fv(projectionUniform, 1, 0, projection.glMatrix);

    CC3GLMatrix *modelView = [CC3GLMatrix matrix];
    [modelView populateFromTranslation:CC3VectorMake(sin(CACurrentMediaTime()), 0, -7)];
    currentRotation += displayLink.duration * 90;
    [modelView rotateBy:CC3VectorMake(currentRotation, currentRotation, 0)];
    glUniformMatrix4fv(modelViewUniform, 1, 0, modelView.glMatrix);

    glDrawElements(GL_TRIANGLES, sizeof(Indices)/sizeof(Indices[0]), GL_UNSIGNED_BYTE, 0);

    glBindVertexArrayOES(0);

    BOOL success = [context presentRenderbuffer:GL_RENDERBUFFER];
    if(!success)
        NSLog(@"present failed");
}

The call to glDrawArrays works, and it fills my texture, however, the call to glDrawElements fails with an EXC_BAD_ACCESS. My shader programs (i use two) are wrapped in a GLProgram object that I took from http://iphonedevelopment.blogspot.com/2010/11/opengl-es-20-for-ios-chapter-4.html

Richard Slater
  • 6,313
  • 4
  • 53
  • 81
davidbitton
  • 818
  • 10
  • 20

1 Answers1

11

Remove glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); from the end of your setup function.

Per the specification for OES_vertex_array_object, a vertex array object encapsulates all state except the array buffer binding1, so there is no element buffer bound at the time that you’re drawing, whereas you presumably wanted indexBuffer to be bound. By leaving indexBuffer bound at the time that you bind away from your vertex array object, you ensure that it’ll be rebound when you return to that vertex array object.


1 If you’re wondering why the array buffer binding isn’t tracked in vertex array objects, this is presumably because the currently-bound array buffer isn’t used directly when reading vertex data from arrays—rather, each vertex attribute has its own buffer binding, which is filled out by its respective gl*Pointer function by looking at the array buffer binding when the function is called.

Pivot
  • 3,456
  • 25
  • 20
  • Awesome. That did the trick. Now, when I analyze my app, Instruments is suggesting I use glDrawElements and indices in lieu of the glDrawArrays at the top of my rendering code. If so, I'll have two element array buffers. Will that matter? Will they both stay bound? – davidbitton Jun 07 '11 at 10:46
  • If you’re just using glDrawArrays to draw a single quad and there’s no actual possibility for vertex reuse, then there’s no point in switching to glDrawElements. Even so, you’re changing which vertex array object is bound between draws, so it would be fine. – Pivot Jun 07 '11 at 17:15