Alpha-blending and the Z-buffer. |
|
The Z buffer doesn't work for transparent polygons.
The problem is that the Z buffer prevents OpenGL from drawing pixels that are behind things that have already been drawn. Generally, that's pretty convenient - but when the thing in front is translucent, you NEED to see things that are behind it.
For many applications there are so few translucent objects that this is "good enough".
The point is that this polygon may well have no partially translucent pixels - there are lots of utterly opaque ones in the middle of the tree - and lots of utterly transparent ones around the outside. In principle, there shouldn't be a problem with Z buffering...but there is because by default, even the totally transparent pixels will write to the Z buffer.
Fortunately, OpenGL has a function that can prevent pixels with a specified set of alpha values from writing the colour or Z buffers. For example:
glAlphaFunc ( GL_GREATER, 0.1 ) ; glEnable ( GL_ALPHA_TEST ) ;This will only allow pixels with alpha values greater than 0.1 to write to the colour or Z buffers. You have to use this with care though - bear in mind that if your texture filter is set to one of the LINEAR or MIPMAP modes (eg GL_LINEAR_MIPMAP_LINEAR) then even if the top level texture map contains only 0.0 and 1.0, intermediate values will creep in during the filtering process.
However, this is another thing that will reduce the number of problems associated with Z-buffered rendering of alpha-blended polygons.
If all the translucent polygons have the same colour, then this does actually work - but for normal glBlendFunc settings and polygons of differing colours, the order that polygons are blended into the frame buffer also matters.
Consider two polygons, one red, the other blue - rendered against a green background. Both are 50% transparent. The red one is in front, the blue one is behind, the green background is behind that.
The final colour should be 50% red, 25% green and 25% blue.
Look at the various possible options, and the colour after each rendering step:
Z buffer enabled, red poly first, blue second. 1) Green background. (0.0,1.0,0.0) 2) Render red poly (0.5,0.5,0.0) 3) Render blue poly (0.5,0.5,0.0) (Z-buffered out) WRONG!!
Z buffer enabled, blue poly first, red second. 1) Green background. (0.0,1.0,0.0) 2) Render blue poly (0.0,0.5,0.5) 3) Render red poly (0.5,0.25,0.25) HOORAY!
Z buffer disabled, red poly first, blue second. 1) Green background. (0.0,1.0,0.0) 2) Render red poly (0.5,0.5,0.0) 3) Render blue poly (0.25,0.25,0.5) WRONG!!
Z buffer disabled, blue poly first, red second. 1) Green background. (0.0,1.0,0.0) 2) Render blue poly (0.0,0.5,0.5) 3) Render red poly (0.5,0.25,0.25) HOORAY!
There are other algorithms entailing use of "destination alpha" (which doesn't work with most PC-based hardware) - but they suffer from similar problems.
To be perfect - even sorting them isn't enough. You may have to split polygons up on-the-fly to get *perfect* rendering. Consider this pathalogical case:
/\/\ / \ \ \ \/ /\ \ / \ \ / /\ \ ____/ /__\___\__ | / / | |__/ /___________| /___/ \___\There is no way to sort this to make it work.
Some people suggest that if you stick with 'convex' objects, then you don't need to sort at the polygon level at all - that's equally easy to disprove:
/\/\ / \ \ \ \/ /\ \ / \ /\ /\ /\/ \ ____/ \/__\___\__ | / / | | |__/ /__|________| /___/ \___\Each object is made of two quads. If you sort by object, it fails, if you sort by quads - it works (just) - providing the right sort criteria.
This *looks* like an unlikely situation - but it's really not.
/ / __/_/__ | | | | /| | L / | C | / /| | _________/ /_|_______|_____ / /_/ T \ /_____________________________\ | || |_______| || | | || / \ || | | || /___________\|| | | || || |||| | | || || |||| |Polygon 'T' is a tabletop, 'C' is the back of a chair that's sitting on the floor behind the table. 'L' is a bolt from a laser gun fired from behind, above and to the right that has just evaporated a bowl of flowers sitting on the table. (Just as well - I can't draw those in ASCII art!).
Now, if you can imagine that the chair has an alpha-texture for the cane chair back - it's a glass topped table and the laser bolt is also alpha-textured. It's impossible to render this properly without splitting up at least one polygon.
Look what can happen when a translucent green blob alien (B) stands in front of a window (A)...Here is a plan view of the two polygons and our eye:
\ A \ \ eye \ \\ B \ \(Using a different slope makes this clearer - but I'm stuck with '\' characters!)
In this example, the center of polygon 'A' is closer to the eye than the center of polygon B - but it is BEHIND B! How about sorting by the nearest vertex? Nope - A is still in front. How about by the furthest? Nope - A still comes out "in front". (this example is more convincing with better artwork!) You have to look at the 'span' of A against the 'span' of B...which does bad things to some sort algorithms when you give them the table/chair/laser example. Some sort algorithms never terminate when given that input because L>T, T>C but C>L !!!