Search Unity

  1. Unity 2020.2 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Help Wanted Use cascade parameters without Screen Space Shadows Enable

Discussion in 'General Graphics' started by SquallLiu, Nov 27, 2020.

  1. SquallLiu


    Jun 19, 2017
    For some reason, I want to receive shadow per object instead of a full screen collecting.
    It seems unity_WorldToShadow[0]~[3] won't update after disabling screen space shadows in graphic settings.

    Is there any workaround for this issue? (e.g. calculate cascade parameters on script side.)
  2. Arycama


    May 25, 2014
    Why don't you want to use the full screen shadow collector pass?

    If you're using the built-in pipeline, then I think you're out of luck, as there's no way to control how Unity positions it's shadow cascades, or to extract the matrices or culling spheres. (There is a light.shadowMatrix property, but that only works for non cascaded shadows, as it only takes a single matrix as as an argument)

    Unity seem to have designed it so that you must use screenspace and cascaded shadows together, even though the techniques themselves are independent .This is a strange decision by Unity for forward rendering, as it makes a depth prepass mandantory for cascaded shadows, greatly increasing draw calls and vertex processing.

    On the other hand, if you are using deferred, I would just keep using the shadow collector pass, as the depth buffer is already there, and it's seperating some expensive fullscreen shadow receiving work from the light accumulation passes.

    This is probably the kind of thing where you want to consider upgrading to URP, if possible. (Or a custom SRP, I have cascaded shadows in my custom render pipeline without a shadow collector pass) HDRP does allow you to toogle screenspace shadows on/off, but I wouldn't recommend it in general as it's a dramatic change from the builtin pipeline, and I have found the performance and customisation very underwhelming.
  3. SquallLiu


    Jun 19, 2017
    We are VR project and use built-in forward rendering pipeline.
    Since VR performance is batch-sensitive, I don't want those depth pre pass draw calls.

    Fortunately I figure out a solution with following compute shader:
    Code (CSharp):
    1. struct CascadeData
    2. {
    3.     float4x4 cascade[4];
    4.     float4 shadowSplitSpheres[4];
    5.     float shadowSplitSqRadii;
    6.     float3 padding;
    7. };
    8. RWStructuredBuffer<CascadeData> _CascadeData : register(u1);
    9. int _CascadeIndex;
    11. [numthreads(1,1,1)]
    12. void CSMain (uint3 id : SV_DispatchThreadID)
    13. {
    14.     // use matrix with perspective divide and normalized to [0,1]
    15.     // it's different from world to shadow
    16.     _CascadeData[0].cascade[_CascadeIndex] = UNITY_MATRIX_VP;
    18.     _CascadeData[0].shadowSplitSpheres = unity_ShadowSplitSpheres;
    19.     _CascadeData[0].shadowSplitSqRadii = unity_ShadowSplitSqRadii;
    20. }
    It's simple. Just to save Unity's cascade setting in read/write buffer at correct timing.
    I insert command buffer to LightEvent.AfterShadowMapPass with flag ShadowPass.DirectionalCascade0~3.
    Once I have cascade data, I can sample shadows in forward pass instead screen space collecting.

    Yes, screen space shadow is more efficient than per-object receiving in general.
    However it may not be suitable for forward rendering with depth pre pass.
    After modification, overall GPU performance of our project is reduced. From 13.6~14.1ms to 11.1~11.6ms.
    I think it's worth to use per-object receiving in our case!

    Last note: Depth pre pass does not improve forward pass performance at all. Unity clear the depth buffer before forward pass so that it won't be benefit from early-z culling.

    We may use new render pipeline for new VR projects in the future instead of old Forward Rendering.