Z-Buffer imprecision in shadow volumes

I’m currently trying to implement shadow volumes using Mark Kilgards infinite far plane scheme, i.e. build a projection matrix where the far plane is set to a theoretical infinity. Everything is working O.K. except that when I render the backfacing polygons, with w = 0, to close off the shadow volume, I get some artifacts in the image. The artifacts are seen as small parts of the shadowed region suddenly becoming unshadowed, giving a flickering image.
I think that this is due to a lack of precision in the Z-buffer, due to the rendering of polygons that are infinitely far away. Could that be the case?
I cannot use the depth clamping extension to try to fix this since I only have a GeForce2 to work on. I’ve tried moving the near plane closer in to increase Z-buffer precision, but it did not change anything. So is there any other way to fix it? Has anyone else had similar problems?
My reasoning for thinking that it is the Z-buffer causing the trouble is, that if I don’t render the back facing polygons to close the shadow volume, the flickering disappears, but of course the shadow doesn’t look right at all times, depending on the camera position. Any help on this is greatly appreciated, and if something needs clarification, please don’t hesitate to ask.

Regards Anders

More than likely it’s not from a loss in zbuffer precision. Setting the far plane to infinity only causes about a 1% loss in precision or something. It’s pretty small. I think what the probem is, is like what Cass has talked about before, and that is LSB problems. So inorder to correct it, add a ‘slop’ to the parts of the inf proj matrix which make the far plane go to infinity.

I dont have my code here but I think it’s:
infProj[3][2] = -2NEARnudge;
infProj[2][2] = -1*nudge;

Where nudge is 1.0 - (1.0/(1<<23)). I believe that’s right. Nudge comes out to be about 0.99999987 or something like that. I remember it’s six 9’s though. So try that and see what happens.


Hmm, the nudge factor didn’t do the trick. It may have lessened the problem a little, but it is hard to tell. Could you tell, where you have that information from, because I am not quite certain what exactly it does. Also what do you mean by LSB problem?

Regards Anders

Using 23 for the bit shifting for the nudge factor also doesn’t work for me at all. There are many cases where shadows are still flickering. I’m using 19 and that seems to be ok.

This nudge ‘formula’ comes from Cass’s inf shadow volume demo. Cass made a post talking a little about this. Try to search the board to see if you can find it. I think it was the post he made when they released the paper. If I find the link ill post it.


Oh also you may have to do a polygon offset. Cass’s demo also does this. He has it set to glPolygonOffset( 0, -2 ); Check the demo for more details on that.


Ok this was not discussed in the first post about the inf shadow volumes like I thought. But I did find the post. Here it is:

The LSB problem I talk about is an issue with the clipper. Since you project the far plane to infinity this makes it have a ‘razors edge’ so any small computational error (like with the clipper) can cause problems. That’s why you include a slop to allow some head room. Some cards work ok without it though. Kind of strange but I guess no two clippers are the same.

EDIT: Also I want to add that for some reason I have never been able to get the correct value I need if I type in:
float nudge = 1.0f - (1.0f / (1<<23));
I dont get .99999 etc like I am supposed to. So I just type in:
float nudge = 0.9999999f;


[This message has been edited by SirKnight (edited 09-25-2002).]

I actually looked up the word “slop”, I assumed Cass was being scientific .
The polygon offset stuff is because Cass has clipping planes enabled. It isn’t required otherwise. Still, it’s probably safest to use it ( I do myself, now that the bug has been fixed in the drivers for the 8500 ). Using LESS should ( in theory ) not shadow the front faces but there are no guarantees. Offsetting is a good way to make things more robust ( and particularly useful if you for some reason, have clipped the shadow volumes ).

[This message has been edited by PH (edited 09-25-2002).]

Using LEQUAL should ( in theory ) not shadow the front faces but there are no guarantees. Offsetting is a good way to make things more robust ( and particularly useful if you for some reason, have clipped the shadow volumes ).

Yes, it’s always good to be safe. Usually what should happen doesn’t happen. Usually some little floating point error can cause all kinds of havok.


Btw, that should have been LESS not LEQUAL .

SirKnight, the reason is of course the floating point precision. Using double you’ll get the desired 0.999… Btw, cass updated the file which you can find at http://www.r3.nu/~cass/shadow_volumes/ and a discussion at http://www.opengl.org/discussion_boards/ubb/Forum3/HTML/007479.html and in this file he sets the nudge value to 0.999.


Thanks for all your help guys.

The nudge factor DID work after all. I had made a really stupid error and nudged a value that should not be nudged at all (compact code etc.) The clipping is now done correctly.
BTW, I had the opportunity to test the code on a GeForce3, and there everything worked fine without the nudging. Weird, does anyone know why this is so?
Another question: Currently I am using a polygon offset when drawing my scene objects to prevent Z-fighting with the shadow volumes on the object surfaces. Is that an acceptable solution or is there a better way to avoid this?

Regards Anders