Search Unity

SHADERPASS_SHADOWCASTER and testing for the shadowcaster pass

Discussion in 'Universal Render Pipeline' started by ElliotB, Jan 5, 2021.

  1. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    284
    Hi,

    In URP 8.2.x, I used SHADERPASS_SHADOWCASTER to change the behavior of some custom nodes in shadergraph during shadowcasting passes:
    Code (csharp):
    1. #ifdef SHADERPASS_SHADOWCASTER
    2. // do something while shadowcasting...
    3. #else
    4. // do something normally...
    5. #endif
    6.  
    I've upgraded to 2020.2 and URP 10.2.2 and this no longer works. I can't seem to find any reference in the changelog or docs about this functionality. I did see on the (now retired) git that some references were made to 'Fix SHADERPASS inconsistency between pipelines', see eg https://github.com/Unity-Technologies/Graphics/commit/db4dddf00233cbe55aa78414d6985ce292a70b46

    This looks like changes were made to the format:
    Code (csharp):
    1. #if (SHADERPASS == SHADERPASS_SHADOWCASTER)
    2. // stuff
    3. #endif
    4.  
    However, I can't seem to get this to work in my shader! Whatever I try the value is always true. What is the 'correct' way to test for the shadowcasting pass in URP 10?

    Cheers,
    Elliot
     
    lucasjohansson likes this.
  2. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    284
    More information:

    I've looked at the ShaderLab code generated by ShaderGraph for each version.

    In the URP 8.2 version, the shadowcaster pass looks like the following:
    Code (csharp):
    1.  
    2.         Pass
    3.         {
    4.             Name "ShadowCaster"
    5.             Tags
    6.             {
    7.                 "LightMode" = "ShadowCaster"
    8.             }
    9.  
    10.             // Render State
    11.             Blend One Zero, One Zero
    12.             Cull Off
    13.             ZTest LEqual
    14.             ZWrite On
    15.             // ColorMask: <None>
    16.  
    17.             HLSLPROGRAM
    18.             #pragma vertex vert
    19.             #pragma fragment frag
    20.        
    21.             // Debug
    22.             // <None>
    23.        
    24.             // --------------------------------------------------
    25.             // Pass
    26.        
    27.             // Pragmas
    28.             #pragma prefer_hlslcc gles
    29.             #pragma exclude_renderers d3d11_9x
    30.             #pragma target 2.0
    31.             #pragma multi_compile_instancing
    32.  
    33.  ....(a whole forest of keyword permutations, followed by)...
    34.  
    35.             #if defined(UNITY_SUPPORT_INSTANCING) && defined(INSTANCING_ON)
    36.             #define UNITY_DOTS_INSTANCING_ENABLED
    37.             #endif
    38.             #define SHADERPASS_SHADOWCASTER
    39.             //-------------------------------------------------------------------------------------
    40.             // Dots Instancing vars
    41.             //-------------------------------------------------------------------------------------
    42. ....
    43.  
    Hence, SHADERPASS_SHADOWCASTER is clearly defined in the Shadowcasting pass.

    In URP 10.2 the generated shader is different:
    Code (csharp):
    1.  
    2.             Pass
    3.             {
    4.                 Name "ShadowCaster"
    5.                 Tags
    6.                 {
    7.                     "LightMode" = "ShadowCaster"
    8.                 }
    9.    
    10.                 // Render State
    11.                 Cull Off
    12.                 Blend One Zero
    13.                 ZTest LEqual
    14.                 ZWrite On
    15.                 ColorMask 0
    16.    
    17.                 // Debug
    18.                 // <None>
    19.    
    20.                 // --------------------------------------------------
    21.                 // Pass
    22.    
    23.                 HLSLPROGRAM
    24.    
    25.                 // Pragmas
    26.                 #pragma target 4.5
    27.                 #pragma exclude_renderers gles gles3 glcore
    28.                 #pragma multi_compile_instancing
    29.                 #pragma multi_compile _ DOTS_INSTANCING_ON
    30.                 #pragma vertex vert
    31.                 #pragma fragment frag
    32.    
    33.                 #if SHADER_TARGET >= 35 && (defined(SHADER_API_D3D11) || defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE) || defined(SHADER_API_XBOXONE) || defined(SHADER_API_PSSL) || defined(SHADER_API_VULKAN) || defined(SHADER_API_METAL))
    34.                     #define UNITY_SUPPORT_INSTANCING
    35.                 #endif
    36.                 #if defined(UNITY_SUPPORT_INSTANCING) && defined(INSTANCING_ON)
    37.                     #define UNITY_HYBRID_V1_INSTANCING_ENABLED
    38.                 #endif
    39.                 #if defined(UNITY_HYBRID_V1_INSTANCING_ENABLED)
    40.                 #define HYBRID_V1_CUSTOM_ADDITIONAL_MATERIAL_VARS \
    41.                 UNITY_DEFINE_INSTANCED_PROP(float, _PixelSize_Array)\
    42.                 UNITY_DEFINE_INSTANCED_PROP(float4, _PixelGridOrigin_Array)
    43.                 #define _PixelSize UNITY_ACCESS_INSTANCED_PROP(unity_Builtins0, _PixelSize_Array)
    44.                 #define _PixelGridOrigin UNITY_ACCESS_INSTANCED_PROP(unity_Builtins0, _PixelGridOrigin_Array)
    45.                 #endif
    46.    
    47.                 // Keywords
    48.                 // PassKeywords: <None>
    49.                 #pragma shader_feature_local _ COLOR_GRADING_ON
    50.                 #pragma shader_feature_local _ RECEIVE_SHADOWS_ON
    51.                 #pragma shader_feature_local _ USE_OBJECT_POSITION_ON
    52.                 #pragma shader_feature_local _ NORMAL_MAP_ON
    53.                 #pragma shader_feature_local _ USE_EMISSION_ON
    54.                 #pragma shader_feature_local _ USE_ALPHA_ON
    55.                
    56. ...(a whole forest of keyword permutations, followed by)...
    57.    
    58.                 #define FEATURES_GRAPH_VERTEX
    59.                 /* WARNING: $splice Could not find named fragment 'PassInstancing' */
    60.                 #define SHADERPASS SHADERPASS_SHADOWCASTER
    61.                 /* WARNING: $splice Could not find named fragment 'DotsInstancingVars' */
    62.    
    63.                 // Includes
    64.                 #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl"
    65.                 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
    66.                 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
    67.                 #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/TextureStack.hlsl"
    68.                 #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/ShaderGraphFunctions.hlsl"
    69.    ...
    So the #define SHADERPASS_SHADOWCASTER has been swapped for #define SHADERPASS SHADERPASS_SHADOWCASTER, and I would expect the if statement in the first post to now work:
    Code (csharp):
    1. #if (SHADERPASS == SHADERPASS_SHADOWCASTER)
    But it still doesn't! The SHADERPASS_SHADOWCASTER statement is defined in Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl. If I put the following into a ShaderGraph Custom Node...
    Code (csharp):
    1. #ifndef UNIVERSAL_SHADERPASS_INCLUDED
    2. #error "Universal ShaderPass not included."
    3. #endif
    ...then I receive the error 'Universal ShaderPass not included' (the same works if I test whether SHADERPASS_SHADOWCASTER is defined).

    The 10.2 generated ShadowCaster Pass hlsl ends with:
    Code (csharp):
    1.                 // --------------------------------------------------
    2.                 // Main
    3.    
    4.                 #include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"
    5.                 #include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/Varyings.hlsl"
    6.                 #include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShadowCasterPass.hlsl"
    7.    
    8.                 ENDHLSL
    9.             }
    10.  
    ...which does include the ShaderPass.hlsl file.

    No answers yet, but I'll keep digging.
     
    bobbaluba likes this.
  3. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    284
    Ok, so I can get this to work if I manually include the ShaderPass.hlsl file at the start of my custom function

    Full Solution in 10.2:
    upload_2021-1-5_13-19-30.png

    Shadows.hlsl:
    Code (csharp):
    1. #include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"
    2.  
    3. inline void shadowcaster_float(out float _out) {
    4. #if ( SHADERPASS == SHADERPASS_SHADOWCASTER )
    5.     _out = 1.0;
    6. #else
    7.     _out = 0.0;
    8. #endif
    9. }
    10.  
    This will produce an object which is transparent yet still casts a shadow:
    upload_2021-1-5_13-21-17.png

    If you do not include the ShaderPass.hlsl file in the custom function, it does not work! So it seems to me that this is a bug, and that the ShaderPass include statement should occur higher up in the generated ShaderGraph file. (Perhaps this should be moved to the ShaderGraph forum?)
     
    morepixels likes this.
  4. ElliotB

    ElliotB

    Joined:
    Aug 11, 2013
    Posts:
    284
    Note that if you want backwards compatibility with previous render pipeline versions, you will need to switch based on the SRP version. There is also a bug there, so you will need to include Version.hlsl otherwise the VERSION_GREATER_EQUAL macro will not be defined in URP 10.2.

    Code (csharp):
    1. #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Version.hlsl"
    2. #if VERSION_GREATER_EQUAL(10, 0)
    3. #include "Packages/com.unity.render-pipelines.universal/Editor/ShaderGraph/Includes/ShaderPass.hlsl"
    4. #endif
    5.  
    6. ... then in your function
    7.  
    8. #if VERSION_GREATER_EQUAL(10,0)
    9. #define SHADOWTEST ( SHADERPASS == SHADERPASS_SHADOWCASTER )
    10. #else
    11. #define SHADOWTEST defined(SHADERPASS_SHADOWCASTER)
    12. #endif
    13.  
    14. #if SHADOWTEST
    15.     //do something in shadowcaster pass
    16. #else
    17.     //do something in normal pass
    18. #endif
    19.