Search Unity

Ignore alpha when casting shadows from standard shader

Discussion in 'Shaders' started by wastvedt, Jun 8, 2016.

  1. wastvedt

    wastvedt

    Joined:
    Oct 6, 2012
    Posts:
    25
    See below for my current shader. I have a separate input for alpha as I'm generating the alpha programmatically and I have a static texture that tiles and is visible where the alpha doesn't cut out the object. What I'd like though, is for the shadows cast by this shader to behave as if there were no cutout, i.e. the entire object casts a shadow, not just the part that is left by the cutout. If I remove `addshadow` from the `#pragma surface` line, I get the full shadow as desired, but then no shadows are displayed behind the parts of the object that are cutout. As far as I can tell I think this should be possible with multiple passes, but I can't figure out how to combine a pass that just displays a shadow with the standard surface pass that show the cutout object.

    Code (CSharp):
    1. Shader "Custom/StandardAlphaCutout" {
    2.     Properties {
    3.         _Color ("Color", Color) = (1,1,1,1)
    4.         [NoScaleOffset] _MainTex ("Base (RGB)", 2D) = "white" {}
    5.  
    6.         [Normal] [NoScaleOffset] _Normal ("Normal (RGB)", 2D) = "bump" {}
    7.         _NormalScale ("Normal scale", Vector) = (1,1,1,0)
    8.  
    9.         [NoScaleOffset] _MetallicGlossMap("Metallic (R) Smoothness (A)", 2D) = "white" {}
    10.         _Metallic ("Metallic", Range(0,1)) = 0.0
    11.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    12.  
    13.         _Cutoff ("Base Alpha cutoff", Range (0,.9)) = .5
    14.         [Toggle(InvertAlpha)] _InvertAlpha("Invert alpha map?", Int) = 0
    15.         _AlphaTex ("Alpha Map (RGB)", 2D) = "white" {}
    16.     }
    17.  
    18.     SubShader {
    19.  
    20.         Tags {"Queue"="AlphaTest" "IgnoreProjector"="True" "RenderType"="TransparentCutout" }
    21.        
    22.         Cull Off
    23.        
    24.         CGPROGRAM
    25.  
    26.         #pragma shader_feature METALLICGLOSSMAP
    27.  
    28.         #pragma shader_feature InvertAlpha
    29.  
    30.         // Physically based Standard lighting model
    31.         #pragma surface surf Standard alphatest:_Cutoff addshadow
    32.  
    33.         // Use shader model 3.0 target, to get nicer looking lighting
    34.         #pragma target 3.0
    35.        
    36.         sampler2D _MainTex;
    37.         sampler2D _MetallicGlossMap;
    38.         sampler2D _AlphaTex;
    39.         sampler2D _Normal;
    40.        
    41.         struct Input {
    42.             float2 uv_MainTex;
    43.             float2 uv_AlphaTex;
    44.             float2 uv_MetallicGlossMap;
    45.             float2 uv_Normal;
    46.             fixed facing : VFACE;
    47.         };
    48.        
    49.         fixed4 _NormalScale;
    50.         fixed _Glossiness;
    51.         fixed _Metallic;
    52.         fixed4 _Color;
    53.  
    54.         void surf (Input IN, inout SurfaceOutputStandard o) {
    55.             // Albedo comes from a texture tinted by color
    56.             fixed4 c = tex2D ( _MainTex, IN.uv_MainTex ) * _Color;          
    57.             o.Albedo = c.rgb;
    58.  
    59.             fixed3 normal = UnpackNormal ( tex2D ( _Normal, IN.uv_Normal * _NormalScale.xy ) );
    60.             normal.xy *= _NormalScale.z;
    61.             o.Normal = normalize ( normal );
    62.  
    63.             // If we're rendering a back face, flip the normal.
    64.             if (IN.facing < 0.5)
    65.                 o.Normal *= -1.0;
    66.            
    67.             #if InvertAlpha
    68.             o.Alpha = 1 - tex2D ( _AlphaTex, IN.uv_AlphaTex ).a;
    69.             #else
    70.             o.Alpha = tex2D ( _AlphaTex, IN.uv_AlphaTex ).a;
    71.             #endif
    72.  
    73.  
    74.             #if METALLICGLOSSMAP
    75.             fixed4 mg = tex2D ( _MetallicGlossMap, IN.uv_MetallicGlossMap );
    76.             o.Metallic = mg.r;
    77.             o.Smoothness = mg.a;
    78.             #else
    79.             // Metallic and smoothness come from slider variables
    80.             o.Metallic = _Metallic;
    81.             o.Smoothness = _Glossiness;
    82.             #endif
    83.  
    84.         }
    85.         ENDCG
    86.  
    87.     }
    88.  
    89.     FallBack "Transparent/Cutout/Diffuse"
    90.     CustomEditor "StandardAlphaCutoutGUI"
    91. }
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,348
    The same shadow caster shader pass is used for both the shadow casting (via shadow maps) and main directional light shadow receiving by way of the depth texture. You can add some code to your surface function to see if it's being used as part of the shadow caster pass, then there are some semi-hacky methods for testing if the shadow caster pass is being used as part of the shadow map or the depth.

    Try adding this to the end of your surf function.

    #ifdef UNITY_PASS_SHADOWCASTER
    if (unity_LightShadowBias.z != 0.0) // is shadow map
    o.Alpha = 1.0;
    #endif


    http://forum.unity3d.com/threads/receive-shadows-but-dont-cast-any.406822/#post-2651281
     
  3. wastvedt

    wastvedt

    Joined:
    Oct 6, 2012
    Posts:
    25
    Perfect. Thanks! Sorry, I didn't see the linked thread in my research.