Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to manage multiple textures in OpenGL ES 2.0?

I have a OpenGL ES 2.0 app with 6 different textures. What I need is to draw and move them all at the same time. I was able to do it, but the movement was laggy because I was loading the bitmaps into the textures all the time. For each texture, I do the following on the Render method:

    setupImage(texture1);
    GLES20.glVertexAttribPointer(mPositionHandle, 3, GLES20.GL_FLOAT, false, 0, vertexBufferT1);
    GLES20.glVertexAttribPointer(mTexCoordLoc, 2, GLES20.GL_FLOAT, false, 0, uvBufferT1);
    GLES20.glDrawElements(GLES20.GL_TRIANGLES, indicesT1.length, GLES20.GL_UNSIGNED_SHORT, drawListBufferT1);

And on the setupImage method, I do this:

    // Create the bitmap
    int id = mContext.getResources().getIdentifier("drawable/texture1", null, mContext.getPackageName());
    Bitmap bmp = BitmapFactory.decodeResource(mContext.getResources(), id);

    // Bind texture to texturename
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);

    // Set filtering
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);

    // Set wrapping mode
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
    GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);

    // Load the bitmap into the bound texture.
    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bmp, 0);

    // Free bitmap
    bmp.recycle();

This is obviously wrong. However, I don't know how to load each bitmap into a different texture and then how can I switch the active texture on the Render method.

So, how can I achieve this, in order to display and move all the six textures and have a fluid movement?

like image 776
David Matos Avatar asked Mar 16 '16 12:03

David Matos


1 Answers

You are right, what you're doing is very wasteful. An easy way to maintain the textures is to simply use that textures[] array in a smarter way.

Ever wonder why that variable is an array of size 1? Well, you can use it to hold more than 1 texture! Simply define it as a larger array (size 6 for you). Once you do this, you will be able to load multiple bitmaps into textures when the app starts and then just bind the correct texture when you're about to draw it.

Here's an example:

private int[] textures = new int[6];

private void loadTexture(Bitmap bitmap, int textureIndex) {
    GLES20.glGenTextures ( 1, textures, textureIndex );

    GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, textures[textureIndex] );

    //.. call glTexParameter as needed

    GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
}

The code above should be called once, when the app starts up, for every bitmap you want to load as a texture. If you have many bitmaps, you might want to consider some sort of just-in-time texture loading, and unloading - but for your needs, it should be enough to just load them all at once.

Later, when you're about to draw a certain texture, make sure you first bind the correct one:

GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[textureIndex]);

This will simply tell the OpenGL layer which pre-loaded texture it's going to be using for the up-coming draw call. Be sure to call this before each draw to ensure you draw the correct texture each time. Note that at this point, OpenGL will not re-create the whole texture, but rather, just use the already loaded one, making it very efficient.

like image 119
Gil Moshayof Avatar answered Nov 11 '22 15:11

Gil Moshayof