PDA

View Full Version : Stencil Shadow Volumes



Schleichmichl
10-29-2005, 06:44 AM
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:
http://www.schleichmichl.de/zpass.jpg

z-fail:
http://www.schleichmichl.de/zfail.jpg

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?

Racoon
10-29-2005, 09:16 AM
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);

Schleichmichl
10-29-2005, 11:50 AM
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...

Racoon
10-29-2005, 01:31 PM
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).

Schleichmichl
10-30-2005, 03:15 AM
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.

Poons
10-30-2005, 04:20 AM
Do you calculate the shadow volume caps?

Racoon
10-30-2005, 04:47 AM
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 ();

Schleichmichl
10-30-2005, 06:10 AM
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:
http://www.schleichmichl.de/depth_clamp.jpg

Racoon: I'm going to test your code soon!
Edit: Racoon: With your version, there's no shadow at all... :(

Poons
10-30-2005, 11:01 PM
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.