Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Vertex Buffer Objects (VBO) in OpenGL es (Iphone) to improve performance

i am writing a simple application for iphone wich displays a rotating cube. I am using glDrawElements (openGl es) to draw the triangles of the cube and to rotate it. I've noticed that when i increase the size of the cube to 100*100*100 voxels the display performance gets bad (clarification: i dont draw the whole cube, i draw only it's outline (mesh). I get all the triangles of the mesh by applying the marching cubes algorithm on the cube ... eventually i get something like 120k triangle to draw which are represented by 40k vertices)...

To draw the cube i hold an array of vertices, array of colors and an array if indices to vertices. The indices array defines the triangles of vertexes to be drawn. It is passed to glDrawElements as a param.

Recently i've red about a different technique to draw the cube using Vertex Buffer Objects (VBO). I've implemented it but the Performance was Even worser then by previous technique

Here is my code, Maybe i've done a silly mistake, Any improvement suggestions will be well received :)

by the way, i used the following articles as references:

http://playcontrol.net/ewing/jibberjabber/opengl_vertex_buffer_object.html http://iphonedevelopment.blogspot.com/2009/05/opengl-es-from-ground-up-table-of.html

//all the 7 variables down are initialized by other function at the beginning 
GLushort* meshIndices;    //array of indices (ushort)
MeshVertex* meshVertices; //array of vertices (floats)
Color3D* meshColors;      //array of colors  (floats)

int numberOfTriangles; //number of Triangle to draw the cube
int numberOfVertices;  //number of all Vertices to draw the cube
int numberOfIndices;   //number of all Indices to draw the cube, each 3 indices define 3 vertices which define 1 triangle
int numberOfColors;    //number of colors used to draw the cube. each color is of tip Color3D

//in this function i initializing the VBOs 
- (void) setupMeshVBOs { 

    glGenBuffers(1, &triangleVBO);
    glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);

    const GLsizeiptr vertex_size = numberOfVertices * sizeof(MeshVertex);
    const GLsizeiptr color_size = numberOfColors * sizeof(Color3D);

    glBufferData(GL_ARRAY_BUFFER, vertex_size + color_size, 0, GL_STATIC_DRAW);

    GLvoid* vbo_buffer = glMapBufferOES(GL_ARRAY_BUFFER, GL_WRITE_ONLY_OES); 
    memcpy(vbo_buffer, meshVertices, vertex_size);

    GLbyte* temp = (GLbyte*)vbo_buffer;
    temp += vertex_size;
    memcpy((GLvoid*)temp, meshColors, color_size);

    glUnmapBufferOES(GL_ARRAY_BUFFER); 

    glVertexPointer(3, GL_FLOAT, 0, (GLvoid*)((char*)NULL));

    glColorPointer(4, GL_FLOAT, 0, (GLvoid*)((char*)NULL+vertex_size));

    glGenBuffers(1, &triangleIBO);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleIBO);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, numberOfIndices * sizeof(GLushort), meshIndices, GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}

//this function is the one which draws the VBOs
- (void)drawView:(GLView*)view;
{

    static GLfloat rot = 0.0;


    glLoadIdentity();
    glTranslatef(-1.0f,-2.0f,-20.0f);
    glRotatef(rot,1.0f,1.0f,1.0f);
    glClearColor(0.7, 0.7, 0.7, 1.0);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        glBindBuffer(GL_ARRAY_BUFFER, triangleVBO);
        glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, triangleIBO);

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_COLOR_ARRAY);

        glDrawElements(GL_TRIANGLE_STRIP, numberOfIndices, GL_UNSIGNED_SHORT, (GLvoid*)((char*)NULL));

        glDisableClientState(GL_VERTEX_ARRAY);
        glDisableClientState(GL_COLOR_ARRAY);

    static NSTimeInterval lastDrawTime;
    if (lastDrawTime)
    {
        NSTimeInterval timeSinceLastDraw = [NSDate timeIntervalSinceReferenceDate] - lastDrawTime;
        rot+=50 * timeSinceLastDraw;                
    }
    lastDrawTime = [NSDate timeIntervalSinceReferenceDate];
}
like image 799
alexpov Avatar asked Aug 27 '11 14:08

alexpov


1 Answers

Firstly, to draw a 100x100x100 map of cubes, you shouldn't draw each cube individually. If have, say, six boxes in a row then you should draw them as one long cuboid for twelve triangles total. Any cube that is surrounded on six sides definitely doesn't need to be considered. You should apply strategies like those to reduce your geometry count significantly.

Apple's advice on GL optimisation is here. The summary version is that you should aim to use VBOs with aligned, interleaved data, using the smallest acceptable types. So, implicitly, reading data is a bottleneck. Using two separate lists could conceivably be halving your geometry input rate, and using floats is likely to be slowing it further.

like image 53
Tommy Avatar answered Sep 23 '22 16:09

Tommy