Search Unity

What does SHADOWS_SCREEN mean?

Discussion in 'Shaders' started by Aldrick, Oct 12, 2018.

  1. Aldrick

    Aldrick

    Joined:
    Feb 19, 2014
    Posts:
    64
    In UnityShadowLibrary.cginc I see:

    #if defined( SHADOWS_SCREEN ) && defined( LIGHTMAP_ON )
    #define HANDLE_SHADOWS_BLENDING_IN_GI 1
    #endif

    But I didn't find explanation of SHADOWS_SCREEN macro.When would it be true?
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    By default, on the desktop and consoles, Unity uses screen space deferred cascaded shadows for the main directional light, for both forward and deferred rendering. This means that the main directional light's shadows are cast on the scene's depth texture and not calculated on the geometry itself. If you disable shadow cascades, or are on a platform that doesn't support using them (mobile) then it doesn't do this.

    TLDR: SHADOWS_SCREEN is defined when cascaded shadow maps are in use.
     
  3. Aldrick

    Aldrick

    Joined:
    Feb 19, 2014
    Posts:
    64

    Do you mean SHADOWS_SCREEN = using cascaded shadow maps ?And mobile device does not support cascades,hence in mobile device there will never be "#define HANDLE_SHADOWS_BLENDING_IN_GI 1" defined?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Well, specifically SCREEN_SHADOWS means screen space shadows are being used, but cascaded shadow maps are only supported using screen space shadows so they're roughly equivalent. Technically you can disable cascades on desktop, but it'll still use screen space shadows unless you dig a lot deeper into the settings to really disable it (if it's possible at all, some versions of Unity it is not). However any platform that doesn't support cascaded shadow maps, like mobile, don't support them because they don't support screen space shadows.

    So yes, it will not be defined on mobile.
     
  5. Aldrick

    Aldrick

    Joined:
    Feb 19, 2014
    Posts:
    64
    As I understand Unity realtime shadowing transfers shadow map to screen space coordinate and compare it with depth map to get the final shadowed pixel.Is this correct?If so,the Unity real-time shadows are certainly all "screen space shadows",is that correct?Because of this,I just feel the name of this macro a bit ambiguous.Please let me know if I get it wrong,Thank you bgolus.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Normally shadow maps work by transforming the mesh's vertex positions into light space and comparing the interpolated fragment shader light space position's depth against the shadow map's depth at the particular light space xy coordinate. It's "screen space" in that "light space" is equivalent the position that would be referred to as screen space if the main camera was rendering from the view of the light, but it's not really ever in screen space any more than anything else being rendered by a fragment shader. You'd never refer to something like per pixel Lambert shading as being "screen space", the calculations in the shader are all likely in world or view space.

    Screen space shadows are done by extrapolating a world position from the camera's depth buffer, (or some other screen space position texture encoding) then transforming that into light space to do the shadow map comparisons. Generally any screen space effect refers to only using data from the scene that's been previously encoded into a full screen texture. Technically any kind of deferred rendering technique is a screen space technique. But I don't really see any ambiguity here as no one ever refers to "light space" as "screen space".

    However one ambiguity might be mobile deferred rendering. I don't know if SHADOWS_SCREEN is set when rendering deferred shadows.
     
    olli_vrcoaster likes this.
  7. Aldrick

    Aldrick

    Joined:
    Feb 19, 2014
    Posts:
    64
    But I check out this post https://catlikecoding.com/unity/tutorials/rendering/part-7/,it says:
    "When the main directional light casts shadows, Unity will look for a shader variant that has the SHADOWS_SCREEN keyword enabled. "

    And in AutoLight.cginc,we can often find comments as below:
    // ---- Screen space direction light shadows helpers (any version)
    #if defined (SHADOWS_SCREEN)[/code]

    // ---- Screen space direction light shadows helpers (any version)
    #if defined (SHADOWS_SCREEN)
    ...


    It seems all these places suggest that the SHADOWS_SCREEN is very related to directional light shadows.

    And in the UnityComputeForwardShadows function,we can see that,if,as you say,SHADOWS_SCREEN means using cascaded shadows,which will not occur on mobile platforms,then the will be no shadow sampling process for mobile directional light shadows.

    So still not sure about that.
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Yes. That's what I said in my first response.
    There's no additional in shader filtering done on the shadows, yes. Only direct shadow map sampling. On PC any shadowing real time directional light past the first brightest will be the same as mobile.
     
  9. Aldrick

    Aldrick

    Joined:
    Feb 19, 2014
    Posts:
    64
    If there are only directional lights and "shadow cascades" in quality settings is 0,and it's mobile platform,what kind of shadows are in use? In this situation,does it mean cascaded shadows are not used and so SHADOWS_SCREEN macro is false?

    On mobile platform,If "shadow cascades = 0" in Quality Settings means "cascaded shadow maps are not in use" so SHADOWS_SCREEN is not defined ,and if there are only directional lights in the scene,I don't see where simple shadow map sampling is happening in this function:
    Code (CSharp):
    1.  
    2. half UnityComputeForwardShadows(float2 lightmapUV, float3 worldPos, float4 screenPos)
    3. {
    4.     //fade value
    5.     float zDist = dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz);
    6.     float fadeDist = UnityComputeShadowFadeDistance(worldPos, zDist);
    7.     half  realtimeToBakedShadowFade = UnityComputeShadowFade(fadeDist);
    8.  
    9.     //baked occlusion if any
    10.     half shadowMaskAttenuation = UnitySampleBakedOcclusion(lightmapUV, worldPos);
    11.  
    12.     half realtimeShadowAttenuation = 1.0f;
    13.     //directional realtime shadow
    14.     #if defined (SHADOWS_SCREEN)
    15.         #if defined(UNITY_NO_SCREENSPACE_SHADOWS)
    16.             realtimeShadowAttenuation = unitySampleShadow(mul(unity_WorldToShadow[0], unityShadowCoord4(worldPos, 1)));
    17.         #else
    18.             //Only reached when LIGHTMAP_ON is NOT defined (and thus we use interpolator for screenPos rather than lightmap UVs). See HANDLE_SHADOWS_BLENDING_IN_GI below.
    19.             realtimeShadowAttenuation = unitySampleShadow(screenPos);
    20.         #endif
    21.     #endif
    22.  
    23.     #if defined(UNITY_FAST_COHERENT_DYNAMIC_BRANCHING) && defined(SHADOWS_SOFT) && !defined(LIGHTMAP_SHADOW_MIXING)
    24.     //avoid expensive shadows fetches in the distance where coherency will be good
    25.     UNITY_BRANCH
    26.     if (realtimeToBakedShadowFade < (1.0f - 1e-2f))
    27.     {
    28.     #endif
    29.  
    30.         //spot realtime shadow
    31.         #if (defined (SHADOWS_DEPTH) && defined (SPOT))
    32.             unityShadowCoord4 spotShadowCoord = mul(unity_WorldToShadow[0], unityShadowCoord4(worldPos, 1));
    33.             realtimeShadowAttenuation = UnitySampleShadowmap(spotShadowCoord);
    34.         #endif
    35.  
    36.         //point realtime shadow
    37.         #if defined (SHADOWS_CUBE)
    38.             realtimeShadowAttenuation = UnitySampleShadowmap(worldPos - _LightPositionRange.xyz);
    39.         #endif
    40.  
    41.     #if defined(UNITY_FAST_COHERENT_DYNAMIC_BRANCHING) && defined(SHADOWS_SOFT) && !defined(LIGHTMAP_SHADOW_MIXING)
    42.     }
    43.     #endif
    44.  
    45.     return UnityMixRealtimeAndBakedShadows(realtimeShadowAttenuation, shadowMaskAttenuation, realtimeToBakedShadowFade);
    46. }
     
    Last edited: Oct 26, 2018
  10. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    Uhhhg...

    It looks like SHADOWS_SCREEN is likely enabled for directional lights on mobile, but then additionally UNITY_NO_SCREENSPACE_SHADOWS is also enabled for platforms that don't support cascades.
     
  11. Aldrick

    Aldrick

    Joined:
    Feb 19, 2014
    Posts:
    64
    Assume SHADOWS_SCREEN plus UNITY_NO_SCREENSPACE_SHADOWS equals using a single directional light shadows on mobile.
    then it seems it will directly do simple sampling of shadow map with "unitySampleShadow":


    Code (CSharp):
    1. // ---- Screen space direction light shadows helpers (any version)
    2. #if defined (SHADOWS_SCREEN)
    3.     #if defined(UNITY_NO_SCREENSPACE_SHADOWS)
    4.         UNITY_DECLARE_SHADOWMAP(_ShadowMapTexture);
    5.         #define TRANSFER_SHADOW(a) a._ShadowCoord = mul( unity_WorldToShadow[0], mul( unity_ObjectToWorld, v.vertex ) );
    6.         inline fixed unitySampleShadow (unityShadowCoord4 shadowCoord)
    7.         {
    8.             #if defined(SHADOWS_NATIVE)
    9.                 fixed shadow = UNITY_SAMPLE_SHADOW(_ShadowMapTexture, shadowCoord.xyz);
    10.                 shadow = _LightShadowData.r + shadow * (1-_LightShadowData.r);
    11.                 return shadow;
    12.             #else
    13.                ...
    14.             #endif
    15.         }
    16.  
    17.     #else
    18.       ...
    19.     #endif
    20.     #define SHADOW_COORDS(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1;
    21.     #define SHADOW_ATTENUATION(a) unitySampleShadow(a._ShadowCoord)
    22. #endif
    23.  
    But in this situation I don't see where does the shadow fadeout is calculated,which is the directional shadow of a object disappears gradually as the camera gets further.

    In other circumstance,I think the below does this job:
    Code (CSharp):
    1.      
    2.         /////////////////////////////////////////////////////////////////////////
    3.         ///////////  blend shadow with   cam distance   ///
    4.         /////////////////////////////////////////////////////////////////////////
    5.         half bakedAtten = UnitySampleBakedOcclusion(giInput.lightmapUV.xy, giInput.worldPos);
    6.         half zDist = dot(_WorldSpaceCameraPos - giInput.worldPos, UNITY_MATRIX_V[2].xyz);
    7.         half fadeDist = UnityComputeShadowFadeDistance(giInput.worldPos, zDist);
    8.         giInput.atten = UnityMixRealtimeAndBakedShadows(giInput.atten, bakedAtten, UnityComputeShadowFade(fadeDist));
    But for unitySampleShadow,I don't see that.But the Unity default directional shadow on mobile DOES fade out with camera distance,right.How does it do it?
     
  12. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    Code (CSharp):
    1. half UnityComputeForwardShadows(float2 lightmapUV, float3 worldPos, float4 screenPos)
    2. {
    3. ...
    4.     return UnityMixRealtimeAndBakedShadows(realtimeShadowAttenuation, shadowMaskAttenuation, realtimeToBakedShadowFade);
    5. }
     
  13. Aldrick

    Aldrick

    Joined:
    Feb 19, 2014
    Posts:
    64
    If it goes to UnityComputeFowardShadows,it makes sense.

    But my doubt is if using main directional light to cast shadow means "SHADOWS_SCREEN" (on mobile too) and if the current scene has lightmap baked so "LIGHTMAP_ON" is defined,so the "HANDLE_SHADOWS_BLENDING_IN_GI" will be defined,then there will be no chance for the codes to go to UnityComputeForwardShadows,instead it will goes to SHADOW_ATTENUATION(a) and wind up wtih unitySampleShadow only,and would not have fadeout:


    Code (CSharp):
    1. #if defined(HANDLE_SHADOWS_BLENDING_IN_GI) // handles shadows in the depths of the GI function for performance reasons
    2. #   define UNITY_SHADOW_COORDS(idx1) SHADOW_COORDS(idx1)
    3. #   define UNITY_TRANSFER_SHADOW(a, coord) TRANSFER_SHADOW(a)
    4. #   define UNITY_SHADOW_ATTENUATION(a, worldPos) SHADOW_ATTENUATION(a)
    5. #elif defined(SHADOWS_SCREEN) && !defined(LIGHTMAP_ON) && !defined(UNITY_NO_SCREENSPACE_SHADOWS) // no lightmap uv thus store screenPos instead
    6.     // can happen if we have two directional lights. main light gets handled in GI code, but 2nd dir light can have shadow screen and mask.
    7.     // - Disabled on DX9 as we don't get valid .zw in vpos
    8.     // - Disabled on ES2 because WebGL 1.0 seems to have junk in .w (even though it shouldn't)
    9. #   if defined(SHADOWS_SHADOWMASK) && !defined(SHADER_API_D3D9) && !defined(SHADER_API_GLES)
    10. #       define UNITY_SHADOW_COORDS(idx1) unityShadowCoord4 _ShadowCoord : TEXCOORD##idx1;
    11. #       define UNITY_TRANSFER_SHADOW(a, coord) {a._ShadowCoord.xy = coord * unity_LightmapST.xy + unity_LightmapST.zw; a._ShadowCoord.zw = ComputeScreenPos(a.pos).xy;}
    12. #       define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(a._ShadowCoord.xy, worldPos, float4(a._ShadowCoord.zw, 0.0, UNITY_SHADOW_W(a.pos.w)));
    13. #   else
    14. #       define UNITY_SHADOW_COORDS(idx1) SHADOW_COORDS(idx1)
    15. #       define UNITY_TRANSFER_SHADOW(a, coord) TRANSFER_SHADOW(a)
    16. #       define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(0, worldPos, a._ShadowCoord)
    17. #   endif
    18. #else
    19. #   if defined(SHADOWS_SHADOWMASK)
    20. #       define UNITY_SHADOW_COORDS(idx1) unityShadowCoord2 _ShadowCoord : TEXCOORD##idx1;
    21. #       define UNITY_TRANSFER_SHADOW(a, coord) a._ShadowCoord = coord * unity_LightmapST.xy + unity_LightmapST.zw;
    22. #       if (defined(SHADOWS_DEPTH) || defined(SHADOWS_SCREEN) || defined(SHADOWS_CUBE) || UNITY_LIGHT_PROBE_PROXY_VOLUME)
    23. #           define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(a._ShadowCoord, worldPos, 0)
    24. #       else
    25. #           define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(a._ShadowCoord, 0, 0)
    26. #       endif
    27. #   else
    28. #       define UNITY_SHADOW_COORDS(idx1) SHADOW_COORDS(idx1)
    29. #       define UNITY_TRANSFER_SHADOW(a, coord)
    30. #       if (defined(SHADOWS_DEPTH) || defined(SHADOWS_SCREEN) || defined(SHADOWS_CUBE))
    31. #           define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(0, worldPos, 0)
    32. #       else
    33.             #if UNITY_LIGHT_PROBE_PROXY_VOLUME
    34. #               define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(0, worldPos, 0)
    35.             #else
    36. #               define UNITY_SHADOW_ATTENUATION(a, worldPos) UnityComputeForwardShadows(0, 0, 0)
    37.             #endif
    38. #       endif
    39. #   endif
    40. #endif
     
    Last edited: Nov 2, 2018
  14. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,025
    Yes, but in this case it will be handled in the depths of GI, as the comment says :)
     
  15. Aldrick

    Aldrick

    Joined:
    Feb 19, 2014
    Posts:
    64
    Thank you a lot
     
  16. Aldrick

    Aldrick

    Joined:
    Feb 19, 2014
    Posts:
    64
    Not so sure what does "float zDist = dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz);" do here:

    Code (CSharp):
    1. half UnityComputeForwardShadows(float2 lightmapUV, float3 worldPos, float4 screenPos)
    2. {
    3.     //fade value
    4.     float zDist = dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz);
    5.     float fadeDist = UnityComputeShadowFadeDistance(worldPos, zDist);
    6.     half  realtimeToBakedShadowFade = UnityComputeShadowFade(fadeDist);
    7. ...
    8.  

    As Cg is using row matrix,UNITY_MATRIX_V[2].xyz means the world space's z basis vector in view space.What is the meaning of its dot product with world space view vector("_WorldSpaceCameraPos - worldPos")?

    If we need only the z value of the transformed vecor,shouldn't we use below instead?

    Code (CSharp):
    1. dot(_WorldSpaceCameraPos - worldPos, float3(UNITY_MATRIX_V[0].z,UNITY_MATRIX_V[1].z,UNITY_MATRIX_V[2].z));
     
    Last edited: Dec 3, 2018
  17. olli_vrcoaster

    olli_vrcoaster

    Joined:
    Sep 1, 2017
    Posts:
    24
    is there a way to force unity to use world space shadow calculation instead of screen space for specific shaders? Turning off shadow cascades is no option.
    I'm trying to achieve a fake volumetric light effect in Universal RP by having a couple of additive shadow-recieving planes.
    Maybe sample the shadow-texture and do shadow calculation by myself?

    fakevollight.jpg
     
  18. olli_vrcoaster

    olli_vrcoaster

    Joined:
    Sep 1, 2017
    Posts:
    24
  19. lxycg

    lxycg

    Joined:
    Jul 16, 2018
    Posts:
    2
    UNITY_MATRIX_V is column major, while UNITY_MATRIX_V[2] means the corresponding row vector.
    Here, "dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz);" is equal to "mul(UNITY_MATRIX_V, _WorldSpaceCameraPos - worldPos).z". But matrix multiplication is not necessary here, so Unity use "dot(_WorldSpaceCameraPos - worldPos, UNITY_MATRIX_V[2].xyz);" . About this "dot" code snippet, you can also see this article.

    Also, Matrix4x4 is also column major, while Matrix4x4[0] is the corresponding row vector.