Depth test and blending

Hi,
I’m trying to use the depth test and culling to render the front faces of some transparent geometry (let’s say a cube). When I run the following code:


setPerspectiveProjection(60, 0.1, 5);
glLoadIdentity();
glTranslatef(0,0,-2);
glMultMatrixd(viewTransform.getRow(0));
glTranslatef(-0.5,-0.5,-0.5);

glEnable(GL_DEPTH_TEST);
glClearDepth(1.0);
glDepthFunc(GL_LESS);
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
drawCube();
glTranslatef(1,0,0);
drawCube();
glutSwapBuffers();

I get strange results. The first cube is opaque, the second cube when you rotate allows me to see the sides of the other cube. That seems inconsistent. This is not how I expected it to behave at all. I expect all the geometry behind not to be rendered because of the depth test.

The drawCube() function is just:


glBegin(GL_QUADS)
	glColor4f(0,0,0,0.5);
	glTexCoord3f(0,0,0);
	glVertex3f(0,0,0);
	glColor4f(0,1,0,0.5);
	glTexCoord3f(0,1,0);
	glVertex3f(0,1,0);
	glColor4f(1,1,0,0.5);
	glTexCoord3f(1,1,0);
	glVertex3f(1,1,0);
	glColor4f(1,0,0,0.5);
	glTexCoord3f(1,0,0);
	glVertex3f(1,0,0);
...

Can anyone help me out?

Thanks.

Blending is order dependent, and blended objects should be rendered in back to front order.
Basically you should not write transparent objects to the depth buffer : in your case, the first cube is drawn first, setting depth buffer value so that depth test for second cube (farther) always fail. When you turn around, the first cube is now farther, and so the second be appears blended on top.

There are ways to to do real order-independent transparency blending, ie with depth peeling, but it is quite complex and eats processing power.

In fact, with convex geometry such as a cube, backface culling is sufficient, no need for the Z buffer at all.

So is the second cube not written to the depth buffer? I don’t quite get why the depth test fails. I find back face culling to be insufficient. Basically I want to render the closest front faces of a bunch of cubes (they represent bounding geometry of some voxels). The blending has to be turned on because the shader outputs stuff with alpha values and I want the result blended with the background. I was expecting to get only front faces rendered (the fragment shader is called for only front face fragments) when depth testing is turned on regardless of any blending, but that’s not the case.

If I understand well what you want to do, here is a possible simple implementation :

  • render to depth only your bunch of cubes, no blending
  • then render again the same bunch of cubes to color only, with blending, with a depth test set to GL_EQUAL.

I think you are misunderstanding what is considered “front faces” : it is simply faces whose normal is towards the viewer. Nothing to do with the faces that are actually visible. For non-convex geometry such as “bunch of cubes”, you need to use depth buffer.
http://www.opengl.org/sdk/docs/man/xhtml/glFrontFace.xml
http://www.opengl.org/sdk/docs/man/xhtml/glCullFace.xml

Well I need the front faces of the closest cubes, so that includes both a depth test and back face culling. But as I said you can see the front face of the cube behind as well when transparency is turned on. So why does the depth test fail?

I’m trying to implement this, page 3 - empty space skipping
http://www.cescg.org/CESCG-2005/papers/VRVis-Scharsach-Henning.pdf

I have it working with my workaround - render back/front faces to a texture, then render a single cube bounding box and lookup the front faces in the texture. I wanted to skip this third step.

The depth test can only test against the depth of polygons that have already been rendered. So if you render the distant cube first and the closer one last, both will be rendered and the closer one will be blended onto the latter.

You should do what ZbuffeR suggested: Render all cubes with depth only first (to find the depth of the frontmost face), then render color.

I see, that sounds like a plan. Can you tell me how to render depth only?

Crude but should work :
glColorMask( GL_FALSE,GL_FALSE,GL_FALSE,GL_FALSE);
glDisable(GL_BLEND);
//Render to depth only
// …
glColorMask( GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
glEnable(GL_BLEND);
// render color pass
// …

Thanks, that works.