Of course you do. You wrote the geometry shader, and the GS will output primitives in a specific order. It is therefore up to you to ensure that it generates things in the proper order.[/QUOTE]Preafos never wrote that all his geometry was generated from a single execution of the geometry shader. Unless it is, or unless he controls the relative order that multiple executions of the geometry shader occur, he does not control the overall rendering order. That’s a consequence of the parallelization of the graphics pipeline.
I was experimenting with rendering overlapping translucent objects a while back and noticed that generally speaking, the only really significant (certainly, the most significant) factor in getting perceptually good results depends only on rendering the front-most translucent surface last; the relative order that non-front surfaces are rendered is not of much perceptual significance provided that all surfaces have approximately the same alpha values.
From my previous review of order-independent translucency techniques, I’d say there are two general approaches: two-pass averaging, and n-pass true translucency, where n is a function of the maximum number of overlapping translucent surfaces.
Here’s a good presentation that discusses both:
http://developer.download.nvidia.com/SDK/10/opengl/src/dual_depth_peeling/doc/DualDepthPeeling.pdf
(There’s source code in SDK 10 that implements all of the algorithms presented in the paper.)
Here’s a nice presentation with more examples and results from the preceding paper:
http://www.slideshare.net/acbess/order-independent-transparency-presentation
I haven’t experimented with this particular idea yet, but I think a hybrid approach could be used to provide better perceptual results efficiently: a two-pass averaging could be done, and in the second pass, the front-most surface would be subtracted from the buffers containing the accumulated colors and then used for proper alpha blending of the front translucent surface with the weighted average of all the non-front surfaces.
First, render all opaque surfaces (defining the depth buffer) as usual.
Second, make a copy of the depth buffer to a draw buffer and then render all translucent surfaces to a variety of draw buffers (with depth buffer testing enabled, so only surfaces in front of opaque surfaces are rendered, but depth buffer writes disabled so all translucent surfaces not hidden by opaque surfaces are rendered):
- to the floating point color accumulation buffer, add the color multiplied by its alpha,
- increment the translucent surface depth count buffer (used as the divisor to calculate the weighted average color in the next pass),
- update the copy of the depth buffer with any Z value (i.e., gl_FragCoord.z) less than the current Z value (see glBlendEquationi (…, GL_MIN, …))
Third, use the updated copy of the depth buffer as the depth buffer (with depth buffer testing enabled and GL_EQUAL mode so only the front-most surface will be rendered) and then render all translucent surfaces. Subtract the color multiplied by its alpha from the floating point color accumulation buffer (removing the front-most surface from it), then divide the remaining color in the color accumulation buffer by one less than the number of colors accumulated in it (this is the weighted average of all the non-front translucent surfaces; if the number of colors accumulated was one, then there was only one translucent surface at this pixel so skip this averaging step). Blend the front-most translucent surface multiplied by its alpha with the weighted average of all the non-front translucent surfaces with the background (the opaque surfaces and background).