Android OpenGL ES 2 - Blending seems to always be additive - android

I can't seem to get my blending properly working in OpenGL ES 2 on Android. What I have are textures with alpha channels that I want to appear with the corresponding alpha. The blending appears as additive even when the top drawn object has alpha of 1.0. In my fragment shader I hard-coded a value of 1.0 for the alpha, and realized it seems to be using color, not alpha values.
For example, it looks like this :
Instead of this :
I am drawing in the correct order, in this example the blue should be fully opaque over top of the gray square. I have tried multiple blending modes (one,one), (alpha,alpha), etc., multiple draw orders, and using and not using depth test. I have tried random blend modes that yield incorrect results, so the blending is changing when I set it.
I believe the problem is that opengl is blending additive color. (Alpha, Alpha) makes sense to me, and when I explicitly set alpha to 1.0 in the shader, I would think I would get a square (the actual shape the texture is projected on) that has a blue circle on it. This not happening puzzles me, I guess I don't understand the sfactor and dfactor blending function enough.

Are you using the Android Bitmap class to load your textures?
Using GLUtils.texImage2D() to load alpha textures from a Bitmap on Android is broken. This is a problem that Google really should document better. The problem is that the Bitmap class converts all images into pre-multiplied format, but that does not work with OpenGL ES unless the image is completely opaque.
This article gives more detail on this click here.

Related

Using texture image with alpha makes mesh 'see through'

I am rendering an obj file in OpenGL ES 2.0 on Android with Back-Culling enabled. Only some part (the necklace around the neck) of the texture image actually has alpha.
When rendering only the mesh, it looks fine :
However, on enabling the texture, I am able to see through the mesh onto the other side. You can see below that the right hand which is behind the body also becomes visible. Any ideas what might be going wrong ?
Edit:
I have tried the following :
Enabling/Disabling back face culling
Checking the ordering of vertices
Checking if normals are inside at some points
But nothing seem to work. Any other direction would be appreciated.
Edit 2 :
I opened up the texture image and filled all the transparent area with black color by saving it as no alpha layer in a image editing program. And this is how it looks now :
Transparency issue is gone, but then I won't be able to see the necklace properly.
Edit 3 : Can Alpha-blending and the Z-buffer be an issue as described in the link ? It claims 'The Z buffer doesn't work for transparent polygons.'
There are quite a few solutions for the conflict of the depth buffer and alpha blending.
In your case it might be best to simply disable the blending and discard the pixels in the fragment shader.
You probably just have some semitransparent pixels on the borders of the accessory the rest is either 1.0 or 0.0. So maybe a pass such as if alpha < 0.5 discard else set alpha to 1.0.
Another way would simply make sure that those blended objects are drawn last. If you have only one of such objects on the scene it should work. But if you have multiple one behind the other you may again encounter issues.

Android Blend transparent png image on existing background

I am trying to create a Analog Meter in OpenGL ES 1.x on Android. I have created a simple circle using Midpoint Theorem in green color. Now I want to place some numbers around the circle for Meter readings. Since OpenGL has no native text rendering API, I am trying to load an PNG image like this with the reading on it and the rest of image is transparent.
Now what parameters I must pass to glBlendFunc() function to achive this.
I have tried many different combinations but nothing works.
This is a common problem on Android. You can't use the Android Bitmap class to load textures that have transparent areas in them. This is because Bitmap follows the Porter-Duff specification for alpha blending, and Bitmap optimizes images with per-pixel alpha by storing them in the premultiplied format (A, R*A, G*A, B*A). This is great for Porter-Duff but not for OpenGL, which requires a non-premultiplied (ARGB) format. This means that the Bitmap class can only be used with textures that are completely opaque (or have no per-pixel alpha). This article details:
http://software.intel.com/en-us/articles/porting-opengl-games-to-android-on-intel-atom-processors-part-1
Just try passing the Alpha Blending values which are:
glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
I hope it helps.
I don't think(even at 2.2)Alpha PNGs are problem for the Android Bitmap loading algorithm.

Sprite Opacity using OpenGL ES 2.0 on Android

I'm trying to get my point sprites to display with the correct opacity.
Originally, I was getting my sprite texture on a black square.
So, I added the following to my fragment shader:
"if(color.a < 0.5) "+
"discard;"+
Now, this does seem to work, in that my sprite displays without the black background, however, my texture itself is 'partially transparent' - and it isn't showing this partial transparency, it is appearing solid. It's a bit difficult to explain, but I hope you understand what I mean. If I draw the same texture using canvas/surfaceview, it displays correctly.
Basically I'm trying to get my textures to display in their original format (ie as they do in the software in which they were created - ie, the Gimp / photoshop etc).
Would appreciate any help - thanks
First make sure your textures are loaded from transparent pngs through a Bitmap with either RGBA_8888 or RGBA_4444 configuration, so you don't lose the alpha channel.
Second you need to enable GL_BLEND with the glEnable() command. On Android you will write it like this: GLES20.glEnable(GLES20.GL_BLEND);. This allows you to blend the already drawn color with the new color, achieving a transparent look.
The blending function should be set to GL_ONE, GL_ONE_MINUS_ALPHA for regular transparency: glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
GL_SRC_ALPHA, GL_ONE_MINUS_ALPHA for regular transparency: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
Finally, you do not need to use discard, just set the gl_FragColor to a 4-component vector with the alpha in the fourth channel (which is what you get when reading a texture from a sampler), e.g. you could just do gl_FragColor = texture2D(sampler, texCoord); if you wanted to.
You will most likely have to turn off depth-testing with glDisable(GL_DEPTH_TEST) to avoid problems with unsorted triangles.
You can read a little bit more about transparency here.

Creating a GL_MAX blend equation equivalent using other methods

I'm trying to figure a way to recreate or at least have a similar result to the max clamp blend equation in OpenGl es 2.0 on Android devices.
Unfortunately, glBlendEquation(GL_MAX_EXT) is not supported on Android. GL_MAX enum is defined in the gl header in Android but when executing, the result is a GL_INVALID_ENUM​, 0x0500 error.
I have a solution using shaders and off screen textures where each render ping-pongs back and forth between textures using the shader to calculate the max pixel value.
However, this solution isn't fast enough for any real time execution on most Android devices.
So given this limitation, is there any way to recreate a similar result using just different blend equations and blend factors?
I have tried many blend function combinations, the closest have been:
glBlendFunction(GL_SRC_ALPHA, GL_ONE_MINUS_ALPHA) : This comes close but textures become too transparent. Textures with low alpha values are difficult to see.
glBlendFunction(GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA) : This also comes some what close but the alpha accumulates too much and the colors become darker than intended.
If you could do GL_MAX blending without needing a special blend function... OpenGL would never have added it in the first place. So your options are to do without or to use your shader method.

Seamlessly layering transparent sprites in OpenGL ES

I am working on an Android app, based on the LibGDX framework (Though I don't think that should affect this problem too much), and I am having trouble finding a way to get the results I want when drawing using transparent sprites. The problem is that the sprites visibly layer on top of each other where they overlap, similar to what is displayed in this image :
This is pretty unsightly for some of what I want to do, and even completely breaks other parts. What I would like them to do is merge together seamlessly, like so:
The only success I have had thus far is to draw the entire sequence of sprites on a separate texture at full opacity, and then draw that texture back with the desired opacity. I had this working moderately well, and I could likely make it work for most of what I need it to, but the large problem right now is that these things are dynamically drawn onto the screen, and the process of modifying a fairly large texture and sending it back are pretty taxing on mobile devices, and causes an unacceptable level of performance.
I've spent a good chunk of time looking for more ideal solutions, including experimenting with blend modes and coming up with quirky formulas that balanced out alpha and color values in ways to even things out, but nothing was particularly successful. My guess is that the only viable route for this is the previously mentioned way of creating a texture and applying the alpha difference to that, but I am unsure of the best way to make that work with lower powered mobile devices.
There might be a few other ways to do this: The most straight forward would be to attach a stencil buffer and draw circles to stencil first and then draw a full screen rect with desired color+alpha with the stencil, this should be much faster then some FBO with a separate texture.
Another thing might work is drawing those circles first with disabled blend and then your whole scene over it with inverted "blendFunc" but do note it might be impossible if other elements also need blending.
3rd instead of using stencil you could just use the alpha channel of your render buffer. Just use a color mask to draw only to alpha and draw the circles, then reenable RGB on color mask and draw the fullscreen rect using appropriate "blendFunc" also note here that if previous shapes have used blend you will need to clear the alpha to 1.0 before doing this (color mask to alpha only, disabled blend, draw full screen rect with color that has alpha set to 1.0)

Categories

Resources