Search Unity

Shadows cast in the wrong way

Discussion in 'Shaders' started by axelsevenet, Sep 7, 2021.

  1. axelsevenet

    axelsevenet

    Joined:
    Jun 5, 2021
    Posts:
    4
    Hello I've been having problems with my shader code; I've tried to implement shadows in my code and they work fine but they are cast in the wrong way.
    Here you can see they are cast as if the Terrain below it was receiving the shadows but the flat blue surface should be receiving the shadows instead since it is opaque.

    Code (CSharp):
    1. {
    2.     Properties
    3.     {  
    4.         _MainTex ("Texture", 2D) = "white" {}
    5.         [Enum(Off,0,Front,1,Back,2)] _Cull ("Cull", Int) = 0
    6.  
    7.         _DepthMultiplier("Depth Multiplier", range(0,4)) = 1.2
    8.         _ShoreFadeStrength ("Shore Fade Strength", Range(0, 1)) = 0.777
    9.         _Smoothness ("Smoothness", range(0,1)) = 0.777
    10.  
    11.         _RipleScale ("Riple Wave Scale", float) = 1
    12.         _RipleSpeed ("Riple Wave Speed", float) = 1
    13.         _RipleFrequency ("Riple Wave Frequency", float) = 0.1
    14.  
    15.         _WaterNormalMap ("Wave Normal Texture", 2D) = "bump"
    16.         _WaterNoiseMap ("Wave Noise Texture", 2D) = "white"
    17.         _WaterDisplacementMap ("Wave Displacement Texture", 2D) = "white"
    18.  
    19.         _SurfaceNoiseScroll("Surface Noise Scroll Amount", Vector) = (0.03, 0.03, 0, 0)
    20.     }
    21.     SubShader
    22.     {
    23.        
    24.         Tags{
    25.             "RenderType"="Opaque"
    26.             "LightMode"="ForwardBase"
    27.             "PassFlags"="OnlyDirectional"
    28.         }
    29.         Cull [_Cull]
    30.         Blend SrcAlpha OneMinusSrcAlpha
    31.  
    32.         Pass
    33.         {
    34.             CGPROGRAM
    35.             #pragma vertex vert alpha
    36.             #pragma fragment frag alpha
    37.             #pragma multi_compile_fwdbase
    38.  
    39.             #include "UnityLightingCommon.cginc"
    40.             #include "UnityCG.cginc"
    41.             #include "AutoLight.cginc"
    42.  
    43.             uniform float _ShadowIntensity;
    44.  
    45.             struct vertexInput
    46.             {
    47.                 float4 vertex : POSITION;
    48.                 float3 normal : NORMAL;
    49.                 float3 tangent : TANGENT;
    50.             };
    51.  
    52.             struct v2f
    53.             {
    54.                 float4 pos : SV_POSITION;
    55.                 LIGHTING_COORDS(0,1)
    56.                 float3 normal : TEXCOORD2;
    57.                 float4 worldPosition : TEXCOORD3;
    58.                 float4 screenPosition : TEXCOORD4;
    59.                 float3 viewVector : TEXCOORD5;
    60.             };
    61.            
    62.             sampler2D _CameraDepthTexture;
    63.             sampler2D _WaterDisplacementMap;
    64.  
    65.             sampler2D _WaterNoiseMap;
    66.             sampler2D _WaterNormalMap;
    67.  
    68.             float4 _ColorShallow;
    69.             float4 _ColorDeep;
    70.  
    71.             float _DepthMultiplier;
    72.             float _AlphaMultiplier;
    73.             float _ShoreFadeStrength;
    74.             float _FoamDistance;
    75.  
    76.             float _NoiseScale;
    77.             float _NoiseStrength;
    78.            
    79.             float _DisturbanceScale;
    80.             float _DisturbanceSpeed;
    81.             float _DisturbanceFrequency;
    82.            
    83.             float3 _WindDirection;
    84.             float3 _DirToSun;
    85.             float _WaveOffset;
    86.  
    87.             /* float _RipleFrequency;
    88.             float _RipleSpeed;
    89.             float _RipleScale; */
    90.  
    91.             bool _IsPlane = false;
    92.  
    93.  
    94.             float CalculateNoise(float speed, float scale, float3 base){
    95.  
    96.                 float2 noiseUV = float2(base.x/150*(_NoiseScale*scale) + _WaveOffset*2*-_WindDirection.x/40*(_DisturbanceSpeed*speed), base.z/150*(_NoiseScale*scale) + _WaveOffset*2*-_WindDirection.z/40*_DisturbanceSpeed);
    97.                 return tex2Dlod(_WaterNoiseMap, float4(noiseUV.x, noiseUV.y,0,0)).r;
    98.             }
    99.  
    100.             float CalculateNewPosition(float3 base){
    101.  
    102.                 return _DisturbanceScale * sin(_WaveOffset*2*_DisturbanceSpeed + (base.x*_WindDirection.x + base.z*_WindDirection.z) * _DisturbanceFrequency);
    103.             }
    104.  
    105.             float3x3 CalculateNewNormal(float4 pos, float3 normal, float3 tangent, float offset, float smoothness){
    106.                
    107.                 float3 position = pos;
    108.                 position.xyz += normal * (offset + CalculateNewPosition(pos));
    109.  
    110.                 float3 modifiedTangent = pos + tangent;
    111.                 modifiedTangent.xyz += normal * (offset*smoothness + CalculateNewPosition(tangent));
    112.  
    113.                 float3 modifiedBitangent = pos + cross(normal, tangent);
    114.                 modifiedBitangent.xyz += normal * (offset*smoothness + CalculateNewPosition(modifiedBitangent));
    115.  
    116.                 modifiedTangent -= position;
    117.                 modifiedBitangent -= position;
    118.  
    119.                 return float3x3(position, modifiedTangent, modifiedBitangent);
    120.             }
    121.  
    122.             float calculateSpecular(float3 normal, float3 viewDir, float specularIntensity, float specularPower) {
    123.  
    124.                 float specularAngle = acos(dot(normalize(_DirToSun - viewDir), normal));
    125.                 float specularExponent = specularAngle / specularIntensity;
    126.                 float specularHighlight = exp(-specularExponent * specularExponent)*specularPower;
    127.                 return specularHighlight;
    128.             }
    129.  
    130.             v2f vert (vertexInput v)
    131.             {
    132.                 v2f o;
    133.                 UNITY_INITIALIZE_OUTPUT(v2f, o);
    134.                
    135.                 float surfaceNoiseSample = CalculateNoise(0.5, 0.3, v.vertex);
    136.                 float offset = float(surfaceNoiseSample-0.5)*_NoiseStrength;
    137.                
    138.                 float3x3 modifiedNormal = CalculateNewNormal(v.vertex, v.normal, v.tangent, offset, 2.5);
    139.  
    140.                 float3 position = modifiedNormal._11_12_13;
    141.                 float3 modifiedTangent = modifiedNormal._21_22_23;
    142.                 float3 modifiedBitangent = modifiedNormal._31_32_33;
    143.  
    144.                 o.pos = UnityObjectToClipPos(position);
    145.                 o.normal = normalize(mul(normalize(cross(modifiedTangent, modifiedBitangent)), (float3x3)unity_WorldToObject));
    146.  
    147.                 o.worldPosition = mul(unity_ObjectToWorld, o.pos);
    148.                 o.screenPosition = ComputeScreenPos(o.pos);
    149.                
    150.                 float3 viewVector = mul(unity_CameraInvProjection, float4((o.screenPosition.xy/o.screenPosition.w) * 2 - 1, 0, -1));
    151.                 o.viewVector = mul(unity_CameraToWorld, float4(viewVector,0));
    152.  
    153.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    154.                 return o;
    155.             }
    156.  
    157.  
    158.             float4 frag (v2f i) : SV_Target
    159.             {
    160.  
    161.                 float depthLinear = tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPosition)).r;
    162.                 float terrainDepth = LinearEyeDepth(depthLinear);
    163.                 float waterDepth = i.screenPosition.w;
    164.                 float waterThickness = terrainDepth - waterDepth;
    165.  
    166.                 float shoreFade = 1 - exp(-waterThickness * _ShoreFadeStrength);
    167.                 float fresnel = 1 - (saturate(dot(-_DirToSun, i.normal))/5 + (.5-_AlphaMultiplier));
    168.                 float waterAlpha = shoreFade * fresnel;
    169.  
    170.                 float diffuseTerm = clamp(dot(_DirToSun, i.normal),0,1);
    171.                 float diffuseLight = (diffuseTerm+0.5)/2;
    172.  
    173.  
    174.                 float2 noiseUV = float2(i.worldPosition.x/3 + _WaveOffset*2*-_WindDirection.x/6, i.worldPosition.z/3 + _WaveOffset*2*-_WindDirection.z/6);
    175.                 float surfaceNoiseSample = tex2Dlod(_WaterNoiseMap, float4(noiseUV.x, noiseUV.y,0,0)).r;
    176.                
    177.                 float surfaceFoam = waterThickness + tex2Dlod(_WaterNoiseMap, float4(i.worldPosition.x/100, i.worldPosition.y/100,0,0)).r/10 < 1 ? 1 : 0;
    178.                 surfaceFoam = saturate(surfaceFoam/(waterThickness*10));
    179.  
    180.  
    181.                 float3 waterColor = lerp(_ColorShallow * _LightColor0.xyz, _ColorDeep * _LightColor0.xyz, 1 - exp(-waterThickness * _DepthMultiplier));
    182.                 float specular = calculateSpecular(i.normal, normalize(i.viewVector), 0.3, 0.4);
    183.                 specular += calculateSpecular(i.normal, normalize(i.viewVector), 0.8, 0.15);
    184.  
    185.                 float attenuation = LIGHT_ATTENUATION(i);
    186.                 surfaceFoam *= saturate(attenuation + 0.2);
    187.                 specular *= attenuation;
    188.  
    189.                 return float4((waterColor + specular + surfaceFoam) * (diffuseLight * _LightColor0.xyz+.8 ) * saturate(attenuation + 0.7), waterAlpha);
    190.             }
    191.             ENDCG
    192.         }
    193.     }
    194. }

    I'm very confused as to how the Shadow pipeline works so if my mistake is obvious i'm sorry.

    Thank you for any help.
     
  2. aleksandrk

    aleksandrk

    Unity Technologies

    Joined:
    Jul 3, 2017
    Posts:
    3,023
    Hi!
    Try using UNITY_LIGHT_ATTENUATION and friends instead of LIGHT_ATTENUATION.
     
  3. axelsevenet

    axelsevenet

    Joined:
    Jun 5, 2021
    Posts:
    4
    Hello and thank you for your answer!

    I tried your suggestion but all it did was limit the distance from which the shadow can be seen (as seen in attached picture).
    I've tried updating the macros to their newer UNITY_ versions but it changed nothing.
     

    Attached Files:

  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,352
    This is a transparent surface using the opaque queue without a shadow caster pass.

    Unity's built in renderer doesn't support this kind of setup normally, because Unity casts shadows into the camera depth texture, not the geometry surface.

    You can add a custom shadow caster pass, which is what is used to generate the camera depth texture, so the shadows show up on the surface of the water, but then you can't do the depth fading / water edge you're doing since the depth texture you're sampling will just be seeing "itself". This is an intentional limitation of the built in renderer that does not have an easy solution.
     
    axelsevenet likes this.
  5. axelsevenet

    axelsevenet

    Joined:
    Jun 5, 2021
    Posts:
    4
    Thank you very much. That explains my issue very well!

    I don't really care for the fade and the depth gradient I just want the vertex displacement and shadows to work so it's not really a problem removing them
    Code (CSharp):
    1. // Upgrade NOTE: replaced '_Object2World' with 'unity_ObjectToWorld'
    2. // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'
    3.  
    4. {
    5.     Properties
    6.     {  
    7.         _MainTex ("Texture", 2D) = "white" {}
    8.         [Enum(Off,0,Front,1,Back,2)] _Cull ("Cull", Int) = 0
    9.  
    10.         _Smoothness ("Smoothness", range(0,1)) = 0.777
    11.  
    12.         _RipleScale ("Riple Wave Scale", float) = 1
    13.         _RipleSpeed ("Riple Wave Speed", float) = 1
    14.         _RipleFrequency ("Riple Wave Frequency", float) = 0.1
    15.  
    16.         _WaterNormalMap ("Wave Normal Texture", 2D) = "bump"
    17.         _WaterNoiseMap ("Wave Noise Texture", 2D) = "white"
    18.         _WaterDisplacementMap ("Wave Displacement Texture", 2D) = "white"
    19.  
    20.         _SurfaceNoiseScroll("Surface Noise Scroll Amount", Vector) = (0.03, 0.03, 0, 0)
    21.     }
    22.     SubShader
    23.     {
    24.        
    25.         Tags{
    26.             "RenderType"="TransparentCutout"
    27.             "LightMode"="ForwardBase"
    28.             "PassFlags"="OnlyDirectional"
    29.         }
    30.         Cull [_Cull]
    31.         Blend SrcAlpha OneMinusSrcAlpha
    32.  
    33.         Pass
    34.         {
    35.             CGPROGRAM
    36.             #pragma vertex vert alpha
    37.             #pragma fragment frag alpha
    38.             #pragma multi_compile_fwdbase
    39.  
    40.             #include "UnityLightingCommon.cginc"
    41.             #include "UnityCG.cginc"
    42.             #include "AutoLight.cginc"
    43.  
    44.             uniform float _ShadowIntensity;
    45.  
    46.             struct vertexInput
    47.             {
    48.                 float4 vertex : POSITION;
    49.                 float3 normal : NORMAL;
    50.                 float3 tangent : TANGENT;
    51.             };
    52.  
    53.             struct v2f
    54.             {
    55.                 float4 pos : SV_POSITION;
    56.                 UNITY_LIGHTING_COORDS(0,1)
    57.                 float3 normal : TEXCOORD2;
    58.                 float4 worldPosition : TEXCOORD3;
    59.                 float4 screenPosition : TEXCOORD4;
    60.                 float3 viewVector : TEXCOORD5;
    61.             };
    62.            
    63.             sampler2D _CameraDepthTexture;
    64.             sampler2D _WaterDisplacementMap;
    65.  
    66.             uniform sampler2D _WaterNoiseMap;
    67.             uniform sampler2D _WaterNormalMap;
    68.  
    69.             float4 _ColorShallow;
    70.             float4 _ColorDeep;
    71.  
    72.             uniform float _NoiseScale;
    73.             uniform float _NoiseStrength;
    74.            
    75.             uniform float _DisturbanceScale;
    76.             uniform float _DisturbanceSpeed;
    77.             uniform float _DisturbanceFrequency;
    78.            
    79.             uniform float3 _WindDirection;
    80.             uniform float _WaveOffset;
    81.             float3 _DirToSun;
    82.  
    83.             /* float _RipleFrequency;
    84.             float _RipleSpeed;
    85.             float _RipleScale; */
    86.  
    87.             bool _IsPlane = false;
    88.  
    89.  
    90.             float CalculateNoise(float speed, float scale, float3 base){
    91.  
    92.                 float2 noiseUV = float2(base.x/150*(_NoiseScale*scale) + _WaveOffset*2*-_WindDirection.x/40*(_DisturbanceSpeed*speed), base.z/150*(_NoiseScale*scale) + _WaveOffset*2*-_WindDirection.z/40*_DisturbanceSpeed);
    93.                 return tex2Dlod(_WaterNoiseMap, float4(noiseUV.x, noiseUV.y,0,0)).r;
    94.             }
    95.  
    96.             float CalculateNewPosition(float3 base){
    97.  
    98.                 return _DisturbanceScale * sin(_WaveOffset*2*_DisturbanceSpeed + (base.x*_WindDirection.x + base.z*_WindDirection.z) * _DisturbanceFrequency);
    99.             }
    100.  
    101.             float3x3 CalculateNewNormal(float4 pos, float3 normal, float3 tangent, float offset, float smoothness){
    102.                
    103.                 float3 position = pos;
    104.                 position.xyz += normal * (offset + CalculateNewPosition(pos));
    105.  
    106.                 float3 modifiedTangent = pos + tangent;
    107.                 modifiedTangent.xyz += normal * (offset*smoothness + CalculateNewPosition(tangent));
    108.  
    109.                 float3 modifiedBitangent = pos + cross(normal, tangent);
    110.                 modifiedBitangent.xyz += normal * (offset*smoothness + CalculateNewPosition(modifiedBitangent));
    111.  
    112.                 modifiedTangent -= position;
    113.                 modifiedBitangent -= position;
    114.  
    115.                 return float3x3(position, modifiedTangent, modifiedBitangent);
    116.             }
    117.  
    118.             float calculateSpecular(float3 normal, float3 viewDir, float specularIntensity, float specularPower) {
    119.  
    120.                 float specularAngle = acos(dot(normalize(_DirToSun - viewDir), normal));
    121.                 float specularExponent = specularAngle / specularIntensity;
    122.                 float specularHighlight = exp(-specularExponent * specularExponent)*specularPower;
    123.                 return specularHighlight;
    124.             }
    125.  
    126.             v2f vert (vertexInput v)
    127.             {
    128.                 v2f o;
    129.                 UNITY_INITIALIZE_OUTPUT(v2f, o);
    130.                
    131.                 float surfaceNoiseSample = CalculateNoise(0.5, 0.3, v.vertex);
    132.                 float offset = float(surfaceNoiseSample-0.5)*_NoiseStrength;
    133.                
    134.                 float3x3 modifiedNormal = CalculateNewNormal(v.vertex, v.normal, v.tangent, offset, 2.5);
    135.  
    136.                 float3 position = modifiedNormal._11_12_13;
    137.                 float3 modifiedTangent = modifiedNormal._21_22_23;
    138.                 float3 modifiedBitangent = modifiedNormal._31_32_33;
    139.  
    140.                 o.pos = UnityObjectToClipPos(position);
    141.                 o.normal = normalize(mul(normalize(cross(modifiedTangent, modifiedBitangent)), (float3x3)unity_WorldToObject));
    142.  
    143.                 o.worldPosition = mul(unity_ObjectToWorld, o.pos);
    144.                 o.screenPosition = ComputeScreenPos(o.pos);
    145.                
    146.                 float3 viewVector = mul(unity_CameraInvProjection, float4((o.screenPosition.xy/o.screenPosition.w) * 2 - 1, 0, -1));
    147.                 o.viewVector = mul(unity_CameraToWorld, float4(viewVector,0));
    148.  
    149.  
    150.                 TRANSFER_VERTEX_TO_FRAGMENT(o);
    151.                 return o;
    152.             }
    153.  
    154.  
    155.             float4 frag (v2f i) : SV_Target
    156.             {
    157.  
    158.                 /* float depthLinear = tex2Dproj(_CameraDepthTexture, UNITY_PROJ_COORD(i.screenPosition)).r;
    159.                 float terrainDepth = LinearEyeDepth(depthLinear);
    160.                 float waterDepth = i.screenPosition.w;
    161.                 float waterThickness = terrainDepth - waterDepth;*/
    162.  
    163.                 //float shoreFade = 1 - exp(-waterThickness * _ShoreFadeStrength);
    164.                 float fresnel = 1 - (saturate(dot(-_DirToSun, i.normal))/5 + (.5-_AlphaMultiplier));
    165.                 //float waterAlpha = shoreFade * fresnel;
    166.  
    167.                 float diffuseTerm = clamp(dot(_DirToSun, i.normal),0,1);
    168.                 float diffuseLight = (diffuseTerm+0.5)/2;
    169.  
    170.  
    171.                 float2 noiseUV = float2(i.worldPosition.x/3 + _WaveOffset*2*-_WindDirection.x/6, i.worldPosition.z/3 + _WaveOffset*2*-_WindDirection.z/6);
    172.                 float surfaceNoiseSample = tex2Dlod(_WaterNoiseMap, float4(noiseUV.x, noiseUV.y,0,0)).r;
    173.                
    174.                 /* float surfaceFoam = waterThickness + tex2Dlod(_WaterNoiseMap, float4(i.worldPosition.x/100, i.worldPosition.y/100,0,0)).r/10 < 1 ? 1 : 0;
    175.                 surfaceFoam = saturate(surfaceFoam/(waterThickness*10)); */
    176.  
    177.  
    178.                 float3 waterColor = lerp(_ColorShallow * _LightColor0.xyz, _ColorDeep * _LightColor0.xyz, 1);
    179.                 float specular = calculateSpecular(i.normal, normalize(i.viewVector), 0.3, 0.4);
    180.                 specular += calculateSpecular(i.normal, normalize(i.viewVector), 0.8, 0.15);
    181.  
    182.                 //UNITY_LIGHT_ATTENUATION(attenuation, i, i.worldPosition.xyz);
    183.                 float attenuation = LIGHT_ATTENUATION(i);
    184.                 //attenuation = 1;
    185.                 //float attenuation = SHADOW_ATTENUATION(i);
    186.                 surfaceFoam *= saturate(attenuation + 0.2);
    187.                 specular *= attenuation;
    188.  
    189.                 fresnel = saturate(fresnel+specular) - saturate(attenuation-0.8);
    190.  
    191.                 //return float4(attenuation,0,0,1);
    192.                 return float4((waterColor + specular + surfaceFoam) * (diffuseLight * _LightColor0.xyz+.8 ) * saturate(attenuation + 0.85), fresnel);
    193.             }
    194.             ENDCG
    195.         }
    196.  
    197.         Pass
    198.         {
    199.             Name "ShadowCaster"
    200.             Tags {"LightMode"="ShadowCaster"}
    201.             CGPROGRAM
    202.             #pragma vertex vert
    203.             #pragma fragment frag
    204.             #pragma multi_compile_shadowcaster
    205.             #include "UnityCG.cginc"
    206.             struct v2f {
    207.                 V2F_SHADOW_CASTER;
    208.             };
    209.  
    210.             sampler2D _WaterNoiseMap;
    211.             sampler2D _WaterNormalMap;
    212.  
    213.             uniform float _NoiseScale;
    214.             uniform float _NoiseStrength;
    215.            
    216.             uniform float _DisturbanceScale;
    217.             uniform float _DisturbanceSpeed;
    218.             uniform float _DisturbanceFrequency;
    219.            
    220.             uniform float3 _WindDirection;
    221.             uniform float _WaveOffset;
    222.  
    223.             float CalculateNoise(float speed, float scale, float3 base){
    224.  
    225.                 float2 noiseUV = float2(base.x/150*(_NoiseScale*scale) + _WaveOffset*2*-_WindDirection.x/40*(_DisturbanceSpeed*speed), base.z/150*(_NoiseScale*scale) + _WaveOffset*2*-_WindDirection.z/40*_DisturbanceSpeed);
    226.                 return tex2Dlod(_WaterNoiseMap, float4(noiseUV.x, noiseUV.y,0,0)).r;
    227.             }
    228.  
    229.             float CalculateNewPosition(float3 base){
    230.  
    231.                 return _DisturbanceScale * sin(_WaveOffset*2*_DisturbanceSpeed + (base.x*_WindDirection.x + base.z*_WindDirection.z) * _DisturbanceFrequency);
    232.             }
    233.  
    234.             v2f vert(appdata_base v)
    235.             {
    236.                 v2f o;
    237.                 TRANSFER_SHADOW_CASTER(o)
    238.                
    239.                 float surfaceNoiseSample = CalculateNoise(0.5, 0.3, v.vertex);
    240.                 float offset = float(surfaceNoiseSample-0.5)*_NoiseStrength;
    241.  
    242.                 float3 position = v.vertex;
    243.                 position.xyz += v.normal * (offset + CalculateNewPosition(position));
    244.  
    245.                 o.pos = UnityObjectToClipPos(position);
    246.  
    247.                 TRANSFER_SHADOW_CASTER_NORMALOFFSET(o)
    248.                 return o;
    249.             }
    250.             float4 frag(v2f i) : SV_Target
    251.             {
    252.                 SHADOW_CASTER_FRAGMENT(i)
    253.             }
    254.             ENDCG
    255.         }
    256.        
    257.     }
    258. }
    .
    So that's what I tried to do, I added a ShadowCaster Pass and tried to change the position of the cast to fit the displacement made in the first vertex shader but it "clips" some fragments under a certain height treshhold and returns an "empty pixel" instead of the color I'm giving it.
     

    Attached Files: