Search code examples
opengl-esglslshadertexturesfragment-shader

How to setup the fragment shader for multiple textures on multiple objects in OpenGLES?


I try to bind a texture to one object and another texture to a next object. I asked here in stackoverflow almost the same question, but the difference in that time was, that I had just one texture and multiple objects. How to bind texture just to one object in OpenGLES? It worked for one texture and multiple objects, but now I have multiple textures and multiple objects. I followed the advice in the answers, but I strongly believe that this time the problem is about the fragment shader.

 @Override
public void onDrawFrame(GL10 gl) {
    GLES20.glClear(GL10.GL_COLOR_BUFFER_BIT);


    synchronized (mediaPlayerObject) {
        surfaceTextureMediaPlayer.updateTexImage();
        mediaPlayeUpdate = false;
    }


    vertexBuffer.position(0);
    GLES20.glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDETEXTURE, vertexBuffer);
    vertexBuffer.position(TEXTURE_COMPONENT_COUNT);
    GLES20.glVertexAttribPointer(aTextureCoordinatesLocation, TEXTURE_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDETEXTURE, vertexBuffer);

    GLES20.glEnableVertexAttribArray(aPositionLocation);
    GLES20.glEnableVertexAttribArray(aTextureCoordinatesLocation);

    GLES20.glUniform1i(textureUnitLocation2, 1);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
    GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textures[1]);

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
    GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);

    GLES20.glDisableVertexAttribArray(aPositionLocation);
    GLES20.glDisableVertexAttribArray(aTextureCoordinatesLocation);



    synchronized (camerObject) {
        surfaceTextureCamera.updateTexImage();
        cameraUpdate = false;
    }






    vertexBuffer2.position(0);
    GLES20.glVertexAttribPointer(aPositionLocation, POSITION_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDETEXTURE, vertexBuffer2);
    vertexBuffer2.position(TEXTURE_COMPONENT_COUNT);
    GLES20.glVertexAttribPointer(aTextureCoordinatesLocation, TEXTURE_COMPONENT_COUNT, GLES20.GL_FLOAT, false, STRIDETEXTURE, vertexBuffer2);

    GLES20.glEnableVertexAttribArray(aPositionLocation);
    GLES20.glEnableVertexAttribArray(aTextureCoordinatesLocation);

    GLES20.glUniform1i(textureUnitLocation, 0);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textures[0]);

    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
    GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, 0);

    GLES20.glDisableVertexAttribArray(aPositionLocation);
    GLES20.glDisableVertexAttribArray(aTextureCoordinatesLocation);

Here the fragment shader:

    #extension GL_OES_EGL_image_external : require
precision mediump float;
uniform samplerExternalOES u_Texture;
uniform samplerExternalOES b_Texture;

varying vec2 v_TextureCoordinates;

void main() {

    gl_FragColor = texture2D(u_Texture, v_TextureCoordinates) * texture2D(b_Texture, v_TextureCoordinates);
}

Solution

  • There is no need for a second texture sampler in the fragment shader, so delete b_Texture. It is sufficient to bind the texture object to the texture unit and to set the index of the texture unit to the texture sampler uniform:

    #extension GL_OES_EGL_image_external : require
    precision mediump float;
    uniform samplerExternalOES u_Texture;
    
    varying vec2 v_TextureCoordinates;
    
    void main() {
    
        gl_FragColor = texture2D(u_Texture, v_TextureCoordinates);
    }
    

    Draw 1st object:

    GLES20.glUniform1i(textureUnitLocation, 1);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE1);
    GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textures[1]);
    
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
    

    Draw 2nd object:

    GLES20.glUniform1i(textureUnitLocation, 0);
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GL_TEXTURE_EXTERNAL_OES, textures[0]);
    
    GLES20.glDrawArrays(GLES20.GL_TRIANGLE_FAN, 0, 6);
    

    Note, it is not necessary to use 2 different texture units. You can use GL_TEXTURE0 in both cases.