Search Unity

UNITY_SAMPLE_SHADOW correct usage

Discussion in 'Shaders' started by JibbSmart, May 19, 2016.

  1. JibbSmart

    JibbSmart

    Joined:
    Feb 18, 2013
    Posts:
    26
    Hi,

    I've been working on shaders for my game on my laptop, which is great, because I can easily switch between testing on Intel integrated graphics (both for low-end performance and compatibility testing) and a more powerful Nvidia card.

    While using Intel, I thought I had hardware-filtered shadows working nicely, using UNITY_SAMPLE_SHADOW. But when I tested it on Nvidia, it didn't work.

    Here's my shader:
    Code (CSharp):
    1. Shader "Custom/KustomShader"
    2. {
    3.     SubShader
    4.     {
    5.         Tags { "RenderType"="Opaque" "IgnoreProjector"="True" "Queue"="Geometry" }
    6.         LOD 200
    7.  
    8.         Pass
    9.         {
    10.             CGPROGRAM
    11.             #pragma vertex vert
    12.             #pragma fragment frag
    13.             #pragma target 3.0
    14.            
    15.             #include "UnityCG.cginc"
    16.  
    17.             struct appdata
    18.             {
    19.                 float4 vertex : POSITION;
    20.                 float3 normal : NORMAL;
    21.                 float2 uv : TEXCOORD0;
    22.                 float4 tangent : TANGENT;
    23.             };
    24.  
    25.             struct v2f
    26.             {
    27.                 float4 vertex : SV_POSITION;
    28.                 float3 normal : TEXCOORD0;
    29.                 float4 shadowPos : TEXCOORD1;
    30.             };
    31.  
    32.             UNITY_DECLARE_SHADOWMAP(_ShadowDepth);
    33.             //sampler2D _ShadowDepth;
    34.             float4x4 _ShadowVP;
    35.             float4x4 _ShadowV;
    36.            
    37.             float4 _SunVec;
    38.             float4 _SunColour;
    39.             float4 _SkyAmbientColour;
    40.            
    41.             v2f vert (appdata v)
    42.             {
    43.                 v2f output;
    44.            
    45.                 float4x4 modelMatrix = _Object2World;
    46.  
    47.                 float4 worldPos = mul(modelMatrix, v.vertex);
    48.                 output.vertex = mul(UNITY_MATRIX_MVP, worldPos);
    49.  
    50.                 output.shadowPos = mul(_ShadowVP, worldPos);
    51.                 output.shadowPos.z = -mul(_ShadowV, worldPos).z;
    52.  
    53.                 output.normal = v.normal * 0.5 + 0.5;
    54.  
    55.                 return output;
    56.             }
    57.            
    58.             fixed4 frag (v2f input) : SV_Target
    59.             {
    60.                 float3 baseColour = input.normal;
    61.  
    62.                 float3 shadowCoords = input.shadowPos.xyz;
    63.                 shadowCoords.xy /= input.shadowPos.w;
    64.                 shadowCoords.xy = shadowCoords.xy * 0.5 + 0.5;
    65.                    shadowCoords.z -= 0.01; // bias...
    66.  
    67.                 //float shadow = step(shadowCoords.z, tex2D(_ShadowDepth, shadowCoords.xy).r);
    68.                 float shadow = UNITY_SAMPLE_SHADOW(_ShadowDepth, shadowCoords.xyz);
    69.  
    70.                 return float4(baseColour * shadow, 1.0);
    71.             }
    72.             ENDCG
    73.         }
    74.     }
    75.     FallBack "Diffuse"
    76. }
    77.  
    If I comment out the lines UNITY_DECLARE_SHADOWMAP... and UNITY_SAMPLE_SHADOW..., and uncomment the lines next to them (sampler2D... and float shadow = step...), I get hard shadows, as one would expect, on both Intel and Nvidia.

    I thought UNITY_SAMPLE_SHADOW, apart from being the filtered result of the 4 nearest texels, would be mostly equivalent to step(shadowCoords.z, tex2D(_ShadowDepth, shadowCoords.xy).r), and it works on Intel, but for some reason it's all zero on Nvidia.

    I couldn't find an example online of the correct usage of UNITY_SAMPLE_SHADOW. Can anyone provide me such an example, or point out what's wrong with my code?

    Thanks so much,
    Jibb
     
  2. JibbSmart

    JibbSmart

    Joined:
    Feb 18, 2013
    Posts:
    26
    I solved it. I somehow missed that UNITY_DECLARE_SHADOWMAP and UNITY_SAMPLE_SHADOW are only supposed to work with render textures using the "Shadowmap" format. Then it took me a while to figure out that it wasn't using the colour output from the shader used to render everything into the shadowmap -- it seems to just use the shadowmap's depth buffer. That would've been helpful information if it was in the manual :p This meant I had to change my calculation of the fragment's position (depth, specifically) in the shadow camera's space to match. In my case, this just meant removing line 51.
     
    Pr0x1d, guycalledfrank and candycat like this.
  3. georgerh

    georgerh

    Joined:
    Feb 28, 2020
    Posts:
    72
    Thank you so much for posting the answer, @JibbSmart. Don't know how many years it would have taken me to find out that there is a RenderTextureFormat.Shadowmap!
     
  4. hippocoder

    hippocoder

    Digital Ape

    Joined:
    Apr 11, 2010
    Posts:
    29,723
    That's the subtitle for the Unity Movie!
     
    Pr0x1d likes this.