asny / three-d

2D/3D renderer - makes it simple to draw stuff across platforms (including web)
MIT License
1.24k stars 105 forks source link

Shadow banding artefacts #373

Closed wilfredjonathanjames closed 1 year ago

wilfredjonathanjames commented 1 year ago

Maybe you can help me. I've got what I think is a quite basic shadowmap setup and I'm getting the following artefacting when I generate a shadow map of any size. I'm using a DirectionalLight and haven't tried the others yet.

image
Versions:
MacOS@12.3
cargo@1.70.0

Target:
x86_64-apple-darwin

Repro repo here.

If you could critique my code as well that would be much appreciated.

asny commented 1 year ago

Only the cube should cast shadow, so if you only use the cube when generating the shadow map, it should look better. The problem is that the ground is really big and the 1024x1024 pixel shadow map will be stretched over a large area.

wilfredjonathanjames commented 1 year ago

Ah that makes sense. So if I had custom terrain that I'd generated in some third party software and wanted it to cast shadows on itself, I would simply need to choose a larger shadow map?

asny commented 1 year ago

Using the shadow map technique over large areas is generally not a good idea, you'll have to move the directional light with the camera to only cast shadow close to the camera view where the shadows are visible or maybe make several directional lights.

I came to think about that in the case you present, the artifacts are more visible by the direction of the light being close to parallel to the ground. Also, the shadow has a soft edge which is not looking good in this case.

wilfredjonathanjames commented 1 year ago

Ah ok, in that case does a directional light have a some local bounds that it generates shadow maps within? Is there something like a ScissorBox that applies here? I know these are probably quite simple questions, and appreciate your time.

asny commented 1 year ago

Ah ok, in that case does a directional light have a some local bounds that it generates shadow maps within? Is there something like a ScissorBox that applies here?

Yes, it will position the shadow map camera such that the objects that cast shadow are all within its viewport. That means, if you have a large object or two objects that are far away from each other, the shadow map will cover a large area and the shadows therefore look pixelated.

you'll have to move the directional light with the camera to only cast shadow close to the camera view

This was not a well thought out reply, of course you can't move a directional light. Instead, you could generate the shadow map with only the objects that are just in front of the camera. Also, it's important to note that only the objects that cast shadow, not the ones that receives shadow, should be given as input to generate_shadow_map.

maybe make several directional lights.

I have considered supporting multiple shadow maps on a single directional light, but unfortunately there's more important tasks at the moment.

I know these are probably quite simple questions, and appreciate your time.

I think they're totally valid questions, I'll convert this into a discussion afterwards so others may find answers to the same questions 👍 I should maybe also update the documentation of generate_shadow_map to make it a bit more clear.

wilfredjonathanjames commented 1 year ago

Also, it's important to note that only the objects that cast shadow, not the ones that receives shadow, should be given as input to generate_shadow_map.

That's a really helpful point, thanks! Would be great to know when this changes, but no pressure on my side.