Search code examples
androidopengl-esbitmaptextures

Android OpenGL ES 2.0 textures from png file are black


Im facing a problem with my OpenGL implementation I don't understand. I'm displaying a Sprite with three textures combined in FragmentShader. If I use bitmaps from android ressource as texture all works fine, but if I'm using the downloaded png equivalents and load them from file system my texture is displayed only black.

The textures are not power of 2 and not square, but as I said the implementation works if I copy the images to android ressource but in real world I need to download them.

This is my Code: Sprite Constructor:

final float[] spriteTextureCoordinates =
{                                               
        1f,  0f,
        1f, 1f,
         0f, 1f,
         0f,  0f
};

mCubeTextureCoordinates = ByteBuffer.allocateDirect(spriteTextureCoordinates.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer();
mCubeTextureCoordinates.put(spriteTextureCoordinates).position(0);

ByteBuffer dlb = ByteBuffer.allocateDirect(spriteCoords.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(drawOrder);
drawListBuffer.position(0);

int vertexShader = MyGLRenderer.loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode);
int fragmentShader = MyGLRenderer.loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode);

shaderProgram = GLES20.glCreateProgram();
GLES20.glAttachShader(shaderProgram, vertexShader);
GLES20.glAttachShader(shaderProgram, fragmentShader);

GLES20.glBindAttribLocation(shaderProgram, 0, "a_TexCoordinate");

GLES20.glLinkProgram(shaderProgram);
mTextureManager.loadDefaultTextures(mActivityContext, true);

onDraw:

GLES20.glUseProgram(shaderProgram);

mPositionHandle = GLES20.glGetAttribLocation(shaderProgram, "vPosition");

GLES20.glEnableVertexAttribArray(mPositionHandle);

GLES20.glVertexAttribPointer(mPositionHandle, COORDS_PER_VERTEX, GLES20.GL_FLOAT, false, vertexStride, vertexBuffer);

mTextureUniformHandle0 = GLES20.glGetUniformLocation(shaderProgram, "u_Texture0");
mTextureUniformHandle1 = GLES20.glGetUniformLocation(shaderProgram, "u_Texture1");
mTextureUniformHandle2 = GLES20.glGetUniformLocation(shaderProgram, "u_Texture2");
mTextureCoordinateHandle = GLES20.glGetAttribLocation(shaderProgram, "a_TexCoordinate");

GLES20.glUniform1i(mTextureUniformHandle0, 0);
GLES20.glUniform1i(mTextureUniformHandle1, 2);
GLES20.glUniform1i(mTextureUniformHandle2, 4);

GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureManager.getMapLayerTexture());

GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 2);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureManager.getRadarTexture(currentImageIndex));

GLES20.glActiveTexture(GLES20.GL_TEXTURE0 + 4);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextureManager.getGeoLayerTextureForZoomLevel(zoomStep));

mCubeTextureCoordinates.position(0);
GLES20.glVertexAttribPointer(mTextureCoordinateHandle, mTextureCoordinateDataSize, GLES20.GL_FLOAT, false, 0, mCubeTextureCoordinates);
GLES20.glEnableVertexAttribArray(mTextureCoordinateHandle);

mMVPMatrixHandle = GLES20.glGetUniformLocation(shaderProgram, "uMVPMatrix");

GLES20.glUniformMatrix4fv(mMVPMatrixHandle, 1, false, mvpMatrix, 0);

GLES20.glDrawElements(GLES20.GL_TRIANGLES, drawOrder.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);

GLES20.glDisableVertexAttribArray(mPositionHandle);

Shader:

private final String vertexShaderCode =
"attribute vec2 a_TexCoordinate;" +
"varying vec2 v_TexCoordinate;" +
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"void main() {" +
"  gl_Position = uMVPMatrix * vPosition;" +
    "v_TexCoordinate = a_TexCoordinate;" +
"}";

private final String fragmentShaderCode =
"precision mediump float;" +
"uniform sampler2D u_Texture0;" +
"uniform sampler2D u_Texture1;" +
"uniform sampler2D u_Texture2;" +
"varying vec2 v_TexCoordinate;" +
"void main() {" +
"vec4 texel0 = texture2D(u_Texture0, v_TexCoordinate);" +
"vec4 texel1 = texture2D(u_Texture1, v_TexCoordinate);" +
"vec4 texel2 = texture2D(u_Texture2, v_TexCoordinate);" +
"gl_FragColor = mix(mix(texel0, texel1, texel1.a),texel2,texel2.a);"+
"}";

Working texture loading:

 public  int[] loadTextures(final Context context, int... resIDs)
{
    final int[] textureHandle = new int[resIDs.length];

    GLES20.glGenTextures(resIDs.length, textureHandle, 0);

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

            final Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), resIDs[i], options);

            GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle[i]);

            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);

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


    return textureHandle;
}

an the not working one:

public synchronized int loadNewRadarLayerTexture(Context context, ImageData data) throws IOException {
    int textureID = data.getTextureID();
    if(textureID == 0) {
        final int[] textureHandle = new int[1];
        GLES20.glGenTextures(textureHandle.length, textureHandle, 0);
        textureID = textureHandle[0];
        if (textureID != 0) {
            final BitmapFactory.Options options = new BitmapFactory.Options();
            options.inScaled = false; // No pre-scaling

            File directory = context.getDir(RRD.DIR,
                    Context.MODE_PRIVATE);
            File image = new File(directory, data.getFile());

            Bitmap bitmap = BitmapFactory.decodeFile(image.getPath(),options);

            // 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_MIN_FILTER, GLES20.GL_NEAREST);
            GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
            GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
            Log.d("OpenGL","Error:"+GLES20.glGetError());
            bitmap.recycle();
        }
        if(textureID == 0){
            throw new RuntimeException("Error loading texture.");
        }

        data.setTextureID(textureID);

    }
    return textureID;
}

if I use the texture generated by the first method, all works fine. if i use the second method my whole texture seems to be black


Solution

  • found the error while reading this topic: Threading textures load process for android opengl game I was loading the texture after the download was complete. I was in the right thread, but not during onSurfaceChanged oder onDrawFrame Method, cause of that the texture wasn't correctly uploaded.

    First solution is to check in onDrawFrame if texture is loaded and to load then the texture if not.