Search Unity

Custom ShadowCaster for Indirect Surface Shader

Discussion in 'Shaders' started by m506, Sep 15, 2020.

  1. m506

    m506

    Joined:
    Dec 21, 2015
    Posts:
    93
    Hi, I have an "Instanced Indirect" surface shader which works fine except it is not casting shadows properly:

    Shader "InstancedIndirect"
    {
    Properties
    {
    _MainTex("Albedo (RGB)", 2D) = "white" {}
    }

    CGINCLUDE

    #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    StructuredBuffer<float4x4> obj2world;
    StructuredBuffer<float4x4> world2obj;
    #endif

    void setup()
    {
    #ifdef UNITY_PROCEDURAL_INSTANCING_ENABLED
    unity_ObjectToWorld = obj2world[unity_InstanceID];
    unity_WorldToObject = world2obj[unity_InstanceID];
    #endif
    }

    ENDCG

    SubShader
    {
    Tags { "Queue" = "Geometry" "RenderType" = "Opaque" "IgnoreProjector" = "True" "DisableBatching" = "True" }

    CGPROGRAM

    //#pragma surface surf Standard addshadow
    #pragma surface surf Standard
    #pragma target 4.5
    #pragma multi_compile_instancing
    #pragma instancing_options procedural:setup

    sampler2D _MainTex;

    struct Input
    {
    float2 uv_MainTex;
    UNITY_VERTEX_INPUT_INSTANCE_ID
    };

    void surf(Input IN, inout SurfaceOutputStandard o)
    {
    o.Albedo = tex2D(_MainTex, IN.uv_MainTex);
    }

    ENDCG

    Pass
    {
    Name "SHADOWCASTER"
    Tags { "LightMode" = "ShadowCaster" }

    CGPROGRAM

    #pragma vertex vert
    #pragma fragment frag
    #pragma multi_compile_shadowcaster
    #pragma fragmentoption ARB_precision_hint_fastest

    #include "UnityCG.cginc"

    struct v2f
    {
    V2F_SHADOW_CASTER;
    };

    v2f vert(appdata_base v)
    {
    v2f o;
    TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    return o;
    }

    float4 frag(v2f i) : COLOR
    {
    SHADOW_CASTER_FRAGMENT(i)
    }

    ENDCG
    }
    }
    FallBack Off
    }

    Basically, if I do "addshadow" in the pragma section the shadows get batched together for multiple objects and
    they all overlap, as if unity was not instancing them properly. See image below:

    https://imgur.com/a/X9vDbcD

    One thing I am trying now is to add a custom "ShadowCaster" pass into this surface shader, but it is not working at all
    for indirect instanced objects, but because it is working for normal MeshRenderers, I can guess I am in the right direction.

    Can someone please let me know if there's a way to either make Unity batch the shadows properly using "addshadows"
    or to make this custom pass to work? (Using Unity 2019.4.1f1)

    Thank you in advance
     
  2. marwi

    marwi

    Joined:
    Aug 13, 2014
    Posts:
    138
  3. m506

    m506

    Joined:
    Dec 21, 2015
    Posts:
    93
    Hi, thanks for replying but using materialproperties didn't work for me. The pass below solved the problem (I included only the relevant parts):

    Code (CSharp):
    1. Pass
    2. {
    3.     Name "ShadowCaster"
    4.     Tags { "LightMode" = "ShadowCaster" }
    5.  
    6.     ZWrite On
    7.     ZTest LEqual
    8.  
    9.     CGPROGRAM
    10.  
    11.     #pragma vertex vertShadowCaster
    12.     #pragma fragment fragShadowCaster
    13.  
    14.     StructuredBuffer<float4x4> obj2world;
    15.  
    16.     struct v2f
    17.     {
    18.         float4 vertex : SV_POSITION;
    19.         float2 uv : TEXCOORD0;
    20.     };
    21.  
    22.     v2f vertShadowCaster(appdata_base v, uint i : SV_InstanceID)
    23.     {
    24.         v2f o;
    25.  
    26.         v.vertex = mul(obj2world[i], v.vertex);
    27.         o.vertex = mul(UNITY_MATRIX_VP, v.vertex);
    28.  
    29.         o.uv = TRANSFORM_TEX(v.texcoord, _MainTex);
    30.  
    31.         return o;
    32.     }
    33.  
    34.     float4 fragShadowCaster(v2f i) : SV_Target
    35.     {      
    36.         return 0;
    37.     }
    38.    
    39.     ENDCG
    40. }
     
    fehencke likes this.