4

I've been bashing my head on the wall this afternoon persuading my openGLES2.0 code to perform correctly when I move from using VBO to VAO / VBO. Basically I'm working my way through Apple's "expert" advice on openGLES and moving to using Vertex Array Objects was top of the list ...

I've reviewed the similar question and response here but that didn't seem to help me, other than re-assure me that other people run into similar problems :(

My scenario is that I have approximately 500 rectangular textures moving around the screen. The code all works fine without VAO, but when I define USE_VAO (my constant) it's crashing on the first draw elements call. I'm obviously not understanding VAO properly ... but I can't see the error of my ways!

The setupBeforeRender method is called as the last part of my setup before entering the render loop.

-(void) setupBeforeRender {

glClearColor(0.6, 0.6, 0.6, 1);
glViewport(0, 0, self.frame.size.width, self.frame.size.height);
glEnable(GL_DEPTH_TEST);

glUniform1i(_textureUniform, 0);
glActiveTexture(GL_TEXTURE0); 

glEnableVertexAttribArray(_positionSlot);
glEnableVertexAttribArray(_colorSlot);
glEnableVertexAttribArray(_texCoordSlot);


glGenBuffers(1, &_indexBuffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indexBuffer);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);

}

And here's the render method

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

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

// Model view matrix and projection code removed for clarity

GLsizei stride = sizeof(Vertex);
const GLvoid* colourOffset = (GLvoid *) sizeof(float[3]);
const GLvoid* textureOffset = (GLvoid *) sizeof(float[7]);

 for (my objectToDraw in objectToDrawArray)
 {

    if (objectToDraw.vertexBufferObject == 0)
    {

        #ifdef USE_VAO

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

        glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, stride, 0);
        glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, stride, colourOffset);
        glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE,stride, textureOffset);    

        objectToDraw.vertexBufferObject = [objectToDraw createAndBindVBO];
        objectToDraw.vertexArrayObject = _vao;
        glBindBuffer(GL_ARRAY_BUFFER, 0);
        glBindVertexArrayOES(0);

        #else

        objectToDraw.vertexBufferObject = [objectToDraw createAndBindVBO];

        #endif
    }

   // Texture binding removed for clarity     

    #ifdef USE_VAO

    // This code crashes with EXC_BAD_ACCESS on the glDrawElements  

    glBindVertexArrayOES(objectToDraw.vertexArrayObject);
    glDrawElements(GL_TRIANGLES, sizeof(Indices) / sizeof(Indices[0]), GL_UNSIGNED_SHORT,0);
    glBindVertexArrayOES(0);                

    #else        

    // This path works fine. So turning VAO off works :(

    glBindBuffer(GL_ARRAY_BUFFER, storyTile.vertexBufferObject);
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, stride, 0);
    glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, stride, colourOffset);
    glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE, stride, textureOffset);

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

    #endif

} // End for each object

[_context presentRenderbuffer:GL_RENDERBUFFER];

}

Finally, my create and bind VBO method looks like this;

-(GLuint) createAndBindVBO {

const float* rgba = CGColorGetComponents([self.colour CGColor]);

Vertex Vertices[] = {
    {{0, 1, 0}, {1, 0, 1, 1}, {0,1}},
    {{0, 0, 0}, {1, 0, 1, 1}, {0,0}},
    {{1, 1, 0}, {1, 0, 1, 1}, {1,1}},
    {{1, 0, 0}, {1, 0, 1, 1}, {1,0}}

};

// Code removed for clarity - sets up geometry and colours    

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

return vertexBuffer;
}

I've tried various permutations of this and have sprinkled the code with glGetError() to see if that helps point to where the problem arises. Alas I get no errors, other than the BAD_ACCESS crash on the drawElements call.

EDIT: As suggested, this unfortunately also doesn't work

objectToDraw.vertexBufferObject = [objectToDraw createVBO];

glGenVertexArraysOES(1,&_vao);
glBindVertexArrayOES(_vao);
glBindBuffer(GL_ARRAY_BUFFER, objectToDraw.vertexBufferObject);

glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, stride, 0);
glVertexAttribPointer(_colorSlot, 4, GL_FLOAT, GL_FALSE, stride, colourOffset);
glVertexAttribPointer(_texCoordSlot, 2, GL_FLOAT, GL_FALSE,stride, textureOffset);    

objectToDraw.vertexArrayObject = _vao;
glBindVertexArrayOES(0);

I must be doing something dumb with the vertex array object ... but can someone figure out what the problem is?

Community
  • 1
  • 1
Roger
  • 15,793
  • 4
  • 51
  • 73

3 Answers3

4

The vertex array enabled flags are part of the VAO state, so you need to enable the vertex attribute arrays using glEnableVertexAttribArray while the VAO is bound.

From: http://www.khronos.org/registry/gles/extensions/OES/OES_vertex_array_object.txt

The resulting vertex array object is a new state vector, comprising all the state values (listed in Table 6.2, except ARRAY_BUFFER_BINDING):

  • VERTEX_ATTRIB_ARRAY_ENABLED
  • VERTEX_ATTRIB_ARRAY_SIZE,
  • VERTEX_ATTRIB_ARRAY_STRIDE,
  • VERTEX_ATTRIB_ARRAY_TYPE,
  • VERTEX_ATTRIB_ARRAY_NORMALIZED,
  • VERTEX_ATTRIB_ARRAY_POINTER,
  • ELEMENT_ARRAY_BUFFER_BINDING,
  • VERTEX_ATTRIB_ARRAY_BUFFER_BINDING.
Anton
  • 5,932
  • 5
  • 36
  • 51
  • Brilliant, thanks Anton. I think I was getting confused between the vertex index objects and the vertex attribute arrays, my head has been swimming a bit! I've got something working now and when I've cleaned it up I'll update my question to show the working version. This answer of yours was definitely the key. – Roger Jul 04 '12 at 20:18
0

You should call glVertexAttribPointer after glBindBuffer function call.

Mārtiņš Možeiko
  • 12,733
  • 2
  • 45
  • 45
0

I had a similar problem, didn't know what was causing it.

Eventually it turned out that i have to put in a const int number of vertices in glDrawArrays. sizeof() was not doing it right.

Michal M
  • 56
  • 2