OpenGL ES 2.0 PNG Alpha Channel

I just learned to work with OpenGL ES 2.0 for Android. I'm trying to just display a texture in the middle of the screen, which was simple enough, but I can't get PNG alpha to work correctly. The image will either display a black background, or the whole image will be slightly mixed with the background color, depending on the settings that I use.

The actual tutorials that I completed to get to this point never worked with transparency, so I tried working with the code I found while searching, and probably just skipped one important step. I searched quite a bit to understand this problem, though, and I did not see any answers that had something that my installation did not have. I tried every combination of glBlendFunc and that no luck.

I decided that if I try to insert all the code that might be related to this, the question will seem very bloated, so I will be happy to post any code snippets that you guys are asking. I would really appreciate any ideas on what I should try next.

EDIT :: Here is my fragment shader, which I believe is the reason. This is the only part on which I have never found a decent example for working with transparency, and everything else matches what I saw 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 explicitly with alpha, this is from an example that doesn't use it in the end, but I still don't know much about fragment shaders and because it seemed like a “kind of” work when it mixes an image in the background, I figured that he worked with alpha in one form or another, and I just had something wrong.

EDIT :: Here is the loadTexture method. This is about the same as the example from the openGL ES 2.0 book I'm trying to learn with, with some changes that seem to bring 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 does, but admittedly, it still baffles me, so I can just miss something obvious due to lack of knowledge.

I don’t see any other parts of my code that seem like they may cause problems that I am having, but programming is always full of surprise (especially in the OpenGL world), so if you think something else is the reason, by which I will send it for you. Sorry for all the problems!

+8
android transparency opengl-es png alpha
source share
3 answers

Edit

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

in

  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 alpha info just 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 as soon as you are done.

+9
source share

Most likely you want to use glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) as a blend function, and you should also write the alpha value of the texture to the output variable of the gl_FragColor shader.

In order to work, your loaded texture data must contain an alpha value, and you must use a texture format that supports the alpha channel (RGBA, RGBA8, etc.).

You can verify this by simply directing the alpha value into the RGB color components and checking the image you get.

EDIT:

In the image upload code, you will forget to copy through the alpha channel! Try to suggest that davebytes gives.

+3
source share

your initial shader is fine. alpha is inherent in color operations; it simply cannot be used depending on blend / mode / etc.

given that your texture goes black, if you do fragcolor = base.aaa, this means that your texture data is “bad”.

looking at your texture, yes, that’s wrong. you never copy alpha, but rgb only. assuming java clears the byte array to 0s, all alpha will be zero, which will lead you to your black box, which will cause the image to disappear when alpha blending is turned on.

To simplify your life, instead of copying everything manually, you can simply load the bitmap in normal mode and use the GLUtils helper to load instead of using glTexImage2d directly:

  bitmap = BitmapFactory.decodeStream(is); GLES20.glGenTextures ( 1, textureId, 0 ); GLES20.glBindTexture ( GLES20.GL_TEXTURE_2D, textureId[0] ); GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0); 

Something like that. Then turn on blending, use src + invsrc blending mode, if you do not pre-multiply, and render, you should get the desired result.

+1
source share

All Articles