Skip to main content
GameDev.net gamedev.net
🔒 Locked

A pretty good solution to Depth-Bias Problem!

Started by programci_84 Feb 24, 2009 at 8:55 AM 12 replies 6.5k views
Original Post
programci_84
programci_84
Hi there! Firstly, execuse me if you cannot understand because of my bad English. In shadow mapping, if you use PCF (Percentage-Closer Filtering), you use an epsilon value (bias) to check whether a pixel is lit or shadowed. Like this: float dx = 1/ShadowSize; float2 tc = ProjectedUV.xy; flaot D = ProjectedUV.z/ProjectedUV.w; float s0 = (tex2D (smp, tc).r + epsilon < D ) ? 0.0f : 1.0f; float s1 = (tex2D (smp, tc + float2 (dx, 0)).r + epsilon < D ) ? 0.0f : 1.0f; float s2 = (tex2D (smp, tc + float2 (0, dx)).r + epsilon < D ) ? 0.0f : 1.0f; float s3 = (tex2D (smp, tc + float2 (dx, dx)).r + epsilon < D ) ? 0.0f : 1.0f; And you know, the main problem is to choose the correct epsilon value to avoid artifacts. To use a constant epsilon value is not a good way. Because, if the light goes so closer to the occluder, some artifacts will occur. But for long distances, constant epsilon values can be used; but this time, shadow my go farther from occluder. Now I want to talk about my pretty good (but not absolute), simple solution. As I mentioned, shadow artifacts are related to Light position. For this reason, epsilon values must be calculated using distance of light. d = length (LightPosW - VertexPosW); epsilon = 1 / (d*d - 2*d); Where, LightPosW = World-Space Pos. of Light VertexPosW = World-Space Pos. of Vertex. Now, let'me show some results. Please be patient and look and compare all of'em. (When I press E, epsilon value toggles between 0.00005f and the value I calculated above. The spotlight is mounted on a skull mesh and I use this mesh to move the light. Also, this light projects a flashlight texture. Note: There's no use of Photoshop or another software): STATE 1: Light's so close to occluder epsilon = 0.00005f; ScreenShot1 epsilon = 1 / (d*d - 2*d); ScreenShot2 STATE 2: Light's a bit farther (normal mapping activated) epsilon = 0.00005f; ScreenShot3 epsilon = 1 / (d*d - 2*d); ScreenShot4 STATE 3: Light's so far (normal mapping activated) epsilon = 0.00005f; ScreenShot5 epsilon = 1 / (d*d - 2*d); ScreenShot6 So, what do you think? Thanks. Rohat. [Edited by - programci_84 on June 21, 2009 3:47:07 AM]
There's no "hard", and "the impossible" takes just a little time.
SiS-Shadowman
SiS-Shadowman
That's awesome.
I've been thinking about implementing shadow mapping in my current engine, but I didn't really want to spent one week implementing and one month tweaking the damn thing.
I've had some experience with it before, and my implementation suffered from those artifacts as well.

One question though. What happens if the light direction and surface normal are nearly in a 90° angle to each other? Are there any artifacts visible with your solution? If there still are, Infinity Admin once posted on his forum a tip that would solve this issued. However I think that this will make the epsilon in the second stage redundant, since the geometry has been offset'ed when rendering to the texture map:

click

I shall try both methods and see which one looks better (maybe I'll combine them in the render-to-shadowmap step).
programci_84
programci_84
@SiS-Shadowman;

You asked: "What happens if the light direction and surface normal are nearly in a 90° angle to each other?"

I tried it and took some screenshots (I think that the surface normal and spotlight's direction vector are approx. perpendicular).

Look:
* For a horizontal surface;
epsilon = 0.00005f;
epsilon = 1 / (d² - 2d)

* For a vertical surface (can be a column)
epsilon = 0.00005f;
epsilon = 1 / (d² - 2d)
* The same surface, but Normal Mapping activated
epsilon = 0.00005f;
1 / (d² - 2d)

I wish this will be useful for you :)
There's no "hard", and "the impossible" takes just a little time.
FeverGames
FeverGames
i must say i am really impressed by the results!
perrs
perrs
Interesting. But just to clarify; The epsilon you are talking about is used in all kinds of shadow mapping. Not just PCF. Correct?


Question:
How did you arrive at the formula:

d = length (LightPosW - VertexPosW);
epsilon = 1 / (d*d - 2*d);


On a side note; Another way to avoid the problem all together is to change your polygon culling (eg. from counter-clockwise to clockwise) when rendering your shadow map. This will make sure that you only render the backside of objects which will be shadowed anyway due to the normal (at least if you are using phong or similar). This should yield some proper results in most "normal" cases. It does, of course, depend on that your objects are closest, but that is a requirement for many other things anyway. :)

Best regards,
Per Rasmussen
programci_84
programci_84
@perrs;

Quote:
The epsilon you are talking about is used in all kinds of shadow mapping. Not just PCF. Correct?

I only tried this only for PCF. Because I only know and use PCF technique; if there are any other techniques, I don't know'em.


Quote:
Another way to avoid the problem all together is to change your polygon culling (eg. from counter-clockwise to clockwise) when rendering your shadow map.

Ok. I'll try this. Thanks.

Quote:
How did you arrive at the formula:

d = length (LightPosW - VertexPosW);
epsilon = 1 / (d*d - 2*d);

There's no proof I can do. Because, this is not a result of a theoretical study. I tried many constant bias values (e.g. 0.00005f, 0.00009f etc.) but didn't get an absolute good result. And I only saw that bias is related to light position (i.e. distance). When I realized that relation, I tried some formulas. First, I tried 1/d, then 1/2d, 1/5d, 1/10d, ... These were bad choices. When I tried 1/d², I got a better result, but not for a long distance. Then I tried 1/(d² - 2d), I got the best results but this fails for approx. 500 or 600 units of distance.

Regards.
Rohat.
There's no "hard", and "the impossible" takes just a little time.
FeverGames
FeverGames
Quote:
Original post by perrs
Interesting. But just to clarify; The epsilon you are talking about is used in all kinds of shadow mapping. Not just PCF. Correct?


Question:
How did you arrive at the formula:

d = length (LightPosW - VertexPosW);
epsilon = 1 / (d*d - 2*d);


On a side note; Another way to avoid the problem all together is to change your polygon culling (eg. from counter-clockwise to clockwise) when rendering your shadow map. This will make sure that you only render the backside of objects which will be shadowed anyway due to the normal (at least if you are using phong or similar). This should yield some proper results in most "normal" cases. It does, of course, depend on that your objects are closest, but that is a requirement for many other things anyway. :)

Best regards,
Per Rasmussen


I never heard of that solution before! sounds interesting.
SiS-Shadowman
SiS-Shadowman
Quote:
Original post by programci_84
@SiS-Shadowman;
...
I wish this will be useful for you :)


Absolutely amazing. Thank you again for your work. This will be implemented right away :)
I'm pretty sure it will look gorgeous.
Guthur
Guthur
Just wanted to add my own experimentations with depth bias epsilion, I based mine very heavily from this thread, thanks for the inspiration OP, I knew when I seen this thread a couple of days ago it would be worthwhile :).

I have used the following:
depthBias = 0.000007 / (pow(lightSpaceZ, 2) - (0.07 * LightSpaceZ));

Not that it means much :p; I have spent so long today trying to get this, it was the fuzziness when the occluder got near the light that was annoying me, now there is none :).
Innovation not reiterationIf at any point I look as if I know what I'm doing don't worry it was probably an accident.
programci_84
programci_84

Quote:
depthBias = 0.000007 / (pow(lightSpaceZ, 2) - (0.07 * LightSpaceZ));


Seems a nice solution ;)
There's no "hard", and "the impossible" takes just a little time.
FeverGames
FeverGames
but to be clear, this is not based on any theory accept the fact that the biassing is dependant on the distance from the light to the caster?
Guthur
Guthur
I have actually just went to a conditional test and 2 seperate constant epsilons.

FeverGames: Is there other theories or experimentations regarding this that get decent results; in fact I don't really mind if its not backed up with theoretical prove, if it works it works :) I'll leave proof to PhD students with nothing better to do :p
Innovation not reiterationIf at any point I look as if I know what I'm doing don't worry it was probably an accident.
FeverGames
FeverGames
Quote:
Original post by Guthur
I have actually just went to a conditional test and 2 seperate constant epsilons.

FeverGames: Is there other theories or experimentations regarding this that get decent results; in fact I don't really mind if its not backed up with theoretical prove, if it works it works :) I'll leave proof to PhD students with nothing better to do :p


hey man I agree 100% with you! I was just wondering :D

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.