简体   繁体   中英

Android: How to Change OpenGL ES Texture Image Dynamically

I'm trying to change the texture image displayed on an object in my opengl view in response to a button click. Currently, when the user presses a button I set a flag to true in my OpenGL Renderer thread. My cross-thread communication seems fine: I am able to successfully toggle flag variables in the Renderer thread at will. My problem seems to be with the Open GL onDraw() workflow, I can't figure out how to systematically change a texture on an object after a texture has already been set during the Renderer's initial onSurfaceCreated() execution.

It seems that fretBoardTexture = new OpenGL_TextureData(mActivityContext, R.drawable.dark_wood); never works outside of onSurfaceCreated(), why?

Below is the code i've tried. Am I missing a sequence of GLES20() method invocations somewhere?

OpenGL Renderer Class

 private int chosenWoodColor = 1;

        public void onSurfaceCreated(GL10 glUnused, EGLConfig config) {
            ...
            loadFretBoardTexture();  //this call works: it succeeds in changing texture
        }

        public void onDrawFrame(GL10 glUnused) {
                if (flag){    
                    loadFretBoardTexture(); //this call fails: it never changes the texture
                }
                ...

                //***Fretboard OpenGL_TextureData Binding***
                GLES20.glActiveTexture(GLES20.GL_TEXTURE1);

                // Bind the texture to this unit.
                GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, fretBoard._textureID);

                //Draw Background
                Matrix.setIdentityM(mModelMatrix, 0);
                Matrix.translateM(mModelMatrix, 0, 0.0f, 0.0f, -1.0f);
                drawFretBoard(); //draw the fretboard
                ...
        }

        public void loadFretBoardTexture(){
                switch (chosenWoodColor){
                    case 1:
                        fretBoardTexture = new OpenGL_TextureData(mActivityContext, R.drawable.dark_wood);
                        break;
                    case 2:
                        fretBoardTexture = new OpenGL_TextureData(mActivityContext, R.drawable.medium_wood);
                        break;
                    case 3:
                        fretBoardTexture = new OpenGL_TextureData(mActivityContext, R.drawable.light_wood);
                        break;
                }
                setFretboardTextureRefresh(false);
                return;
            }

Texture Data Helper Class

public class OpenGL_TextureData {
    public int textureID;
    public float imageWidth, imageHeight;

    public OpenGL_TextureData(Context context, int resourceId) { //constructor
        final int[] textureHandle = new int[1];

        GLES20.glGenTextures(1, textureHandle, 0);

        if (textureHandle[0] != 0) {
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inScaled = false;   // No pre-scaling

            // Read in the resource
            final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);

            //fetch texture image width & height
            imageWidth = options.outWidth;
            imageHeight = options.outHeight;

            // Bind to the texture in OpenGL
            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[0]);

            // Set filtering
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
            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);

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

            // Recycle the bitmap, since its data has been loaded into OpenGL.
            bitmap.recycle();
        }

        if (textureHandle[0] == 0) {
            throw new RuntimeException("Error loading texture.");
        }

        textureID = textureHandle[0];
    }
}

Solved.

The problem was that I was creating a new texture object and loading a bitmap to it, but since the texture object was already created in my onSurfaceCreated() method this was undesired: I really just needed to load a bitmap onto the already existing texture object.

I added the following method to my Texture data helper class:

public void updateTexture(Context context, int resourceId) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inScaled = false;   // No pre-scaling
        final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resourceId, options);  //Read in the resource
        GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 1);
        // Load the bitmap into the bound texture.
        GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
        bitmap.recycle();
    }

Inspiration drawn from here

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM