4

I'd like to use Vertex Buffer Objects (VBOs) to improved my rendering of somewhat complicated models in my Open GL ES 1.1 game for iPhone. After reading several posts on SO and this (http://playcontrol.net/ewing/jibberjabber/opengl_vertex_buffer_object.html) tutorial, I'm still having trouble understanding VBOs and how to implement them given my Cheetah 3D export model format. Could someone please give me an example of implementing a VBO and using it to draw my vertices with the given data structure and explain the syntax? I greatly appreciate any help!

#define body_vertexcount    434
#define body_polygoncount   780

// The vertex data is saved in the following format:
// u0,v0,normalx0,normaly0,normalz0,x0,y0,z0
float body_vertex[body_vertexcount][8]={
{0.03333, 0.00000, -0.68652, -0.51763, 0.51063, 0.40972, -0.25028, -1.31418},
{...},
{...}
}

GLushort body_index[body_polygoncount][3]={
{0, 1, 2},
{2, 3, 0}
}

I've written the following code with the help of Chapter 9 from Pro OpenGL ES (Appress). I'm getting EXC_BAD_ACCESS with the DrawElements command and I'm not sure why. Could someone please shed some light? Thanks -

// First thing we do is create / setup the index buffer
glGenBuffers(1, &bodyIBO);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bodyIBO);

// For constrast, instead of glBufferSubData and glMapBuffer, 
// we can directly supply the data in one-shot
glBufferData(GL_ELEMENT_ARRAY_BUFFER, body_polygoncount*sizeof(GLubyte), body_index, GL_STATIC_DRAW);

// Define our data structure
int numXYZElements = 3;
int numNormalElements = 3;
int numTextureCoordElements = 2;
long totalXYZBytes;
long totalNormalBytes;
long totalTexCoordinateBytes;
int numBytesPerVertex;

// Allocate a new buffer
glGenBuffers(1, &bodyVBO);

// Bind the buffer object to use
glBindBuffer(GL_ARRAY_BUFFER, bodyVBO);

// Tally up the size of the data components
numBytesPerVertex = numXYZElements;
numBytesPerVertex += numNormalElements;
numBytesPerVertex += numTextureCoordElements;
numBytesPerVertex *= sizeof(GLfloat);

// Actually allocate memory on the GPU ( Data is static here )
glBufferData(GL_ARRAY_BUFFER, numBytesPerVertex * body_vertexcount, 0, GL_STATIC_DRAW);

// Upload data to the cache ( memory mapping )
GLubyte *vboBuffer = (GLubyte *)glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES);

// Caclulate the total number of bytes for each data type
totalXYZBytes = numXYZElements * body_vertexcount * sizeof(GLfloat);
totalNormalBytes = numNormalElements * body_vertexcount * sizeof(GLfloat);
totalTexCoordinateBytes = numTextureCoordElements * body_vertexcount * sizeof(GLfloat);

// Set the total bytes property for the body
self.bodyTotalBytes = totalXYZBytes + totalNormalBytes + totalTexCoordinateBytes;

// Setup the copy of the buffer(s) using memcpy()
memcpy(vboBuffer, body_vertex, self.bodyTotalBytes);

// Perform the actual copy
glUnmapBufferOES(GL_ARRAY_BUFFER);

Here are the drawing commands where I'm getting the exception:

    // Activate the VBOs to draw
    glBindBuffer(GL_ARRAY_BUFFER, bodyVBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bodyIBO);

    // Setup drawing
    glMatrixMode(GL_MODELVIEW);
    glEnable(GL_TEXTURE_2D);
    glClientActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D,lightGreyInt);

    // Setup pointers
    glVertexPointer(3, GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 0 );
    glTexCoordPointer(2, GL_FLOAT, sizeof(vertexStruct),  (char *)NULL + 12 );
    glNormalPointer(GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 24 );

    // Now draw the body
    glDrawElements(GL_TRIANGLES, body_polygoncount,GL_UNSIGNED_SHORT, (GLvoid*)((char*)NULL));
    //glDrawElements(GL_TRIANGLES, body_polygoncount, GL_UNSIGNED_SHORT, nil);
    //glDrawElements(GL_TRIANGLES,body_polygoncount*3,GL_UNSIGNED_SHORT,body_index);
PhilBot
  • 748
  • 18
  • 85
  • 173
  • I cannot believe there is no learning resource to be found that explains this pretty well to you, assuming you already know how vertex arrays and the rest of OpenGL works (which your mentioning of **your** OpenGL ES 1.1 game suggests). You may also look [here](http://www.songho.ca/opengl/gl_vbo.html), but the linked tutorial from your question looks reasonable (I only glanced over it, though). – Christian Rau Mar 18 '12 at 15:24
  • What part are you having trouble with? We're not just going to write code for you. What about the data structure and syntax don't you understand? Just be as explicit as possible so we can formulate a reasonable answer. – user1118321 Mar 18 '12 at 15:52
  • I've pasted my code, I'm particularly having trouble rendering the interleaved data with the glDrawElements call. I'm getting the EXC_BAD_ACCESS, I'd really appreciate some help - – PhilBot Mar 18 '12 at 19:09

1 Answers1

3

Well, first of all your index buffer is too small, you don't just have body_polygoncount indices but body_polygoncount * 3. You also messed up the type, since they're shorts, you need GLushort and not GLubyte, so it should be

glBufferData(GL_ELEMENT_ARRAY_BUFFER, body_polygoncount*3*sizeof(GLushort),
             body_index, GL_STATIC_DRAW);

And then, you messed up the offsets of your attributes, since your data contains first the texture coords, then the normal and then the position for each vertex, it should be

glVertexPointer(3, GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 20 );   //3rd, after 5*4 byte
glTexCoordPointer(2, GL_FLOAT, sizeof(vertexStruct),  (char *)NULL + 0 ); //1st
glNormalPointer(GL_FLOAT, sizeof(vertexStruct), (char *)NULL + 8 );       //2nd, after 2*4 bytes

And finally, in a glDrawElements call you don't give the number of triangles, but the number of elements (indices), so it should be

glDrawElements(GL_TRIANGLES, body_polygoncount*3,
               GL_UNSIGNED_SHORT, (GLvoid*)((char*)NULL));

Otherwise your code looks reasonable (of course the mapping was senseless and you could have just used glBufferData again, but I guess you did it for learning) and if you understood everything it does, there is nothing more to it.

But I wonder that all these errors would also have occurred if you had just used client side vertex arrays without VBOs and I thought OpenGL ES 1.1 doesn't have immediate mode glBegin/glEnd. So I wonder why your game worked previously without VBOs if you're not aware of these errors.

Christian Rau
  • 45,360
  • 10
  • 108
  • 185
  • Thank you - I see my mistakes.. now it makes sense. I was previously drawing like:// Draw the Gun - Render and Texture Proceedure for gunX //glBindTexture(GL_TEXTURE_2D,lightGreyInt); glVertexPointer(3, GL_FLOAT, sizeof(vertexStruct), &interpolatedVerticesGun[0][5]); glTexCoordPointer(2, GL_FLOAT, sizeof(vertexStruct), &interpolatedVerticesGun[0][0]); glNormalPointer(GL_FLOAT, sizeof(vertexStruct), &interpolatedVerticesGun[0][2]); glDrawElements(GL_TRIANGLES,gun2_polygoncount*3,GL_UNSIGNED_SHORT,gun2_index); – PhilBot Mar 19 '12 at 03:15