Search Unity

WrapLambert with Shadows

Discussion in 'Shaders' started by ErebosGames, Jun 8, 2014.

  1. ErebosGames

    ErebosGames

    Joined:
    Aug 1, 2012
    Posts:
    6
    Update: From further testing, I have found that a mesh with the WrapLambert shader can still cast shadows, but it will not receive them. However, even if I add a shadow collector to the bottom of the shader class, it still does not receive shadows. I tried adding this to the bottom (after the shadow caster):

    Code (CSharp):
    1.        
    2. Pass
    3.         {
    4.             Name "ShadowCollector"
    5.             Tags { "LightMode" = "ShadowCollector" }
    6.          
    7.             Fog {Mode Off}
    8.             ZWrite On ZTest LEqual
    9.  
    10.             CGPROGRAM
    11.             #pragma vertex vert
    12.             #pragma fragment frag
    13.             #pragma multi_compile_shadowcollector
    14.  
    15.             #define SHADOW_COLLECTOR_PASS
    16.             #include "UnityCG.cginc"
    17.  
    18.             struct appdata {
    19.                 float4 vertex : POSITION;
    20.             };
    21.  
    22.             struct v2f {
    23.                 V2F_SHADOW_COLLECTOR;
    24.             };
    25.  
    26.             v2f vert (appdata v)
    27.             {
    28.                 v2f o;
    29.                 TRANSFER_SHADOW_COLLECTOR(o)
    30.                 return o;
    31.             }
    32.  
    33.             fixed4 frag (v2f i) : COLOR
    34.             {
    35.                 SHADOW_COLLECTOR_FRAGMENT(i)
    36.             }
    37.             ENDCG
    38.         }
    Original Post: My goal is to have the effects of WrapLambert where light bleeds over edges, as well as geometry still casting and receiving shadows.


    If I use the Lambert surface shader, shadows cast appropriately, but light does not wrap around edges. If I use WrapLambert, light wraps around edges like it should -- but it doesn't cast/receive shadows!

    I have tried placing the Lambert shader code after the WrapLambert shader (and vice-versa) in the same file, but one just overwrites the other - they don't layer or combine in any way.

    How can I combine the effects of these two shaders?

    WrapLambert shader:
    Code (CSharp):
    1. Shader "Custom/BlockShader"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture For Diffuse Material Color", 2D) = "white" {}
    6.         _Color ("Overall Diffuse Color Filter", Color) = (1,1,1,1)
    7.     }
    8.     SubShader
    9.     {
    10.         //This has wrap, but not shadows
    11.         CGPROGRAM
    12.         #pragma surface surf WrapLambert
    13.         half4 LightingWrapLambert (SurfaceOutput s, half3 lightDir, half atten)
    14.         {
    15.             half NdotL = dot (s.Normal, lightDir);
    16.             half diff = NdotL * 0.7 + 0.3;
    17.             half4 c;
    18.             c.rgb = s.Albedo * _LightColor0.rgb * (diff * atten * 2);
    19.             c.a = s.Alpha;
    20.             return c;
    21.         }
    22.  
    23.         struct Input
    24.         {
    25.             float2 uv_MainTex;
    26.         };
    27.      
    28.         sampler2D _MainTex;
    29.         fixed4 _Color;
    30.  
    31.         void surf (Input IN, inout SurfaceOutput o)
    32.         {
    33.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    34.             o.Albedo = c.rgb;
    35.             o.Alpha = c.a;
    36.         }
    37.         ENDCG
    38.    
    39.         Pass
    40.         {
    41.             Name "ShadowCaster"
    42.             Tags { "LightMode" = "ShadowCaster" }
    43.        
    44.             Fog {Mode Off}
    45.             ZWrite On ZTest LEqual Cull Off
    46.             Offset 1, 1
    47.  
    48.             CGPROGRAM
    49.             #pragma vertex vert
    50.             #pragma fragment frag
    51.             #pragma multi_compile_shadowcaster
    52.             #include "UnityCG.cginc"
    53.  
    54.             struct v2f {
    55.                 V2F_SHADOW_CASTER;
    56.             };
    57.  
    58.             v2f vert( appdata_base v )
    59.             {
    60.                 v2f o;
    61.                 TRANSFER_SHADOW_CASTER(o)
    62.                 return o;
    63.             }
    64.  
    65.             float4 frag( v2f i ) : COLOR
    66.             {
    67.                 SHADOW_CASTER_FRAGMENT(i)
    68.             }
    69.             ENDCG
    70.         }
    71.     }
    72. }
    Lambert Shader:
    Code (CSharp):
    1. Shader "Custom/BlockShader"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex ("Texture For Diffuse Material Color", 2D) = "white" {}
    6.         _Color ("Overall Diffuse Color Filter", Color) = (1,1,1,1)
    7.     }
    8.     SubShader
    9.     {
    10.         //this allows for shadows, but doesn't allow wrap
    11.         CGPROGRAM
    12.         #pragma surface surf Lambert finalcolor:mycolor
    13.         sampler2D _MainTex;
    14.         fixed4 _Color;
    15.  
    16.         struct Input
    17.         {
    18.             float2 uv_MainTex;
    19.         };
    20.         void mycolor (Input IN, SurfaceOutput o, inout fixed4 color)
    21.         {
    22.             color.a = 1;
    23.         }
    24.  
    25.         void surf (Input IN, inout SurfaceOutput o)
    26.         {
    27.             fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color;
    28.             o.Albedo = c.rgb;
    29.             o.Alpha = c.a;
    30.         }
    31.         ENDCG
    32.    
    33.         Pass
    34.         {
    35.             Name "ShadowCaster"
    36.             Tags { "LightMode" = "ShadowCaster" }
    37.        
    38.             Fog {Mode Off}
    39.             ZWrite On ZTest LEqual Cull Off
    40.             Offset 1, 1
    41.  
    42.             CGPROGRAM
    43.             #pragma vertex vert
    44.             #pragma fragment frag
    45.             #pragma multi_compile_shadowcaster
    46.             #include "UnityCG.cginc"
    47.  
    48.             struct v2f {
    49.                 V2F_SHADOW_CASTER;
    50.             };
    51.  
    52.             v2f vert( appdata_base v )
    53.             {
    54.                 v2f o;
    55.                 TRANSFER_SHADOW_CASTER(o)
    56.                 return o;
    57.             }
    58.  
    59.             float4 frag( v2f i ) : COLOR
    60.             {
    61.                 SHADOW_CASTER_FRAGMENT(i)
    62.             }
    63.             ENDCG
    64.         }
    65.     }
    66. }
     
    Last edited: Jun 8, 2014
  2. metaleap

    metaleap

    Joined:
    Oct 3, 2012
    Posts:
    589
    If you're fine with Surface Shaders, just create a new one inside Unity (which will give you a clone of the built-in Diffuse shader to start off with) and then copy the WrapLambert lighting function into it as per http://docs.unity3d.com/Manual/SL-SurfaceShaderLighting.html --- there's no reason such a Surface Shader would behave differently than any others with respect to casting and receiving shadows, and speaking from experience, as a matter of fact it won't.
     
  3. Farfarer

    Farfarer

    Joined:
    Aug 17, 2010
    Posts:
    2,249
    Add in a fallback shader, that should let it receive and cast shadows.

    Diffuse should work, or simply VertexLit.

    Or you could add in the shadow caster/receiver passes yourself to your shader (but generally it's just easier to use the ones defined in the fallback).