2
\$\begingroup\$

I render a sprite twice, one on top of the other. The sprites have transparent parts, so I should be able to see the bottom sprite under the top sprite. The transparent parts are black (the clear colour) and opaque instead though and the topmost sprite blocks the bottom sprite.

My fragment shader is trivial:

uniform sampler2D texture;
varying vec2 f_texcoord;
void main()
{
    gl_FragColor = texture2D(texture, f_texcoord);
}

I have glEnable(GL_BLEND) and glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) in my initialization code. My texture comes from a PNG file that I load with libpng. I'm sure to use GL_RGBA when initializing the texture with glTexImage2D (otherwise the sprites look like noise).

Edit: Here's a screenshot.

enter image description here

\$\endgroup\$
3
  • \$\begingroup\$ Shouldn't it be glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);? Check this examples, machwerx.com/2009/02/11/glblendfunc \$\endgroup\$
    – Dan
    Jul 10, 2012 at 14:52
  • \$\begingroup\$ No, the posted code should work fine. Thanks for your comment. \$\endgroup\$
    – Oskar
    Jul 10, 2012 at 15:06
  • \$\begingroup\$ Keep in mind that alpha blend happens after the fragment shader (ie you have very little control over it other than setting glBlendFunc()). Check this question and see if it helps you (alpha channel being dropped). I would suggest trying to render 2 nontextured squares on top of one another to make sure blending is working, in case your alpha channel is somehow getting dropped. \$\endgroup\$
    – bobobobo
    Jul 10, 2012 at 15:11

3 Answers 3

7
\$\begingroup\$

What do you get if you try and swap the order you draw them in?

Transparent pixels still create depth buffer entries. If you're drawing the back one after the first it's not processing the pixels behind the front image, making it look like there's no alpha.

For reference, take a look at the Painter's alogrithm.

\$\endgroup\$
4
  • \$\begingroup\$ Switching the order fixed the issue. I was drawing the bottom sprite last, where its position was controlled by its z-coordinate. I suppose there's no way to get this kind of transparency working without sorting the sprites? \$\endgroup\$
    – Aaron
    Jul 11, 2012 at 0:51
  • \$\begingroup\$ @Aaron There is no solution for partially opaque surfaces that works for all scenes. Sorting works as long as your objects do not intersect. Another trick is that if your blending is additive (e.g. in a fire particle system) then you can simply disable depth testing. \$\endgroup\$
    – Kevin Reid
    Jul 11, 2012 at 1:18
  • \$\begingroup\$ Oh oh oh. Yeah. Here's my answer on SO \$\endgroup\$
    – bobobobo
    Jul 11, 2012 at 2:12
  • 2
    \$\begingroup\$ Right. I knew about the drawing order issues with translucent (not completely transparent) polygons, but didn't consider the effect of the depth buffer on polygons with transparent regions. I've discovered though that I can use the discard command in my fragment shader to reject transparent pixels regardless of drawing order, though I lose support for translucent objects and get aliasing around the final opaque objects. \$\endgroup\$
    – Aaron
    Jul 11, 2012 at 16:20
1
\$\begingroup\$

I don't think your textures have the desired alpha inside them, so calling gl_FragColor = texture2D(texture, f_texcoord) won't generate any transparent fragments. You should pass the alpha through as a varying from the vertex program to the fragment program if you want transparency.

EDIT: Teodron suggestion writing the following code to verify that alpha information is getting passed to the shaders (this is in the fragment shader and color is a varying which is assigned in the vertex program). vec4 color = texture2D(texture, f_texcoord); if (color.w < 1) gl_FragColor = vec4(1,0,0,1); else gl_FragColor = vec4(0,1,0,1);

\$\endgroup\$
3
  • \$\begingroup\$ Perhaps the OP can verify the alpha channel of the png files and chime in. Sending the alpha as an interpolated from a per-vertex information is geometry dependent, not image/texture dependent and not the way to go. I suggest this: a simple vec4 color = texture2D(texture, f_texcoord); if (color.w < 1) gl_FragColor = vec4(1,0,0,1); else gl_FragColor = vec4(0,1,0,1); and see whether there exists any alpha information getting through to the shader at all. \$\endgroup\$
    – teodron
    Jul 10, 2012 at 15:14
  • \$\begingroup\$ Brilliant! Thanks a lot, I will incorporate this into my answer. \$\endgroup\$
    – Oskar
    Jul 10, 2012 at 15:19
  • \$\begingroup\$ I've tried teodron's test and can verify that the transparent parts are correctly coloured red. \$\endgroup\$
    – Aaron
    Jul 10, 2012 at 22:41
0
\$\begingroup\$

If you know that those pixels have zero alpha and you want to discard them, a trivial solution is:

if (color.a <= 0.0) {
    discard;
}

There are better options probably, but this does work. There is no claim that this is good for performance on my behalf however.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .