I am developing an iPhone game using OpenGL ES 1.1 and you need to use buffer vertex objects to render 500+ particles without sacrificing performance.
My game was able to successfully draw using a method other than VBO, but now that I have tried to enable VBOs, nothing else is drawn.
Please help me identify what I am doing wrong and give a correct example.
I have a class called TexturedQuad , which consists of the following:
// TexturedQuad.h enum { ATTRIB_POSITION, ATTRIB_TEXTURE_COORD }; @interface TexturedQuad : NSObject { GLfloat *textureCoords; // 8 elements for 4 points (u and v) GLfloat *vertices; // 8 elements for 4 points (x and y) GLubyte *indices; // how many elements does this need? // vertex buffer array IDs generated using glGenBuffers(..) GLuint vertexBufferID; GLuint textureCoordBufferID; GLuint indexBufferID; // ...other ivars } // @synthesize in .m file for each property @property (nonatomic, readwrite) GLfloat *textureCoords; @property (nonatomic, readwrite) GLfloat *vertices; @property (nonatomic, readwrite) GLubyte *indices; @property (nonatomic, readwrite) GLuint vertexBufferID; @property (nonatomic, readwrite) GLuint textureCoordBufferID; @property (nonatomic, readwrite) GLuint indexBufferID; // vertex buffer object methods - (void) createVertexBuffers; - (void) createTextureCoordBuffers; - (void) createIndexBuffer;
TexturedQuad.m creates vertex buffers:
- (void) createVertexBuffers { glGenBuffers(1, &vertexBufferID); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferID); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); } - (void) createTextureCoordBuffers { glGenBuffers(1, &textureCoordBufferID); glBindBuffer(GL_ARRAY_BUFFER, textureCoordBufferID); glBufferData(GL_ARRAY_BUFFER, sizeof(textureCoords), textureCoords, GL_STATIC_DRAW); } - (void) createIndexBuffer { glGenBuffers(1, &indexBufferID); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, indexBufferID); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLubyte) * 16, indices, GL_STATIC_DRAW); }
The above VBO creation methods are called by the special AtlasLibrary class , which initializes each instance of TexturedQuad.
Firstly, the vertices are located in the following format:
// bottom left quad.vertices[0] = xMin; quad.vertices[1] = yMin; // bottom right quad.vertices[2] = xMax; quad.vertices[3] = yMin; // top left quad.vertices[4] = xMin; quad.vertices[5] = yMax; // top right quad.vertices[6] = xMax; quad.vertices[7] = yMax;
Secondly, the texture coordinates are located in the following format (inverted to reflect the OpenGL ES tendency to mirror):
// top left (of texture) quad.textureCoords[0] = uMin; quad.textureCoords[1] = vMax; // top right quad.textureCoords[2] = uMax; quad.textureCoords[3] = vMax; // bottom left quad.textureCoords[4] = uMin; quad.textureCoords[5] = vMin; // bottom right quad.textureCoords[6] = uMax; quad.textureCoords[7] = vMin;
... further, VBO creation methods are called (in AtlasLibrary)
[quad createVertexBuffers]; [quad createTextureCoordBuffers]; [quad createIndexBuffer];
Now meat and potatoes. Class SceneObject . SceneObjects are objects in the game that are renderable. They reference a TexturedQuad instance and contain information about rotation, translation, and scaling.
Here is the rendering method in SceneObject:
- (void) render { // binds texture in OpenGL ES if not already bound [[AtlasLibrary sharedAtlasLibrary] ensureContainingTextureAtlasIsBoundInOpenGLES:self.containingAtlasKey]; glPushMatrix(); glTranslatef(translation.x, translation.y, translation.z); glRotatef(rotation.x, 1, 0, 0); glRotatef(rotation.y, 0, 1, 0); glRotatef(rotation.z, 0, 0, 1); glScalef(scale.x, scale.y, scale.z); // change alpha glColor4f(1.0, 1.0, 1.0, alpha); // vertices glBindBuffer(GL_ARRAY_BUFFER, texturedQuad.vertexBufferID); glVertexAttribPointer(ATTRIB_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT), &texturedQuad.vertices[0]); // texture coords glBindBuffer(GL_ARRAY_BUFFER, texturedQuad.textureCoordBufferID); glVertexAttribPointer(ATTRIB_TEXTURE_COORD, 2, GL_FLOAT, GL_FALSE, sizeof(GL_FLOAT), &texturedQuad.textureCoords[0]); // bind index buffer array glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, texturedQuad.indexBufferID); // draw glDrawElements(GL_TRIANGLE_STRIP, sizeof(texturedQuad.indices) / sizeof(texturedQuad.indices[0]), GL_UNSIGNED_BYTE, texturedQuad.indices); glPopMatrix(); }
I have a strong feeling that either the array of indices is structured incorrectly or the glDrawElements (..) function is called incorrectly.
To answer this question, please:
- determine what I'm doing wrong, which will cause OpenGL ES not to draw my SceneObjects.
- indicate the correct way to do what I'm trying to do (according to my structure, please)
- provide any suggestions or links that may help (optional)
Thank you very much!