OpenGL ES 2.0 PNG alpha channel

DaeKo picture DaeKo · Aug 17, 2011 · Viewed 10.5k times · Source

I am just learning to work with OpenGL ES 2.0 for Android. I have been trying to simply display a texture on the middle of the screen, which was easy enough, but I cannot seem to get the PNG alpha to work properly. The image will either show with a black background, or the entire image will be blended into the background color slightly, depending on the settings I use.

The actual tutorials I have followed to get to this point never worked with transparency, so I have tried to work in code I have found by searching around, and likely have just missed one important step. I have searched quite a lot to figure this problem out though, and I have not seen any answers that had something my setup does not. I have tried every combination of glBlendFunc and what not with no luck.

I figured if I tried to paste in all of the code that may be related to this, the question would seem very bloated, so I will be happy to post any bits of code you guys ask for. I'd greatly appreciate any ideas for what I should try next.

EDIT :: Here is my fragment shader, which is what I believe to be the cause. This is the only part that I have never really found a decent example for working with transparency, and everything else matches what I have seen elsewhere.

        final String fragmentShader =           
        "precision mediump float;       \n"  
        + "varying vec2 v_Color;          \n"     
        + "uniform sampler2D s_baseMap;   \n"
        + "void main()                    \n"     
        + "{                              \n"
        + "  vec4 baseColor;              \n"
        + "  baseColor = texture2D( s_baseMap, v_Color );   \n"
        + "   gl_FragColor = baseColor;     \n"    
        + "}                              \n"; 

It never does anything with the alpha explicitly, it is from an example that doesn't use it after all, but I still don't know much about fragment shaders and because it seemed to "sort of" work when it blends the image into the background, I figured it was working with the alpha in some form and I just had something set wrong.

EDIT :: Here is the "loadTexture" method. It is roughly the same as the example from the openGL ES 2.0 book that I am trying to learn from, with a few alterations that seem to get the image closer to working properly.

    private int loadTexture ( InputStream is )
{
    int[] textureId = new int[1];
    Bitmap bitmap;
    bitmap = BitmapFactory.decodeStream(is);
    byte[] buffer = new byte[bitmap.getWidth() * bitmap.getHeight() * 4];

    for ( int y = 0; y < bitmap.getHeight(); y++ )
        for ( int x = 0; x < bitmap.getWidth(); x++ )
        {
            int pixel = bitmap.getPixel(x, y);
            buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF);
            buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF);
            buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF);
        }

    ByteBuffer byteBuffer = ByteBuffer.allocateDirect(bitmap.getWidth() * bitmap.getHeight() * 4);
    byteBuffer.put(buffer).position(0);

    GLES20.glGenTextures ( 1, textureId, 0 );
    GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, textureId[0] );

    GLES20.glTexImage2D ( GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, bitmap.getWidth(), bitmap.getHeight(), 0, 
                          GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, byteBuffer );

    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 );
    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 );

    return textureId[0];
}

I understand what the code is doing, but admittedly it still confuses me a bit so I may just be missing something obvious due to my lack of knowledge.

I don't see any other parts of my code that seem like they could cause the kind of problems I am having, but programming is always full of the unexpected (Especially in the world of OpenGL it seems) so if you think something else is the cause I'll be sure to post that for you as well. Sorry for all the trouble!

Answer

idunnololz picture idunnololz · Jan 27, 2012

Change

 for ( int y = 0; y < bitmap.getHeight(); y++ )
    for ( int x = 0; x < bitmap.getWidth(); x++ )
    {
        int pixel = bitmap.getPixel(x, y);
        buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF);
        buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF);
        buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF);
    }

into

 for ( int y = 0; y < bitmap.getHeight(); y++ )
    for ( int x = 0; x < bitmap.getWidth(); x++ )
    {
        int pixel = bitmap.getPixel(x, y);
        buffer[(y * bitmap.getWidth() + x) * 4 + 0] = (byte)((pixel >> 16) & 0xFF);
        buffer[(y * bitmap.getWidth() + x) * 4 + 1] = (byte)((pixel >> 8) & 0xFF);
        buffer[(y * bitmap.getWidth() + x) * 4 + 2] = (byte)((pixel >> 0) & 0xFF);
        buffer[(y * bitmap.getWidth() + x) * 4 + 3] = (byte)((pixel >> 24) & 0xFF);
    }

to include the alpha information then simply add

GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
GLES20.glEnable(GLES20.GL_BLEND); 

right before you draw the texture. Remember to disable GL_BLEND once you are done.