VSM Quality is linked to render resolution

The VSM shadow Quality is greatly degraded when the resolution is reduced, this is a big problem for console builds with dynamic resolution.

It seems that the LOD is calculated using the rendering resolution, whch is not a good idea because you don’t know the size of a shadow texel depending on the projection angle and it is almost always vastly bigger than the pixel density. So there is no reason to drop the shadow resolution when the rendering resolution gets lowered. (Unlike Nanite)

Here is the example, as I said, Epic Quality, a simple spot a cone and a cube :

Setup :

With 100% Screen Percentage :

With 50% Screen Percentage :

Of course if I lower the r.Shadow.Virtual.ResolutionLodBiasLocal (here at 0) I get nicer results but the memory footprint explodes.

On console I have the ResolutionLodBiasLocal at 1, for 300Mb of shadows, if I set it to 0 I get 1Gb of shadows.

I also tried to change the ShadowResolutionScale on the light but there is no effect on values > 1.0

And of course when a scene gets a bit heavier on the GPU, the resolution drops and the shadows gets ugly (for no reason).

Raytraced shadows don’t have this problem but they are vastly more expansive.

So there is two things I would like to know :

  • How can I untie VSM Shadows LOD and Pixel Density.
  • How can I control the shadow LOD Bias/resolution on a per light basis.

Steps to Reproduce

  • Create a new project with “Scalability” Quality.
  • Check that you are in “Epic”
  • Create a cube, a cone and a spotlight, disable the Directional and make the spotlight project the shadow of the cone on the cube
  • Set the ScreenPercentage to 100%, observe that the shadow is “ok but not “Epic” great”
  • Set the ScreenPercentage to 50%, observe that the shadow is “Ugly” with no obvious reason

Dynamic res is a mechanism that responds to, hopefully periods, of lower performance by reducing cost in various systems. For shadows, this equates to lowering resolution, by far the largest knob available. We could of course have wired it up differently such that you could decouple the resolution from the VSM scaling, but in the end it sort of amounts to the same thing: if you are over budget cost must go down to meet performance targets. If you expect your game to run at 50% dynamic res for extended periods you probably need to tweak settings to suit that scenario better. There are after all practical limits to how much one can scale automatically.

The two things you ask for are not possible without modifying the engine:

  1. You’d need to modify page marking to go off of the target resolution rather than the current one, see e.g., VirtualShadowMapCalcPixelFootprintLocal. And then implement some alternative load reduction scheme for dynamic res. Though of course you could ignore that completely if you don’t care about maintaining frame rate.
  2. VSMResolutionLodBias in the light scene proxy feeds into the resolution LOD calculations but is not exposed in the component UI.

You can set the physical page pool size to limit max memory use, but again the only way for this to scale it by lowering resolution.