OpenGL transparent images have black in them - android

I am working on a game for Android and I was wondering why whenever I draw images with transparency there seems to always be some black added to the transparent parts. This happens all over and makes some of my effects look strange.
Here is an example. The two circles are only white images with a blur but you can see when one overlaps the other it has a shadow. If I overlap two of the circles say in Inkscape I get pure white where they overlap.
I am using
GLES20.glEnable(GLES20.GL_BLEND);
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
for my blending.
Any idea why this happens and how I can avoid it?
Edit: the only thing I can think of is that the two images have the same z so maybe they are blending only with the background instead of each other?
Edit:
I changed
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
to
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_DST_ALPHA);
Here is the result I was looking for.
The only thing now is that the transparent images that I had that have a transparent black in them are ignored, which makes sense because I think the destination alpha is 1. Why would One minus source add that gray?

I figured out how to fix it.
I changed
GLES20.glBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
to
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
It turns out that Android pre-multiplies the alpha of textures of PNG images when you load it (making white turn gray).
I added
vColor.r = vColor.r * vColor.a;
vColor.g = vColor.g * vColor.a;
vColor.b = vColor.b * vColor.a;
to my vertex shader to do the multiplying for my other colors.

Are you sure your content is correct? If you don't want the circles to produce any black color the color values in the image should be completely white, and the alpha channel should define the shape of the circle. Now it looks like the image has a white circle with both alpha channel and the color value fading to zero, which leads to a halo.

Are you using linear sampling? My thought could be if you have a very small image (less than say 30-40 pixels in dimension), you could be getting interpolated alpha values between the inside of the circle (alpha = 1) to the outside of the circle (alpha = 0). This would give you intermediate alpha values that result in the kind of blur effect.
Try the following code when you have the circle texture bound:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
Maybe you can host the actual texture that you're using such that we can inspect it? Also please post your drawing code if this doesn't help.

You can also divide by alpha, because, the problem is, when you export your textures, Image processing software may pre-multiply your Alpha channel. I ended up with alpha division into my fragment shader. The following code is HLSL, but you can easily convert it to GLSL:
float4 main(float4 tc: TEXCOORD0): COLOR0
{
float4 ts = tex2D(Tex0,tc);
//Divide out this pre-multiplied alpha
float3 outColor = ts.rgb / ts.a;
return float4(outColor, ts.a);
}
Note that this operation is lossy, very lossy and even if it will most likely suffice in cases such as these, it's not a general solution. In your case you can totally ignore the COLOR and serve original alpha AND white in your fragment shader, e.g. return float4(1,1,1,ts.a); (convert to GLSL)

Related

OpenGL ES 2 Texture atlas bleeding edge

Currently working on video games project.
When I get:
Matrix.orthoM(projectionMatrix, 0, 0, widthwindows, heightwindows, 0, -1, 3);
Everything looks ok. But when the variable widthwindows is different from the real screen resolution now I get this effect.
I can't use precited solution from other topic because some of my tiles are curve or whatever so even with -0.5 pixel there are no effect on them they still get transparency around them (and even some tiles aren't in taking 64*64, but 12*64 for instance, so -0.5 pixel get no effect).
You might want to work with PMA(Pre Multiplied Alpha).
When you draw a sprite with transparency you many times use a Normal blending mode.
A normal blending mode takes the sprite's pixel color multiplies it by the Alpha of that pixel and adds it to the background pixel color multipled by 1 compliment of the source pixel alpha.
This works most of the time however when scaling and filtering the sprite this might cause semi transparent pixels to appear darker than they should.
In order to solve this you use PMA.
Since in the blending you are going to multiply the sprite's color with the sprite's alpha, you can instead store the pixel color already multiplied by it's alpha.
Now the blending mode will look like this... Add PMA pixel color(without multiplying the alpha) to the background color multiplied by 1's compliment of the source pixel alpha.
In GLES 2 the Normal blending mode will be like this:
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
The PMA blending mode will look like this:
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
Hope this solves your issue.

Android OpenGL2.0 intersection between two textures

I'm making game in OpenGL2.0 and I want to check are two sprites have intersection but i don't need to check intersection between two rectangles.I have two sprites with texture,some part of texture is transparent,some not. I need to check intersection between sprites only on not trasnparent part.
Example: http://i.stack.imgur.com/ywGN5.png
The easiest way to determine intersection between two sprites is by Bounding Box method.
Object 1 Bounding Box:
vec3 min1 = {Xmin, Ymin, Zmin}
vec3 max1 = {Xmax, Ymax, Zmax}
Object 2 Bounding Box:
vec3 min2 = {Xmin, Ymin, Zmin}
vec3 max2 = {Xmax, Ymax, Zmax}
You must precompute the bounding box by traversing through the vertex buffer array for your sprites.
http://en.wikibooks.org/wiki/OpenGL_Programming/Bounding_box
Then during each render frame check if the bounding boxes overlap (compute on CPU).
a) First convert the Mins & Maxs to world space.
min1WorldSpace = modelViewMatrix * min1
b) Then check their overlap.
I need to check intersection between sprites only on not trasnparent part.
Checking this test case maybe complicated depending on your scene. You may have to segment your transparent sprites into a separate sprite and compute their bounding box.
In your example it looks like the transparent object is encapsulate inside an opaque object so it's easy. Just compute two bounding boxes.
I don't think there's a very elegant way of doing this with ES 2.0. ES 2.0 is a very minimal version of OpenGL, and you're starting to push the boundaries of what it can do. For example in ES 3.0, you could use queries, which would be very helpful in solving this nicely and efficiently.
What can be done in ES 2.0 is draw the sprites in a way so that only pixels in the intersection of the two end up producing color. This can be achieved with either using a stencil buffer, or with blending (see details below). But then you need to find out if any pixels were rendered, and there's no good mechanism in ES 2.0 that I can think of to do this. I believe you're pretty much stuck with reading back the result, using glReadPixels(), and then checking for non-black pixels on the CPU.
One idea I had to avoid reading back the whole image was to repeatedly downsample it until it reaches a size of 1x1. It would originally render to a texture, and then in each step, sample the current texture with linear sampling, rendering to a texture of half the size. I believe this would work, but I'm not sure if it would be more efficient than just reading back the whole image.
I won't provide full code for the proposed solution, but the outline looks like this. This is using blending for drawing only the pixels in the intersection.
Set up an FBO with an RGBA texture attached as a color buffer. The size does not necessarily have to be the same as your screen resolution. It just needs to be big enough to give you enough precision for your intersection.
Clear FBO with black clear color.
Render first sprite with only alpha output, and no blending.
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_TRUE);
glDisable(GL_BLEND);
// draw sprite 1
This leaves the alpha values of sprite 1 in the alpha of the framebuffer.
Render the second sprite with destination alpha blending. The transparent pixels will need to have black in their RGB components for this to work correctly. If that's not already the case, change the fragment shader to create pre-multiplied colors (multiply rgb of the output by a).
glColorMask(GL_TRUE GL_TRUE, GL_TRUE, GL_TRUE);
glBlendFunc(GL_DST_ALPHA, GL_ZERO);
glEnable(GL_BLEND);
// draw sprite 2
This renders sprite 2 with color output only where the alpha of sprite 1 was non-zero.
Read back the result using glReadPixels(). The region being read needs to cover at least the bounding box of the two sprites.
Add up all the RGB values of the pixels that were read.
There was overlap between the two sprites if the resulting color is not black.

Hide second-row transparent faces?

I'm trying to display a geographically complex, semi-transparent (e.g. alpha = 0.5) object (terrain). When I render this object, the hidden front-faces of this object will also be drawn (like a hill that actually lies behind another one).
I would like to see other objects behind my "terrain" object, but don't want to see the hidden faces of my terrain (the second hill). So actually set the transparency for the "whole" object, not for single faces.
Q: How could I achieve to hide the "hidden" front-faces of a semi-transparent object?
I'm setting the transparency in the vertex shader by multiplying the color vector with the desired transparency:
fColor = vec4(vColor, 1.0);
fColor *= 0.5;
// fColor goes to fragment shader
GL_DEPTH_TEST is activated with GL_LEQUAL as depth function.
GL_BLEND is activated with GL_ONE, GL_ONE_MINUS_SRC_ALPHA as blending functions.
I tried to deactivate the depth buffer by GLES20.glDepthMask(false); before drawing, but this doesn't make any difference.
Probably I don't get the idea for the right depth buffer settings or the blending functions.
Well, I think I got it now:
Actually I can resign on blending at all. With the depth test switched on only the foreground fragments are visible (the front hill of my terrain). With the multiplication in the vertex shader the fragment shader will draw these visible fragments with desired transparency (the terrain as a whole becomes semi-transparent).
So, depth test on, blending off, color multiplication in vertex shader.

Render To Texture & Trails Not Disappearing

I am trying to implement fireworks with point sprites and then drawing trails by rendering the fireworks to two different textures, and then drawing them back to each other every second time with alpha set to < 1, making each previous draw fade away more and more.
It looks nice and depending on what alpha I use when drawing the previously rendered texture the trails gets longer or shorter, as expected. However, on most devices (not all) the trails never disappear completely. They leave a very transparent but still noticable trail after they should have faded away.
This is what I do currently:
depending on a boolean called second I set the framebuffer to render to one of two textures called buff1 and buff2.
((GL11ExtensionPack)gl).glBindFramebufferOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, myFBO.get(0));
if (second){
((GL11ExtensionPack)gl).glFramebufferTexture2DOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, GL10.GL_TEXTURE_2D, buff2.texture.textureId, 0);
} else {
((GL11ExtensionPack)gl).glFramebufferTexture2DOES(GL11ExtensionPack.GL_FRAMEBUFFER_OES, GL11ExtensionPack.GL_COLOR_ATTACHMENT0_OES, GL10.GL_TEXTURE_2D, buff1.texture.textureId, 0);
}
gl.glViewport(0, 0, bufferSize, bufferSize);
gl.glClearColor(0, 0, 0, 0);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
Then I render the previously drawn texture on the current one, using a alpha value < 1. The buff object is just a helper drawing a quad with a texture. The draw function premultiplies the alpha to the other color channels.
// a = alpha, higher value = longer trails = more distinct leftovers
if (second){
buff1.setColor(1, 1, 1, a);
buff1.draw(gl);
second = false;
else {
buff2.setColor(1, 1, 1, a);
buff2.draw(gl);
second = true;
}
After that I do the drawing of the point sprite fireworks. Also using premultiplied alpha and gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ONE_MINUS_SRC_ALPHA);
Finally I reset the frame buffer and have my new texture containing the old trails fading and the current fireworks on top drawn at 100% alpha. I then use this texture to draw to my scene together with all the other objects behind and in front of the fireworks texture.
As I said, almost everything is working, except for those almost transparent trails staying after the trails should have faded. The higher the alpha value drawing the previous buffer the more noticable the trail "leftovers" that stay forever.
I have been trying with different blending modes, pre-multiplied and not pre-multiplied alpha etc. But since this is an android opengl es 1.1 I think the blending should be GL_ONE and GL_ONE_MINUS_SRC_ALPHA since all bitmaps are premultiplied by default.
What am I doing wrong? Is there a better way to do this?
Thanks for any help,
Anders
What am I doing wrong?
The way you sum downscaled (in their values) image is effectively a Power Series that exponetiate your alpha value. Such a power series will asympote to zero, but never reach it.
Is there a better way to do this?
Actually this is the right way to do it. You just forgot one last step: You want to have some threshold added, so that values below a certain alpha values get clamped to zero. Most easily this is obtained adding a GL_GREATER alpha test, with the threshold slightly above the alpha value of your trails you do want to remove.

libGDX: treat first color in palette as transparent color

old game engines designate the first color of an image's palette as a transparent color.
is there a way to do the same with libGDX?
i tried loading the picture and replacing the palete's first color with 0x00000000. however since the pixels are either opaque or transparent i dont need alpha values so i could save a lot of memory by using RGB888 instead of RGBA8888.
i lookes through the gdx and opengl documentary for other blending options and found Gdx.gl20.glBlendColor and the SpriteBatch's setBlendFunction function. but they only change the values used in the blending equations.
thanks in advance :)
to draw a textureRegion transparently use the routine like this:
Color c = batch.getColor();
batch.setColor(1, 1, 1, alpha);
batch.draw(....);
batch.setColor(c);

Categories

Resources