Shadow blur causes shadow leak

Godot Version

4.5

Question

I am using a directional light with high “shadow blur” to create a diffuse lighting effect. In overcast lighting, shadows are blurrier because the direction of the sun’s light is scattered by the clouds. This is a very important part of the tone of the game.

Here’s what it looks like before and after blur:

Blurring the shadow creates a lot of artifacts. Most of these artifacts are trivial because I actually want to lose shadow detail anyway. But a pretty bad artifact that happens is a loss in the precision of shadow depth, creating an impression of light “leaking” through solid objects:

It gets even more egregious with shadows further away. I tried tuning the splits and the pancakes and the biases to no avail. I am not 100% sure how “shadow blur” works but I imagine it is either “blurring” the shadow map at runtime or each fragment is sampling it in a '“blurry” way, but I have no idea why this is happening. The light is facing straight down here. Fragments should be blending shadow values from their neighbors along the shadow plane, not vertically up through the ceiling, right?

Is there a way that I can use “blurry” shadows without “blurring” vertically? It would really be a shame to have to pick between hard-edge shadows in this cloudy scene and bright strips of light under every ceiling. Maybe there is a way to have both?

How about using ambient oclussion instead?

No that is not similar lol

It actually is similar, or at least it gives you the overcast mood.

Although if you want very soft cast shadows best to bake the illumination, either in Godot, or in other 3d modeling app. That way you can get properly raytraced cast shadows.

So there is no way at all to blur directional shadows without it blurring in the z direction also? Seems like there is no reason for shadow blur to do that.

Remember that you’re dealing with shadow maps, not with ray traced shadows. Bluring is just scattered sampling of the shadow map, which cannot be done without artifacts because of the way shadow maps work.

As already said, baking is your best bet if you want nice shadows with wide penumbras.

I understand how godot creates directional shadows. I just don’t understand why blurring in the direction of the light’s projection would also cause shadows to blur vertically. My understanding is that the shadow map saves a z value for the distance from the light to the nearest obstruction, and then fragments beyond this value know they are “in shadow”. “Blurring” this texture would stretch out the shapes of shadows horizontally, but in my scene it also seems to be drastically decreasing the precision of the value itself. You wouldn’t expect blurring a big solid grey rectangle to change the color in the center, so why do shadows “move down”?

There’s no blurring as such. The shader samples the shadow map multiple times inside some radius. This is not analogous to simply blurring a 2d bitmap. It’s much less controllable and sort of un-intuitive. The samples can hit all over the place in respect to scene geometry and thus artifacts can and will always appear, regardless of the specific softening method. All of the common methods have artifacts and those will be more pronounced the more you crank the softening up, i.e. the larger the sampling kernel. There’s no way around it with realtime shadowmapped shadows.

Does the samples go up and down with respect to the light direction? Why would you possibly want that? I guess I am asking if there is a way to turn that off lol.

Shadow map is sampled in a circular kernel around the light direction vector (which projects to a point in the shadow map). This translates to a conic volume in 3d space. The concepts of “up” and “down” don’t really make much sense here.

Afaik, Godot uses PCF or PCSS softening. Google those if you want more detailed information on how it works.

There’s no additional control of the parameters other than what you get in shadow properties and project settings.

Again, bake raytraced shadows and/or AO if you need it ideal. Shadow maps won’t be able to handle wide penumbras without artifacts or insanely large map resolutions.

In Godot 4.8 and later, you can enable screen-space contact shadows in the project settings when using the Forward+ renderer. This will add contact hardening using a screen-space effect, which isn’t perfect but should significantly reduce the occurrences of light leaking. In your particular case, it’ll likely work best when the maximum contact shadow length is set to Long (which has a higher GPU cost than the default Medium).

If you can’t use contact shadows, you’d likely need something like DPCF to ensure proper contact hardening of shadows while keeping a high shadow blur value.