2
\$\begingroup\$

I'm having some transparency issues when rendering billboards in modern OpenGL.

I've created two billboard sprites, each one with alpha transparency, just for testing.

When I render two sprites without any transparency, it all works as expected:

enter image description here

Whenever I render two sprites with alpha transparency, part of one of the sprites is blocked by the other:

enter image description here

At first I though it had something to do with the render order, so I tried to change the order by simply render the second sprite before the first one, but then the issue is on the first sprite instead:

enter image description here

Blending is enabled by calling glEnable(GL_BLEND); at the start of the application.

I feel like I've tried every glBlendFunc() combination (glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) etc) that exist in OpenGL but nothing helps.

I've also tried disable the depthmask by calling glDepthMask(GL_FALSE);but that doesn't help either.

I am using VBO's (one per sprite) when rendering.

In the vertex- and fragment shader I'm not doing anything more than setting the vertex position, the texture coordinate and the pixel color.

\$\endgroup\$
3
  • \$\begingroup\$ Are you using a VBO, or are you calling glVertex? \$\endgroup\$
    – clabe45
    Commented Aug 1, 2017 at 13:57
  • \$\begingroup\$ I am using VBO's for rendering. I've edited my question and added that information. \$\endgroup\$ Commented Aug 1, 2017 at 14:02
  • \$\begingroup\$ I'm not positive that this will help, but you can also try rendering them in the same VBO. \$\endgroup\$
    – clabe45
    Commented Aug 1, 2017 at 14:06

2 Answers 2

6
\$\begingroup\$

With the help of Bálint, I successfully got the issue fixed.

Bálint suggested using the discard keyword in GLSL to discard pixels that are not visible (i.e, transparent).

So inside my fragment shader, I'm checking the pixel's alpha value and if it's below a certain threshold, the pixel is discarded and therefore not rendered.

vec4 PixelColor = texture2D(Colormap, FragmentUV);

if(PixelColor.a < 0.1)
    discard;

Result:

enter image description here

\$\endgroup\$
1
  • \$\begingroup\$ I use threshold 0.5 for my case, it looks better. A different threshold for a different case I assume. \$\endgroup\$ Commented Aug 9, 2019 at 14:15
2
\$\begingroup\$

Yes it's the render order, but not in the way you think. The depth buffer only contains 1 dimensional data, it can't represent transparency.

Even if part of the texture is transparent, it will still write in the depth buffer. Because of this when the other plane gets rendered, it'll get obstructed.

It's very hard to solve it in this case, you probably have to slice the plane up into 4 squares and render them separately at which point you could just make the models have an L shape.

\$\endgroup\$
2
  • \$\begingroup\$ Oh, I see. What if I want to render, for example, grass textures with a lot of transparency (reinerstilesets.de/3dtextures/billboardgrass0002.png). Do I have to cut those up aswell to get the desired result? \$\endgroup\$ Commented Aug 1, 2017 at 14:15
  • \$\begingroup\$ @Naith Use glsl's discard for that. It actually discards the fragments before anything gets written to the depth buffer \$\endgroup\$
    – Bálint
    Commented Aug 1, 2017 at 14:34

You must log in to answer this question.

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