Stencil Shadow Volumes

Hi!

I have a problem:
I’ve implemented the z-pass Algorithm for stencil shadow volumes and everything works fine. But if I change it to z-fail nothing is correct anymore.

z-pass:

z-fail:

My code for drawing the shadows:

	// store current OpenGL state
	glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT | GL_ENABLE_BIT);

	glClearStencil(0);

	// draw the scene to the depth buffer and
	// to the color buffer because the shadows should not be totally black
	glPushAttrib(GL_LIGHTING_BIT);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, black); // only ambient and emission light
	glLightfv(GL_LIGHT1, GL_SPECULAR, black);
	drawObjects(true); // draws the scene
	glPopAttrib();
	// ---------------------------------------

	glDepthMask(0);
	glColorMask(0,0,0,0);
	glDisable(GL_CULL_FACE);
	glEnable(GL_STENCIL_TEST);
	glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);

	glActiveStencilFaceEXT(GL_BACK);
	bool zpass = false; // works fine as long as zpass = false...
	if (zpass) {
		glStencilOp(GL_KEEP,            // stencil test fail
					GL_KEEP,            // depth test fail
					GL_DECR_WRAP_EXT);  // depth test pass
	} else { // zfail
		glStencilOp(GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP);
	}
	glStencilMask(~0);
	glStencilFunc(GL_ALWAYS, 0, ~0);

	glActiveStencilFaceEXT(GL_FRONT);
	if (zpass) {
		glStencilOp(GL_KEEP,			// stencil test fail
					GL_KEEP,            // depth test fail
					GL_INCR_WRAP_EXT);  // depth test pass
	} else { // zfail
		glStencilOp(GL_KEEP, GL_DECR_WRAP_EXT, GL_KEEP);
	}
	glStencilMask(~0);
	glStencilFunc(GL_ALWAYS, 0, ~0);

	drawHybridShadowVolume(); // draws the shadow volumes

	// restore OpenGL state
	glPopAttrib();

	glPushAttrib(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_ENABLE_BIT);

	// re-draw the model with the light enabled only where
	// there's no shadow
	glDepthFunc(GL_EQUAL);

	glStencilFunc(GL_EQUAL, 0, ~0);
	glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP);
	glEnable(GL_STENCIL_TEST);
	glEnable(GL_STENCIL_TEST_TWO_SIDE_EXT);
	drawObjects(true);

	// restore OpenGL state
	glPopAttrib();

What am I doing wrong ?

With zfail enabled I also see sometimes the scene projected into the shadows. Anyone experienced that before?

This code

  if (zpass) {
	      glStencilOp(GL_KEEP,      // stencil test fail
				      GL_KEEP,            // depth test fail
				      GL_DECR_WRAP_EXT);  // depth test pass
  } else { // zfail
	      glStencilOp(GL_KEEP, GL_INCR_WRAP_EXT, GL_KEEP);
  }

don’t effect under zpass = true. As GL_DECR_WRAP_EXT (0) -> 0 with stencil buf.
Visible assymetric under zpass = false — GL_INCR_WRAP_EXT.

Use
glClearStencil (128);
glStencilFunc (GL_EQUAL, 128, ~0);

Thanks for your answer, but I thought that GL_DECR_WRAP_EXT decreases the stencil value and if it is 0 it “wraps” the value to 255. Is that incorrect?

I also tried your recommendation but then everything is in shadow…

You right, sorry. But nevertheless try to remove assymetry. And zpass-algorithm work without EXT_stencil_two_side, i.e. two pass.

Try clear this function from odds glEnable (GL_STENCIL_TEST_TWO_SIDE_EXT) (in the close, replace on glDisable) and glPopAttrib () (in midle).

What do you mean with asymmetry?

I first implemented the shadow drawing with one sided stencil test and two passes but the problem was the same.

Do you calculate the shadow volume caps?

It is unimportant, but assymetry visibly in code “if (zpass) GL_DECR else GL_INCR”.

I’m can another say to you what this procedure is working.

  // in INIT
  glClearStencil (0);
  glStencilMask (~0);

  // in PROCEDURE

  glDepthMask (1);
  glColorMask (1,1,1,1);
  glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

  // Ambient, Emission
  glDisable (GL_STENCIL_TEST);
  glDepthFunc (GL_LESS);
  glPushAttrib (GL_LIGHTING_BIT);
  glLightfv(GL_LIGHT0, GL_DIFFUSE, black);
  glLightfv(GL_LIGHT0, GL_SPECULAR, black);
  DrawScene ();
  glPopAttrib ();

  // Stencil
  glEnable (GL_STENCIL_TEST);
  glDepthMask (0);
  glColorMask (0,0,0,0);
  glStencilFunc (GL_ALWAYS, 0, ~0);
  glEnable (GL_CULL_FACE);

  glCullFace (GL_FRONT);
  glStencilOp (GL_KEEP, GL_KEEP, GL_DECR_WRAP_EXT);
  DrawVolume ();

  glCullFace (GL_BACK);
  glStencilOp (GL_KEEP, GL_KEEP, GL_INCR_WRAP_EXT);
  DrawVolume ();

  // Full light
  glColorMask (1,1,1,1);
  glDepthFunc (GL_EQUAL);
  glStencilOp (GL_KEEP, GL_KEEP, GL_KEEP);
  glStencilFunc (GL_EQUAL, 0, ~0);
  DrawScene ();
 

Originally posted by Poons:
Do you calculate the shadow volume caps?
I have to admit, I didn’t know that I have to!
But now I have added a

glEnable(GL_DEPTH_CLAMP_NV);

before drawing the shadow volumes and everything seems fine in spite of the far clipping plane of the light being visible in the shadow by “inverting” the shadow.

Here is an example:

Racoon: I’m going to test your code soon!
Edit: Racoon: With your version, there’s no shadow at all… :frowning:

I have to admit, I didn’t know that I have to!

actually you only need it when the camera is inside the shadow volume or the shadow volume cuts thru the near clip plane.