Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Resolved Is it possible to have an invisible shader that casts shadows, but does not receive them?

Discussion in 'Shaders' started by Awarets, Aug 12, 2023.

  1. Awarets

    Awarets

    Joined:
    Jan 5, 2019
    Posts:
    4


    I'm using Unity version 2022.3.5f1.

    I'm aware that it's possible to do this on a per-object level using the "Shadows Only" option in MeshRenderer, but I'm looking for a shader solution specifically so that I can apply this effect only to certain faces on a mesh, while keeping the others visible normally.

    Everything I've tried so far by searching doesn't seem to work properly in this version, they all produce this effect where the shadows on the object itself are still visible (I want only the casted shadows as shown in the image).

    Anybody know if doing this on the shader/material level is possible?
     
  2. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,081
    Make sure your shader have onlt shadowcaster pass and no other passes.
    Or make sure you set ColorMask 0 in main shader
     
  3. Awarets

    Awarets

    Joined:
    Jan 5, 2019
    Posts:
    4
    Doesn't work, it just produces the same result as shown above.

    Code (CSharp):
    1. Shader "InvisibleShadowCaster"
    2. {
    3.     SubShader
    4.     {
    5.         UsePass "VertexLit/SHADOWCASTER"
    6.     }
    7. }
    On Unity version 2022.3.5f1, built-in render pipeline, on a completely new empty project.
     
  4. JesOb

    JesOb

    Joined:
    Sep 3, 2012
    Posts:
    1,081
    It looks like you write in depth buffer somehow you can check it in frame debugger.
    You need t disable depth write for forward pass or deferred pass
     
  5. JSmithIR

    JSmithIR

    Joined:
    Apr 13, 2023
    Posts:
    84
    yeah i know this can be done, I remember doing it before. Keep trying
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,221
    The shadow caster pass is used for both the camera depth texture, and the shadow maps. This is a problem because directional shadows cast onto the camera depth texture.

    The solution is you need to detect if the current pass is being used for the camera depth texture or for shadows. This is non-trivial because there is no value that is always set to differentiate them. Unity's own code makes the assumption that any shadow map pass will have some amount of bias, where as the camera depth texture will have zero. As long as you don't set your lights have a bias of 0, this will work. But it does require a custom shadowcaster pass.

    Put this in the shadow caster shader's vertex function.
    Code (csharp):
    1. #ifdef SHADOWS_DEPTH
    2. if (unity_LightShadowBias.z == 0.0) {
    3.     // camera
    4.     o = (v2f)0;
    5.     return o;
    6. }
    7. #endif
     
  7. Awarets

    Awarets

    Joined:
    Jan 5, 2019
    Posts:
    4
    This works perfectly, thank you!

    Here's the full shader code I used, for reference:
    Code (CSharp):
    1. Shader "InvisibleShadowCaster"
    2. {
    3.     SubShader
    4.     {
    5.         Pass
    6.         {
    7.             Tags { "LightMode" = "ShadowCaster" }
    8.  
    9.             CGPROGRAM
    10.             #pragma vertex vert
    11.             #pragma fragment frag
    12.             #pragma multi_compile_shadowcaster
    13.             #include "UnityCG.cginc"
    14.  
    15.             struct v2f
    16.             {
    17.                 V2F_SHADOW_CASTER;
    18.             };
    19.  
    20.             v2f vert(appdata_base v)
    21.             {
    22.                 v2f o;              
    23.  
    24.                 // This only works as long as the Normal Bias setting for the light source is above 0
    25.                 #ifdef SHADOWS_DEPTH
    26.                 if (unity_LightShadowBias.z == 0.0)
    27.                 {
    28.                     // camera
    29.                     o = (v2f)0;
    30.                     return o;
    31.                 }
    32.                 #endif
    33.  
    34.                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    35.                 return o;
    36.             }
    37.  
    38.             float4 frag(v2f i) : SV_Target
    39.             {
    40.                 SHADOW_CASTER_FRAGMENT(i)
    41.             }
    42.             ENDCG
    43.         }
    44.     }
    45.     FallBack Off
    46. }