Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Implementing custom mixed shadow caching for Unity 2020

Discussion in 'High Definition Render Pipeline' started by customphase, Aug 7, 2021.

  1. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    245
    Im trying to implement a custom mixed shadow caching solution (we cant use the built in one, cause its Unity 2021 only, and our project is on 2020), for that im using renderingLayerMask (since our project doesnt use those in any way). At edit time im marking all static objects as layer 2 and non-static as layer 1. Finally im modifying the RenderShadows function in the HDShadowAtlas, and the pseudocode looks something like this:

    Code (CSharp):
    1. shadowDrawSettings.useRenderingLayerMaskTest = true;
    2.  
    3. if (firstFrame) {
    4.     shadowRequest.lightData.SetLightLayer(layer2);
    5.     SetRenderTarget(cachedRT);
    6.     renderContext.DrawShadows(ref shadowDrawSettings);
    7. }
    8.  
    9. Blit(cachedRT, shadowAtlas, copyCachedShadowMat);
    10.  
    11. shadowRequest.lightData.SetLightLayer(layer1);
    12. SetRenderTarget(shadowAtlas);
    13. renderContext.DrawShadows(ref shadowDrawSettings);

    This doesnt work however, the cachedRT only has objects from layer1. I assume its because the light data is cached somewhere on the c++ side and only updated at the start of the frame or something like that. Am i correct in this assumption? Is there a way around that?

    Ive also tried spreading the process over multiple frames as a workaround (frame 0 - set the layer to layer2 and wait; frame 1 - render the layer2 and revert the layer to layer1; frame 2 - resume as usual), and it worked correctly, however it only works for lights with updateMode == EveryFrame.

    Would love to have any help with this. Thanks.
     
  2. customphase

    customphase

    Joined:
    Aug 19, 2012
    Posts:
    245
    Found a solution that works better.

    If anyones interested, worked around it by:

    1) creating a temporary (one-frame) copy of the light (somewhere in Update/LateUpdate, before the rendering starts, otherwise that light wont be registered on c++ side)
    2) making its intensity to something small (but not too small, cause unity skips lights below a certain intensity) so we dont see it flash on the screen when it renders for one frame
    3) giving it a static objects layer
    4) marking it as a special custom cached shadows light with some flag
    5) setting the shadow mode to OnDemand and calling RequestShadowMapRendering.

    Then in the RenderShadows function in HDShadowAtlas just check for that flag and change the target to your cached render texture, i.e.:

    Code (CSharp):
    1. if (shadowRequest.lightData.isCustomCachedShadowLight) {
    2.     SetRenderTarget(cachedRT);
    3.     renderContext.DrawShadows(ref shadowDrawSettings);
    4. } else {
    5.     Blit(cachedRT, shadowAtlas, copyCachedShadowMat);
    6.     SetRenderTarget(shadowAtlas);
    7.     renderContext.DrawShadows(ref shadowDrawSettings);
    8. }
     
    PutridEx likes this.