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

Question Issues with both shadows and alpha cutoffs in Surface Shaders.

Discussion in 'Shaders' started by AkiraRagnas, Oct 3, 2023.

  1. AkiraRagnas

    AkiraRagnas

    Joined:
    Mar 15, 2016
    Posts:
    11
    Hello! I'm writing two shaders; one for a board of sorts, and one for a card that will float above it. I'd like both to be transparent (have the ability to fade in and out) as well as cast shadows. I am having two issues.

    The first is that the card has rounded edges, and the texture has rounded edges, so I tried to use alphatest to cut off the corners, but it's not cutting them off. In the editor, I can see that the alpha test is correctly rounding the edges, but it's rendering the corners anyway. If I switch to the Standard shader, it cuts them off in both Fade and Cutout Rendering Modes, so I don't think it's an issue with the imported files.

    The second is that the card is not casting shadows, despite my adding addshadow to the pragma surface surf line.

    Below is my code. Thank you for all your help! (The extra complication in the Board shader is to allow it to blend 3 materials.)

    Code (CSharp):
    1. Shader "Board"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1, 1, 1, 1)
    6.  
    7.         _NeutralTex ("Texture", 2D) = "white" {}
    8.  
    9.         _LunarTex ("Texture", 2D) = "white" {}
    10.         _LunarStrength ("Lunar Strength", Range(0,1)) = 0.0
    11.  
    12.         _SolarTex ("Texture", 2D) = "white" {}
    13.         _SolarStrength ("Solar Strength", Range(0,1)) = 0.0
    14.     }
    15.     SubShader
    16.     {
    17.         Tags { "Queue" = "Transparent" "RenderType" = "Transparent" }
    18.  
    19.         CGPROGRAM
    20.         #pragma surface surf Lambert alpha addshadow
    21.         #pragma target 3.0
    22.  
    23.         struct Input {
    24.             float2 uv_NeutralTex;
    25.             float2 uv_LunarTex;
    26.             float2 uv_SolarTex;
    27.         };
    28.  
    29.         float4 _Color;
    30.  
    31.         sampler2D _NeutralTex;
    32.  
    33.         float _LunarStrength;
    34.         sampler2D _LunarTex;
    35.  
    36.         float _SolarStrength;
    37.         sampler2D _SolarTex;
    38.  
    39.         void surf (Input IN, inout SurfaceOutput o) {
    40.             float4 col = lerp(tex2D(_NeutralTex, IN.uv_NeutralTex), tex2D(_LunarTex, IN.uv_LunarTex), _LunarStrength);
    41.             col = lerp(col, tex2D(_SolarTex, IN.uv_SolarTex), _SolarStrength);
    42.             o.Albedo = col.rgb * _Color;
    43.             o.Alpha = _Color.a;
    44.         }
    45.         ENDCG
    46.     }
    47.     Fallback "Diffuse"
    48. }

    Code (CSharp):
    1. Shader "Card" {
    2.     Properties {
    3.         _Color("Main Color", Color) = (1,1,1,1)
    4.         _MainTex("Texture", 2D) = "white" {}
    5.         _Cutoff("Cutoff", Range(0,1)) = 0.5
    6.     }
    7.  
    8.     SubShader {
    9.         Tags { "Queue" = "Transparent+10" "RenderType" = "Transparent" }
    10.  
    11.         CGPROGRAM
    12.         #pragma surface surf Lambert alpha alphatest:_Cutoff
    13.         #pragma target 3.0
    14.  
    15.         struct Input
    16.         {
    17.             float2 uv_MainTex;
    18.         };
    19.  
    20.         float4 _Color;
    21.  
    22.         sampler2D _MainTex;
    23.  
    24.         void surf(Input IN, inout SurfaceOutput o)
    25.         {
    26.             o.Albedo = tex2D(_MainTex, IN.uv_MainTex).rgb * _Color;
    27.             o.Alpha = _Color.a;
    28.         }
    29.         ENDCG
    30.     }
    31.  
    32.     Fallback "Diffuse"
    33. }
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    Neither shader are using the alpha from the texture. Only the
    _Color
    property's alpha value.

    You want to do something like this:
    Code (csharp):
    1. fixed4 col = tex2D(_MainTex, IN.uv_MainTex);
    2. o.Albedo = col.rgb * _Color;
    3. o.Alpha = col.a * _Color.a;
    As for shadows in the Board shader (which is what I'm guessing is you meant to say), Surface Shader's generated shadow caster pass doesn't work when
    alpha
    is used. You'll either want to use
    alphatest
    w/o
    alpha
    , or you need to write your own custom shadow caster pass.

    The Standard shader uses a custom shadow caster that works with both cutoff and fade, but you can't use it via the Fallback as you can't specify what keywords to enable for fallback passes. But you can look at that shader's shadow caster pass to get an idea of what the shadow caster pass's code needs to look like.

    https://github.com/TwoTailsGames/Un.../master/DefaultResourcesExtra/Standard.shader
    https://github.com/TwoTailsGames/Un...b/master/CGIncludes/UnityStandardShadow.cginc
     
  3. AkiraRagnas

    AkiraRagnas

    Joined:
    Mar 15, 2016
    Posts:
    11
    Thank you for the help! I will experiment and let you know how it all works.

    So just to confirm, I can’t have fading and the generated shadow pass together, right? I’d need to write my own shadow pass for that?

    Finally, stupid/noob question, if I want shadows to appear on something, do I need a shadow pass on the thing upon which the shadow is cast (the board, in this example), or on the thing which is casting shadows (the card, in this example), or both?
     
    Last edited: Oct 4, 2023
  4. AkiraRagnas

    AkiraRagnas

    Joined:
    Mar 15, 2016
    Posts:
    11
    EDIT: I should also say that removing alpha and adding addshadow to both also doesn't seem to work.

    Okay, I was able to get the cutout working. But I still can't get shadows; the shaders now look like this (I tried different orders, in case that mattered):

    Code (CSharp):
    1. Shader "Board"
    2. {
    3.     Properties
    4.     {
    5.         _Color ("Color", Color) = (1, 1, 1, 1)
    6.  
    7.         _NeutralTex ("Texture", 2D) = "white" {}
    8.  
    9.         _LunarTex ("Texture", 2D) = "white" {}
    10.         _LunarStrength ("Lunar Strength", Range(0,1)) = 0.0
    11.  
    12.         _SolarTex ("Texture", 2D) = "white" {}
    13.         _SolarStrength ("Solar Strength", Range(0,1)) = 0.0
    14.     }
    15.  
    16.     CGINCLUDE
    17.         #define UNITY_SETUP_BRDF_INPUT MetallicSetup
    18.     ENDCG
    19.  
    20.     SubShader
    21.     {
    22.         Tags { "Queue" = "Transparent" "RenderType" = "Opaque" }
    23.  
    24.         Pass
    25.         {
    26.             Name "ShadowCaster"
    27.             Tags { "LightMode" = "ShadowCaster" }
    28.  
    29.             ZWrite On ZTest LEqual
    30.  
    31.             CGPROGRAM
    32.             #pragma target 3.0
    33.  
    34.             // -------------------------------------
    35.  
    36.  
    37.             #pragma shader_feature_local _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
    38.             #pragma shader_feature_local _METALLICGLOSSMAP
    39.             #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
    40.             #pragma shader_feature_local _PARALLAXMAP
    41.             #pragma multi_compile_shadowcaster
    42.             #pragma multi_compile_instancing
    43.             // Uncomment the following line to enable dithering LOD crossfade. Note: there are more in the file to uncomment for other passes.
    44.             //#pragma multi_compile _ LOD_FADE_CROSSFADE
    45.  
    46.             #pragma vertex vertShadowCaster
    47.             #pragma fragment fragShadowCaster
    48.  
    49.             #include "UnityStandardShadow.cginc"
    50.  
    51.             ENDCG
    52.         }
    53.  
    54.         CGPROGRAM
    55.         #pragma surface surf Lambert alpha
    56.         #pragma target 3.0
    57.  
    58.         struct Input {
    59.             float2 uv_NeutralTex;
    60.             float2 uv_LunarTex;
    61.             float2 uv_SolarTex;
    62.         };
    63.  
    64.         float4 _Color;
    65.  
    66.         sampler2D _NeutralTex;
    67.  
    68.         float _LunarStrength;
    69.         sampler2D _LunarTex;
    70.  
    71.         float _SolarStrength;
    72.         sampler2D _SolarTex;
    73.  
    74.         void surf (Input IN, inout SurfaceOutput o) {
    75.             float4 col = lerp(tex2D(_NeutralTex, IN.uv_NeutralTex), tex2D(_LunarTex, IN.uv_LunarTex), _LunarStrength);
    76.             col = lerp(col, tex2D(_SolarTex, IN.uv_SolarTex), _SolarStrength);
    77.             o.Albedo = col.rgb * _Color;
    78.             o.Alpha = col.a * _Color.a;
    79.         }
    80.         ENDCG
    81.     }
    82.     Fallback "Diffuse"
    83. }
    84.  
    Code (CSharp):
    1. Shader "Card" {
    2.     Properties {
    3.         _Color("Main Color", Color) = (1,1,1,1)
    4.         _MainTex("Texture", 2D) = "white" {}
    5.         _Cutoff("Cutoff", Range(0,1)) = 0.5
    6.     }
    7.  
    8.     SubShader {
    9.         Tags { "Queue" = "Transparent" "RenderType" = "Transparent" }
    10.  
    11.         CGPROGRAM
    12.         #pragma surface surf Lambert alpha alphatest:_Cutoff
    13.         #pragma target 3.0
    14.  
    15.         struct Input
    16.         {
    17.             float2 uv_MainTex;
    18.         };
    19.  
    20.         float4 _Color;
    21.  
    22.         sampler2D _MainTex;
    23.  
    24.         void surf(Input IN, inout SurfaceOutput o)
    25.         {
    26.             fixed4 col = tex2D(_MainTex, IN.uv_MainTex);
    27.             o.Albedo = col.rgb * _Color;
    28.             o.Alpha = col.a * _Color.a;
    29.         }
    30.         ENDCG
    31.  
    32.         Pass
    33.         {
    34.             Name "ShadowCaster"
    35.             Tags { "LightMode" = "ShadowCaster" }
    36.  
    37.             ZWrite On ZTest LEqual
    38.  
    39.             CGPROGRAM
    40.             #pragma target 3.0
    41.  
    42.             // -------------------------------------
    43.  
    44.  
    45.             #pragma shader_feature_local _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
    46.             #pragma shader_feature_local _METALLICGLOSSMAP
    47.             #pragma shader_feature_local _SMOOTHNESS_TEXTURE_ALBEDO_CHANNEL_A
    48.             #pragma shader_feature_local _PARALLAXMAP
    49.             #pragma multi_compile_shadowcaster
    50.             #pragma multi_compile_instancing
    51.             // Uncomment the following line to enable dithering LOD crossfade. Note: there are more in the file to uncomment for other passes.
    52.             //#pragma multi_compile _ LOD_FADE_CROSSFADE
    53.  
    54.             #pragma vertex vertShadowCaster
    55.             #pragma fragment fragShadowCaster
    56.  
    57.             #include "UnityStandardShadow.cginc"
    58.  
    59.             ENDCG
    60.         }
    61.     }
    62.  
    63.     Fallback "Diffuse"
    64. }
     
    Last edited: Oct 4, 2023
  5. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
    Order doesn’t matter, no. However you can’t just use the Standard shader’s shadow pass unmodified, because by default it’s not going to do anything but opaque shadows, and if you force the keywords on to enable the features you want it’s going to be trying to use properties your shader does not have and end up breaking or throwing errors. Which is why I linked the cginc file with the actual shader code. You’ll need to construct your own shadow caster shader pass that does the things you want using the textures you want.

    As for receiving shadows, Unity’s built in rendering path does not support transparent objects receiving shadows. And any object in the Transparent queue will not receive any shadow information regardless of if it’s actually transparent or not.

    No, there’s not a simple work around. There’s some examples out there that’ll let you get a single directional light working, but it requires some c#, a few extra helper objects in the scene, and a lot of custom shader code. It’s not realistically something you can use with surface shaders easily for example.

    My suggestion to you is if you want shadow receiving, change the queue to AlphaTest, and use dithering to fade objects out. Otherwise switch to the URP and using Shader Graph, which does support shadow receiving on transparencies… though annoyingly shadow casting transparencies made using shader graph has been broken for several years now and I don’t know if they finally fixed it or not.
     
  6. AkiraRagnas

    AkiraRagnas

    Joined:
    Mar 15, 2016
    Posts:
    11
    Oof, that's disappointing. Again, I appreciate your help. It seems like there's no good way to workaround the shadow issue, so maybe I can work around the fading issue? What do you mean by using dithering to fade objects in and out?
     
  7. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,238
  8. AkiraRagnas

    AkiraRagnas

    Joined:
    Mar 15, 2016
    Posts:
    11
    Thank you for the help!