playcanvas / engine

Powerful web graphics runtime built on WebGL, WebGPU, WebXR and glTF
https://playcanvas.com
MIT License
9.71k stars 1.36k forks source link

Shadow map sizing #813

Open yard opened 7 years ago

yard commented 7 years ago

Hello guys,

While playing with shadows in Play Canvas I ran into quite an unpleasant issue with my scene: basically, the scene is quite big (in terms how much world units the camera sees), but the bounding box of all shadow casters is quite small – imagine an exhibition hall with an item in the center of it – all the surroundings are basically empty / not affected by shadows. However, the shadow map always gets rendered so that the whole visible area (limited by shadow distance) gets into shadow camera's view.

Just a random thought: would it make sense to try adjusting shadow camera frustrum so that it captures the volume = MIN(visible scene BB, shadow casters BB)? I am looking into trying to play with it but a bit afraid that I am missing something crucial and will just waste the time before running into a stone wall – or it's actually worth trying?

willeastcott commented 7 years ago

Assigning this thread to @guycalledfrank. This part of the engine has changed a fair bit since I last worked on it.

guycalledfrank commented 7 years ago

This is quite possible to do, yes. We even have the visible shadow casters' AABB already: https://github.com/playcanvas/engine/blob/master/src/scene/forward-renderer.js#L1645 But it's only used for tightening near/far planes. Shadow map bounds are currently bound to the camera. I'll take a look at focsuing them on the casters' AABB, as soon, as I finish current tasks.

yard commented 7 years ago

An immediate problem that comes to my mind and might be worth noting is that frustrum of shadow camera should have some padding around shadow casters' BB – otherwise (due to CLAMP_TO_EDGE sampling mode) the shadows might spread further from the end of the actual projection.

And I believe the questions like Cascading Shadow Maps etc are "not for now"? :)

guycalledfrank commented 7 years ago

It does already have a single-pixel padding for that reason: https://github.com/playcanvas/engine/blob/master/src/scene/forward-renderer.js#L881

Cascades are good, but heavy for many non-desktop platforms. They're on the roadmap, however, I wanted to add per-object shadows first. Per-object can be relatively cheap, because you can draw only few needed objects in their own shadowmaps, skipping vast empty spaces (therefore utilizing texels way better), and you can also skip updating shadows for objects that don't move. Would per-object shadow help you? (note, that it doesn't mean strictly 1 shadowmap per 1 model, you could group stuff together).

yard commented 7 years ago

"Per-object" shadows sound great, I was thinking of smth similar - maybe clustering objects somehow? This would complicate applying shadow though - so per-object approach is good enough I think

guycalledfrank commented 7 years ago

Currently I have a prototype of per-object shadows, but they require screen depth to be available... (which would be a separate geometry pass). I thought about clustering objects as well. For static lights and static geometry ("static" checkbox in Editor) we do cut triangles from meshes where the intersections happen. For dynamic lights/shadows we need different clusterting at runtime though. For static geometry it would be valid to generate a BVH tree of triangles, for example... dynamic objects could have local movable trees. Starts to sound complicated, but should be doable. With screen depth approach it's also possible to only draw shadow receiving geometry to depth, which is better than the whole scene. However it has some problems to solve with shadow occlusion and overdraw.

yard commented 7 years ago

Well, I think starting with focusing on shadowcasters is probably the way to go – replacing the notion of "shadow casters" with a more narrowed set of objects would gradually optimise the algorithm down the road.

BVH tree is a great idea – actually, I've been thinking that the whole scene hierarchy should be somehow packed in an R-tree or smth to allow efficient geometry queries; a hashmap with layer -> list objects to be maintained etc. Just looking through the code of the engine and these filter-loops are everywhere – but that's for a separate issue.

willeastcott commented 3 years ago

Assigning this to you @mvaligursky since you're working on the shadow subsystems at the moment. Up to you where we go with this thread... 😄