OpenGL-ES - correct approach to rendering a 2D game

166 Views Asked by At

I am making an Android game with 2D graphics, and I need an advice to how to correctly render it to get good performance. Currently the performance is really bad. Furthermore I want to know how to correctly move to using VBOs for rendering many sprites. Here are some facts that might pose constraints on the implementation:

  1. Every object in the game has it's own class which has it's own onDraw() function.
  2. The game screen contains 100,000 textured quads that need to be rendered. very small textures.
  3. Those 100,000 quads may change position or disappear.
  4. Some objects are very complex to draw (require changing blending modes and pixel tests) and require a lot of information from the object's data to be drawn correctly.

I have read almost all of the existing articles about speeding up performance and I realized moving to VBO is a good idea (since right now it uses vertex arrays). However they all were either too simple and didn't explain too good, or didn't satisfy all of my needs.

Here is where my problems start: 1. Is it better to keep everything in one VBO or keep a VBO per object or class? 2. When objects change positions, do I modify the texture coordinates and re-copy the VBO to the GPU again (and this can be done only from the gl thread), or do I call glTranslatef() before any object drawing and just specify it's index in the VBO? They also recommended to reduce the number of gl calls so it doesn't work together. 3. How do you render a frame quickly when there are many gl function calls before drawing each object?

The current approach is probably the worst you can find:

    private float vertices[] = 
    {
            -1.0f, -1.0f,  0.0f,        // V1 - bottom left
            -1.0f,  1.0f,  0.0f,        // V2 - top left
             1.0f, -1.0f,  0.0f,        // V3 - bottom right
             1.0f,  1.0f,  0.0f         // V4 - top right
    };

    private FloatBuffer textureBuffer;  
    private float texture[] = 
    {           

            0.0f, 1.0f,     // top left     (V2)
            0.0f, 0.0f,     // bottom left  (V1)
            1.0f, 1.0f,     // top right    (V4)
            1.0f, 0.0f      // bottom right (V3)
    };
    ...
    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(vertices.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());

    vertexBuffer = byteBuffer.asFloatBuffer();

    vertexBuffer.put(vertices);

    vertexBuffer.position(0);

    byteBuffer = ByteBuffer.allocateDirect(texture.length * 4);
    byteBuffer.order(ByteOrder.nativeOrder());
    textureBuffer = byteBuffer.asFloatBuffer();
    textureBuffer.put(texture);
    textureBuffer.position(0);

And the drawing code:

        gl.glBindTexture(GL11.GL_TEXTURE_2D,  MainProgram.glSurfaceView.renderer.ResourceIdToTexture(resourceId));
        gl.glEnableClientState(GL11.GL_VERTEX_ARRAY);
        gl.glEnableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
        gl.glFrontFace(GL11.GL_CW);
        gl.glVertexPointer(3, GL11.GL_FLOAT, 0, vertexBuffer);
        gl.glTexCoordPointer(2, GL11.GL_FLOAT, 0, textureBuffer);
        gl.glPushMatrix();
        gl.glTranslatef(glPos[0], glPos[1], -1.0f);
        gl.glScalef(glDim[0], glDim[1], 1.0f);
        gl.glRotatef(rotation, 0,0,-1);
        if(maskColor != null) maskColor.apply(gl);
        gl.glDrawArrays(GL11.GL_TRIANGLE_STRIP, 0, vertices.length / 3);
        if(maskColor != null) maskColor.restore(gl);
        gl.glPopMatrix();
        gl.glDisableClientState(GL11.GL_VERTEX_ARRAY);
        gl.glDisableClientState(GL11.GL_TEXTURE_COORD_ARRAY);
0

There are 0 best solutions below