PDA

View Full Version : Correct alpha blending for generated Geometry



Preafos
11-21-2010, 03:45 AM
Hi,

I generated a lot of geometry by the geometry shader. I try to generate polygons with transparent textures. I have no control over the rendering order. I want to have correctly overlapping textures with correct alpha blending.

Does any one knows a trick?

Alfonse Reinheart
11-21-2010, 04:00 AM
I have no control over the rendering order.

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.

However, if you're interested in order-independent transparency, you should try doing a search on, well, "order-independent transparency."

david_f_knight
11-21-2010, 12:49 PM
I have no control over the rendering order.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.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):
1) to the floating point color accumulation buffer, add the color multiplied by its alpha,
2) increment the translucent surface depth count buffer (used as the divisor to calculate the weighted average color in the next pass),
3) 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).

aqnuep
11-21-2010, 01:16 PM
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.

Actually geometry shader does guarantee the order of the primitives. That's why there were those severe performance issues with the first generation of GPUs that provided geometry shaders.

Besides that, it seems that the ultimate, yet efficient implementation of order-independent transparency is in the form of OIT with linked list buffers as provided by SM5.0 GPUs:
http://www.slideshare.net/hgruen/oit-and-indirect-illumination-using-dx11-linked-lists

david_f_knight
11-21-2010, 02:05 PM
Actually geometry shader does guarantee the order of the primitives. That's why there were those severe performance issues with the first generation of GPUs that provided geometry shaders.Interesting, but by my interpretation, that might not quite be true:

All output primitives generated from a given input primitive are passed to subsequent pipeline stages before any output primitives generated from subsequent input primitives.I interpret that to mean that if there are multiple geometry shaders executing in parallel, that all the primitives per shader will be output without intermixing them with primitives output from any other shader, but that there is no requirement as to the order that input primitives will be processed by geometry shaders. In other words, all the output primitives from input primitive n may precede any of the output primitives from input primitive n-1. If so, then one still can't know in what order, overall, the output primitives will be generated by the geometry shaders collectively. However, the spec is kind of ambiguous, in that it refers to "subsequent input primitives." Does "subsequent" simply mean "later" or does it necessarily and strictly mean "occurring later in the input stream, i.e., with gl_PrimitiveIDIn monotonically increasing" for each set of primitives output by geometry shaders?

Things get especially messy when you consider the interaction of the tessellation stage with the geometry shader. The OpenGL programmer never controls the order that triangles are generated by the Tessellation Primitive Generator, and those are the primitives sent to the geometry shader.


Besides that, it seems that the ultimate, yet efficient implementation of order-independent transparency is in the form of OIT with linked list buffers as provided by SM5.0 GPUs:That is AWESOME! If DX11-class hardware can support it, then I sure hope that OpenGL 4.2 will expose that capability.

aqnuep
11-21-2010, 05:35 PM
I interpret that to mean that if there are multiple geometry shaders executing in parallel, that all the primitives per shader will be output without intermixing them with primitives output from any other shader, but that there is no requirement as to the order that input primitives will be processed by geometry shaders.
I'm pretty sure geometry shaders do process primitives in order. Agree that the spec is quite unclear about this, but as I remember I read it in some document from NVIDIA or ATI.



Besides that, it seems that the ultimate, yet efficient implementation of order-independent transparency is in the form of OIT with linked list buffers as provided by SM5.0 GPUs:That is AWESOME! If DX11-class hardware can support it, then I sure hope that OpenGL 4.2 will expose that capability.
In fact, you can already implement it using the GL_EXT_shader_image_load_store extension. The only problem is that implementing DX11-style append-consume buffers needs you to use atomic counters, which you can simulate with atomic image writes, but is not the most efficient.
In order to get the full speed of order-independent transparency in OpenGL we need the ARB to finalize their GL_ARB_shader_atomic_counters extension which is not available yet.
For more info about it, I would recommend you to read my article about my expectations for OpenGL 4.2: http://rastergrid.com/blog/2010/11/suggestions-for-opengl-4-2-and-beyond/