16
$\begingroup$

Alpha blending can be turned on to make surfaces transparent, like so:

glDisable(GL_DEPTH_TEST); //or glDepthMask(GL_FALSE)? depth tests break blending
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

But this only works if objects are rendered in back to front order. Otherwise things in the background appear in front of closer objects, like the floor in the image below. For particles and GUI elements sorting would be OK, but for triangle meshes it seems like it'd be too much effort and slow, as discussed here: https://www.opengl.org/wiki/Transparency_Sorting.

What are the common methods to deal with this? I know this is quite broad and am not after in-depth implementation details, just a brief description of some approaches and what might be involved.

enter image description here

$\endgroup$
2
  • $\begingroup$ I'm not sure if this should go as an answer or not, but the errors in your image are caused by rendering without depth testing on all primitives. You should render the scene in 2 passes: First render normally all solid geometry. Afterwards, disable depth writes (not GL_DEPTH_TEST) and render translucent geometry in roughly back-to-front order. This will ensure that transparent geometry will not be drawn in front of solid geometry that's in front of it. $\endgroup$
    – yuriks
    Aug 11, 2015 at 17:45
  • $\begingroup$ @yuriks In this case it's probably a poor example on my part, but everything is meant to be transparent. I wanted something to show how wrong transparency might look when done badly. Also an example where sorting geometry would be amazingly difficult (for example here the floor is one giant polygon and covers the entire depth range). $\endgroup$
    – jozxyqk
    Aug 12, 2015 at 6:00

3 Answers 3

11
$\begingroup$

A set of techniques to avoid explicit ordering go under the name of Order Independent Transparency (OIT for short).

There are lots of OIT techniques.

Historically one is Depth Peeling. In this approach you first render the front-most fragments/pixels, then you find the closest to the one found in the previous step and so forth, going on with as many "layer" as you need. It is called depth peeling because at each pass you "peel" one layer of depth. All your layer can be then normally recombined from back to front. To implement this algorithm you need to have a copy of the depth buffer.

Another set of techniques are the blendend OIT ones. One the most recent and interesting one is the Weighted Blended OIT proposed by McGuire and Bavoil. It basically apply a weighted sum for all the surfaces that occupies a given a fragment. The weighting scheme they propose is based on camera-space Z (as an approximation to occlusion) and opacity.
The idea is that if you can reduce the problem to a weighted sum, you don't really care about ordering.

Other than the original paper, a great resource for implementation details and problems of Weighted Blended OIT is in Matt Pettineo's blog. As you can read from his post this technique is not a silver bullet. The main problem is that the weighting scheme is central and it needs to be tuned according to your scene/content. From his experiments, whilst the technique seems to work fine for relatively low and medium opacity, it is failing when opacity approaches 1 and so could not be used from materials where big part of the surface is opaque (he makes the example of foliage).

Again, all come down to how you tune your depth-weights and finding the ones that fit perfectly your use-cases is not necessarily trivial.

As for what is needed to for the Weighted Blended OIT, nothing more than two extra render targets. One that you fill with the premultiplied alpha color ( color * alpha) and alpha, both weighted accordingly. The other one for the weights only.

$\endgroup$
6
$\begingroup$

One option is to use depth peeling.

Essentially, one processes the scene a set number of times (say, n times) in order to determine the closest, second-closest, all the way to nth-closest fragments of the scene.

This processing is done by first applying a regular depth test to the entire scene (which naturally returns the closest surface). One then uses the result of the depth test to filter out the first layer, by ignoring everything with a lesser depth than returned in the depth test.

Applying the depth test again will then return the second layer. Repeat as needed.

Once you have the layers, you can just draw all the layers in reverse order (assuming you kept track of the RGBA colors for each layer), blending normally, since the layers are in front-to-back order.

$\endgroup$
2
  • 1
    $\begingroup$ Thanks! It looks like I'll need two depth buffers for this. I.e. one to store and filter out the last depths, and one to do the depth testing for the current render. Correct me if I'm wrong but I assume I'll need two depth textures for the FBO which I swap between each peeling pass. $\endgroup$
    – jozxyqk
    Aug 9, 2015 at 9:07
  • 1
    $\begingroup$ @jozxyqk Correct, two depth buffers are necessary for this procedure. $\endgroup$
    – es1024
    Aug 9, 2015 at 9:09
1
$\begingroup$

The creme de la creme of single-pass no (or few) compromises transparency in OpenGL is an A-buffer. With modern OpenGL, it is possible to implement:

http://blog.icare3d.org/2010/06/fast-and-accurate-single-pass-buffer.html

It avoids the multiple passes of depth peeling and doesn't require onerous sorting.

$\endgroup$
1
  • 3
    $\begingroup$ Ideally, answers should be self-contained and depend vitally on external links. Having links is nice for supplementary material, but an answer shouldn't just consist of a keyword. If you could include some details on what an A-buffer is and how it works that would greatly improve your answer. $\endgroup$ Aug 12, 2015 at 9:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.