Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

HELP PLS: Implementing Volumetric Shadows

Discussion in 'Shaders' started by Penquen, Oct 13, 2021.

  1. Penquen

    Penquen

    Joined:
    Oct 13, 2021
    Posts:
    2
    Hello...

    I am just getting started in the Unity shaders world and am just trying to understand the Stencil Buffer. How would one go about using the stencil buffer to rendering correctly shadow volume meshes?

    So on overlap with other objects, they show a hard shadow...

    Any help would be really appreciated...
     
  2. Przemyslaw_Zaworski

    Przemyslaw_Zaworski

    Joined:
    Jun 9, 2017
    Posts:
    327
    "Shadow Volume" technique - the simplest example. Works for 3D Object / Sphere.
    It extrudes mesh vertices which are not lit by Directional Light (where angle is below zero).
    It is done twice, in first and second pass. First pass renders mesh with backface culling.
    Second pass renders mesh with frontface culling. With proper stencil buffer setup, we get a difference
    between volume shape from both cull modes. It is a shadow !
    When vertices are displaced with vertex shader, but base object is not in camera frustum, extruded vertices will be invisible.
    It is possible to edit mesh bounds as workaround:
    this.GetComponent<MeshFilter>().sharedMesh.bounds = new Bounds(new Vector3(0f, 0f, 0f), new Vector3(500f, 500f, 500f));

    Code (CSharp):
    1. Shader "Shadow Volume For Sphere Only"
    2. {
    3.     SubShader
    4.     {
    5.         Tags { "RenderType"="Opaque" "Queue"="Overlay"}
    6.         ZWrite Off
    7.         Pass
    8.         {
    9.             Cull Back
    10.             ZTest Greater
    11.             ColorMask 0
    12.             Stencil
    13.             {
    14.                 Ref 1
    15.                 Comp Always
    16.                 Pass Replace
    17.             }
    18.  
    19.             CGPROGRAM
    20.             #pragma vertex VSMain
    21.             #pragma fragment PSMain
    22.  
    23.             void VSMain (inout float4 vertex : POSITION, in float3 normal : NORMAL)
    24.             {
    25.                 float4 worldPos = mul(unity_ObjectToWorld, vertex);
    26.                 float3 normalDir = normalize(mul(unity_ObjectToWorld, float4(normal, 0.0))).xyz;
    27.                 float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
    28.                 float angle = dot(lightDir, normalDir);
    29.                 if (angle < 0.0) worldPos.xyz = worldPos.xyz - lightDir * 1000.0f;
    30.                 vertex = mul(UNITY_MATRIX_VP, worldPos);
    31.             }
    32.  
    33.             void PSMain (float4 vertex : POSITION, out float4 fragColor : SV_Target)
    34.             {
    35.                 fragColor = 0.1;
    36.             }
    37.             ENDCG
    38.         }
    39.        
    40.  
    41.         Pass
    42.         {
    43.             Cull Front
    44.             ZTest Greater
    45.             Stencil
    46.             {
    47.                 Ref 1
    48.                 Comp NotEqual
    49.             }
    50.  
    51.             CGPROGRAM
    52.             #pragma vertex VSMain
    53.             #pragma fragment PSMain
    54.  
    55.             void VSMain (inout float4 vertex : POSITION, in float3 normal : NORMAL)
    56.             {
    57.                 float4 worldPos = mul(unity_ObjectToWorld, vertex);
    58.                 float3 normalDir = normalize(mul(unity_ObjectToWorld, float4(normal, 0.0))).xyz;
    59.                 float3 lightDir = normalize(_WorldSpaceLightPos0.xyz);
    60.                 float angle = dot(lightDir, normalDir);
    61.                 if (angle < 0.0) worldPos.xyz = worldPos.xyz - lightDir * 1000.0f;
    62.                 vertex = mul(UNITY_MATRIX_VP, worldPos);
    63.             }
    64.  
    65.             void PSMain (float4 vertex : POSITION, out float4 fragColor : SV_Target)
    66.             {
    67.                 fragColor = 0.1;
    68.             }
    69.             ENDCG
    70.         }
    71.  
    72.         Pass
    73.         {
    74.            
    75.             CGPROGRAM
    76.             #pragma vertex VSMain
    77.             #pragma fragment PSMain
    78.  
    79.             void VSMain (inout float4 vertex : POSITION, inout float3 normal : NORMAL)
    80.             {
    81.                 normal = normalize(mul(unity_ObjectToWorld, float4(normal, 0.0))).xyz;
    82.                 vertex = UnityObjectToClipPos(vertex);
    83.             }
    84.  
    85.             void PSMain (float4 vertex : POSITION, float3 normal : NORMAL, out float4 fragColor : SV_Target)
    86.             {
    87.                 float angle = dot(normalize(_WorldSpaceLightPos0.xyz), normal);
    88.                 fragColor = float4(angle.xxx, 1.0);
    89.             }
    90.             ENDCG
    91.         }
    92.     }
    93. }