Search code examples
c++openglshaderalpha-transparencydepth-buffer

Rendering 3D Models With Textures That Have Alpha In OpenGL


So Im trying to figure out the best way to render a 3D model in OpenGL when some of the textures applied to it have alpha channels.

When I have the depth buffer enabled, and start drawing all the triangles in a 3D model, if it draws a triangle that is in front of another triangle in the model, it will simply not render the back triangle when it gets to it. The problem is when the front triangle has alpha transparency, and should be able to be seen through to the triangle behind it, but the triangle behind is still not rendered.

Disabling the depth buffer eliminates that problem, but creates the obvious issue that if the triangle IS opaque, then it will still render triangles behind it on top if rendered after.

For example, I am trying to render a pine tree that is basically some cones stacked on top of each other that have a transparent base. The following picture shows the problem that arises when the depth buffer is enabled:

Depth Buffer Enabled

You can see how you can still see the outline of the transparent triangles.

The next picture shows what it looks like when the depth buffer is disabled.

Depth Buffer Disabled

Here you can see how some of the triangles on the back of the tree are being rendered in front of the rest of the tree.

Any ideas how to address this issue, and render the pine tree properly?

P.S. I am using shaders to render everything.


Solution

  • If you're not using any partial transparency (everything is either 0 or 255), you can glEnable(GL_ALPHA_TEST) and that should help you. The problem is that if you render the top cone first, it deposits the whole quad into the z-buffer (even the transparent parts), so the lower branches underneath get z-rejected when its their time to be drawn. Enabling alpha testing doesn't write pixels to the z buffer if they fail the alpha test (set with glAlphaFunc).

    If you want to use partial transparency, you'll need to sort the order of rendering objects from back to front, or bottom to top in your case.

    You'll need to leave z-buffer enabled as well.

    [edit] Whoops I realized that those functions I don't believe work when you're using shaders. In the shader case you want to use the discard function in the fragment shader if the alpha value is close to zero.

    if(color.a < 0.01) {
       discard;
    } else {
       outcolor = color;
    }