views:

845

answers:

3

Hello, first time here. Sitting down today and teaching myself OpenGL. But I have run into a question I can't seem to find the answer to. I'm wondering why depth testing seems to be incompatible with semi-transparent objects in OpenGL. The documentation seems to suggest that you must turn off depth-testing, then draw objects in reverse-distance order and the blending will work properly.

But why can't openGL just use the same depth test it always does to figure out what's furthest back in reverse distance order and do this for you? Is it just a limitation of the framework, or is it something to do with what you can do efficiently in graphics hardware, or something like that?

Just wondering. Hope someone here can elucidate.

+6  A: 

Good question.

The short answer is that the Z-buffer stores a single value (only) for each pixel in the frame buffer. Given the "usual" mode of operation (for opaque objects--GL_DEPTH_TEST enabled, glDepthFunc set to GL_LESS), that value will be the depth of the nearest fragment that maps to that pixel.

The frame buffer is a "dumb" device--every fragment rasterizes and depth tests independently from all others, and divorced from any concept of the primitive that produced it. So, there is no place for the information about preceding primitives, depth sorting, etc. to be held, as would be required to implement your "auto transparency" feature.

You might want to look into "scene graphs" for help with the depth sorting. These are libraries that add "higher level" functionality beyond the basic T&L stuff that OpenGL provides.

Hope this helps.

Drew Hall
+1  A: 

I haven't heard of turning off depth testing. You want depth testing of transparent objects.

You just don't want the transparent objects writing to the z-buffer because then they'd punch holes in anything behind them that's drawn afterwards.

David
I wonder why this was up-voted, since if you used OpenGL as he's suggesting, everything drawn after your transparent object but behind it would totally occlude the transparent object, clearly not intended.
Blindy
That's the point--you draw the transparent stuff last, with depth testing enabled but depth writing disabled. That way transparent stuff is still occluded by opaque stuff that's in front of it.
Drew Hall
You draw the transparent objects last, back to front. I assumed he already knew that, since he mentioned the reverse order, and was asking about z-buffering.
David
+3  A: 

OpenGL writes to the depth buffer one pixel at a time, and renders the triangles that produce the pixels in the order that they are presented to OpenGL. OpenGL doesn't do any depth sorting of triangles, it is up to the calling framework to manage that in the way that is most efficient for that application. This is for the purpose of speed and flexibility, since the most efficient way to render a lot of triangles is to store them in contiguous buffers of vertices and indices, and if the API has to worry about sorting them all every frame, that would make things much slower.

Also, materials aren't associated directly with triangles in the API, so OpenGL really has no way of knowing which ones are transparent and which ones are opaque until the time that they're actually rendered.

A good way to handle it is to draw all of your opaque triangles first, and then draw all of your transparent/alpha blended triangles last. You generally want to have depth testing enabled, but depth-writing disabled, and sort your transparent triangles from back to front order for correct blending. The way I usually handle this is to have a scene graph with a number of buckets, and when I add triangles to the scene graph it will automatically separate them into the appropriate buckets that will be rendered in the correct order.

Gerald