Issue with shadow clipping on large worlds

Hi, any idea if this is a bug or it’s to be expected? Both screenshots render with the exact same settings, the only different is in the second one the world is larger. There are more objects in a distance, though far away and definitely outside the shadows render distance.

There is obvious “peter-panning”, much more obvious in the second case and it only slightly gets better with reducing shadow bias. So basically it doesn’t seem to be fixed that way. Any idea why this happens?

@mvaligursky

I think I understand the problem here. To store shadow map, we use 16/24/32 bit depth buffer of some sorts, and the lower the precision, the bigger the issue.

We get all objects that can cast shadows into shadow map, and find out a depth range of them in the space of the light. And then map this depth range into 0…1 range of the depth map.

So if you add a shadow caster really far, but it can still cast shadows into visible part of the frustum, it would make the depth range a lot larger, and so the precision of the depth map lower.

You can use more bits in shadow map (say 32bit if supported for VSM), but that is mostly out of your control in most cases, as hardware supports usually just one format.

The other way to help this is to mark those really far away meshes that you dont expect to see shadows from as not casting shadow - then they would not be used as part of the depth range estimation.

The other thing that could help would be pancaking … mentioned here, but not implemented yet: Cascaded shadow enhancements · Issue #3193 · playcanvas/engine · GitHub

2 Likes

Nice, makes sense! It may be a tricky problem for our project to disable shadow casting for specific mesh instances. Since those distant objects use the same mesh instance with the closer ones, with hardware instancing.

Still I will explore that, and also the other technique you shared. Many thanks Martin!

Perhaps your instancing system could split each instance into two batches … one for near by with shadow, one for distance without shadows?

1 Like

Yes, good idea, most likely we will go with that. It may allow better control of some other rendering aspects as well.

and ideally turn off both shadow casting and shadow receiving as well if possible to improve performance as well

1 Like

Without tackling any of the smaller instances like vegetation or the cliffs models on the distant islands yet, by turning off shadow casting on the island ground model (which is big, it extends below the water surface), improved precision by a big margin:

2 Likes

Actually I am making this topic public, it’s quite useful to know this issue and the workarounds.

It could be related to the fact that you use instancing to render those small meshes. In theory, you should probably set up AABB on the meshInstance, so that culling works on it … (it would not call per instance, but only as a whole). If you set up that AABB that those meshes would expand the shadow casting volume and you would not see improvement like you do. So I suspect instead of this you set up culling to off for those meshes … so they always render, but they don’t increase the size of shadow volume as AABB is small. I hope that makes sense.

Right, for instanced mesh instances we already have culling disabled (the ground models I’ve disabled don’t use instancing).

I am going to double check now the AABB of everything rendered in case it overlaps with the border of the shadow distance limit.

In idea case, you could probably subdivide your world into some sections (grid cells or islands) and have meshInstances that use instanced rendering for each of them. So palm trees on one island would be separate from palm trees on the other islands as an example. And you should leave culling on for these, but update the AABB for them as you generate them. This way palm trees on the island behind the camera would not render at all. If you just disable culling, they’re still submitted to GPU (for main camera and also for all shadow cascades).

We are already doing our own custom culling, so instances are partitioned in cells and we do per cell culling (frustum, distance and sometimes occlusion). So on each frame the mesh instance vertex buffer will contain only visible instances. And the shadows renderer will only render those visible instances.

I am curious now, do you think it’s possible to override a render method and update the vertex buffer one more time prior shadows render? So on that specific occasion we reduce the visible distance.

If that’s not possible most likely we will update our generation code to spawn a second mesh instance for non shadowed islands. That will increase the draw calls slightly.

So on each frame the mesh instance vertex buffer will contain only visible instances. And the shadows renderer will only render those visible instances.

This is not strictly correct, unless you use both the scene camera and cameras for individual shadow cascades to do culling. For example a tree that is not visible by main camera can still cast shadows that the main camera can see.

I am curious now, do you think it’s possible to override a render method and update the vertex buffer one more time prior shadows render? So on that specific occasion we reduce the visible distance.
If that’s not possible most likely we will update our generation code to spawn a second mesh instance for non shadowed islands. That will increase the draw calls slightly.

Updating the same buffer during a frame is likely not a great idea - as depending on the underlaying WebGl implementation, this could cause CPU to have to wait for GPU to be done using that buffer and similar. You’re better off creating a separate vertex buffer for shadow instances.

That’s correct, I oversimplified visible instances. The cells have their size set so trees, cliffs and other things are still rendered even though they may not be visible at all.

That’s quite powerful since it allows us to fine tune control over what’s and when it’s rendered (and LODs) without having to do per instance culling (which can kill performance).

Good idea! We may explore that at a later point, many thanks. For now we will most likely call it a day since precision has already improved by tackling ground model shadows.

Thanks Martin!

1 Like