Search Unity

HELP! - Shader not receiving Point/Spotlight Shadows

Discussion in 'Shaders' started by IntelligentDesign, May 8, 2016.

  1. IntelligentDesign

    IntelligentDesign

    Joined:
    Jun 13, 2014
    Posts:
    51
    Hey all, so I've been attempting to write a MatCap shader that is able to accept light and shadows (which may seem counter-intuitive, I know, but it's more for educational purposes than anything else) and while I was able to get shadows functioning properly in my ForwardBase pass for some reason they aren't working in ForwardAdd. And to get it out of the way, I've made sure both my Player and Camera are set to Deferred rendering (not Legacy Deferred), and point and spot lights do have shadows turned on. Code below:

    Code (CSharp):
    1.     Properties
    2.     {
    3.         _Color ("Main Color", Color) = (0.5,0.5,0.5,1)
    4.         _BumpMap ("Normal Map", 2D) = "bump" {}
    5.         _MatCap ("MatCap (RGB)", 2D) = "white" {}
    6.         [Toggle(MATCAP_ACCURATE)] _MatCapAccurate ("Accurate Calculation", Int) = 0
    7.     }
    8.    
    9.     Subshader
    10.     {
    11.         Tags { "RenderType"="Opaque" }
    12.        
    13.         Pass
    14.         {
    15.             // **changed to ForwardBase
    16.             Tags { "LightMode" = "ForwardBase" }
    17.            
    18.             CGPROGRAM
    19.                 #pragma vertex vert
    20.                 #pragma fragment frag
    21.                 #pragma fragmentoption ARB_precision_hint_fastest
    22.                 #pragma shader_feature MATCAP_ACCURATE
    23.                 // **added the the pragma below
    24.                 #pragma multi_compile_fwdbase
    25.                 #pragma debug
    26.                 #include "UnityCG.cginc"
    27.                 // **added the include below
    28.                 #include "AutoLight.cginc"
    29.                
    30.                 struct v2f
    31.                 {
    32.                     float4 pos    : SV_POSITION;
    33.                     float2 uv_bump : TEXCOORD0;
    34.                     float3 normal : TEXCOORD1;
    35.                     float3 lightDir : TEXCOORD2;
    36.  
    37.  
    38.                    
    39.             #if MATCAP_ACCURATE
    40.                     fixed3 tSpace0 : TEXCOORD3;
    41.                     fixed3 tSpace1 : TEXCOORD4;
    42.                     fixed3 tSpace2 : TEXCOORD5;
    43.                     // **added lowest possible lighting_coords
    44.                     LIGHTING_COORDS(6,7)
    45.             #else
    46.                     float3 c0 : TEXCOORD3;
    47.                     float3 c1 : TEXCOORD4;
    48.                     // **added lowest possible lighting_coords
    49.                     LIGHTING_COORDS(5,6)
    50.             #endif
    51.                 };
    52.                
    53.                 uniform float4 _BumpMap_ST;
    54.                
    55.                 v2f vert (appdata_tan v)
    56.                 {
    57.                     v2f o;
    58.                     o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    59.                     o.uv_bump = TRANSFORM_TEX(v.texcoord,_BumpMap);
    60.                    
    61.                     #if MATCAP_ACCURATE
    62.                     //Accurate bump calculation: calculate tangent space matrix and pass it to fragment shader
    63.                     fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
    64.                     fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
    65.                     fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
    66.                     o.tSpace0 = fixed3(worldTangent.x, worldBinormal.x, worldNormal.x);
    67.                     o.tSpace1 = fixed3(worldTangent.y, worldBinormal.y, worldNormal.y);
    68.                     o.tSpace2 = fixed3(worldTangent.z, worldBinormal.z, worldNormal.z);
    69.                     // **added o.normal output
    70.                     o.normal = worldNormal;
    71.                     #else
    72.                     //Faster but less accurate method (especially on non-uniform scaling)
    73.                     v.normal = normalize(v.normal);
    74.                     v.tangent = normalize(v.tangent);
    75.                     TANGENT_SPACE_ROTATION;
    76.                     o.c0 = mul(rotation, normalize(UNITY_MATRIX_IT_MV[0].xyz));
    77.                     o.c1 = mul(rotation, normalize(UNITY_MATRIX_IT_MV[1].xyz));
    78.                     // **added o.normal output
    79.                     o.normal = UnityObjectToWorldNormal(v.normal);
    80.                     #endif
    81.                     // **added the below code to sample the lighting/shadow map
    82.                     TRANSFER_VERTEX_TO_FRAGMENT(o);
    83.                     o.lightDir = normalize(ObjSpaceLightDir(v.vertex));
    84.  
    85.                     return o;
    86.                 }
    87.                
    88.                 uniform float4 _Color;
    89.                 uniform sampler2D _MatCap;
    90.                 uniform sampler2D _BumpMap;
    91.                 float4 _LightColor0;
    92.                
    93.                 float4 frag (v2f i) : COLOR {
    94.                     // **added below line to get the light attenuation after the transfer (see above)
    95.                     float atten = LIGHT_ATTENUATION(i) * 2;
    96.                     fixed3 normals = UnpackNormal(tex2D(_BumpMap, i.uv_bump));
    97.  
    98.                     float3 L = normalize(i.lightDir);
    99.                     float3 N = normalize(i.normal);
    100.  
    101.                     float NdotL = saturate(dot(N,L));
    102.                     float4 diffuse = NdotL * atten;
    103.                    
    104.                     #if MATCAP_ACCURATE
    105.                     //Rotate normals from tangent space to world space
    106.                     float3 worldNorm;
    107.                     worldNorm.x = dot(i.tSpace0.xyz, normals);
    108.                     worldNorm.y = dot(i.tSpace1.xyz, normals);
    109.                     worldNorm.z = dot(i.tSpace2.xyz, normals);
    110.                     worldNorm = mul((float3x3)UNITY_MATRIX_V, worldNorm);
    111.                     float4 mc = tex2D(_MatCap, worldNorm.xy * 0.5 + 0.5);
    112.                     #else
    113.                     half2 capCoord = half2(dot(i.c0, normals), dot(i.c1, normals));
    114.                     float4 mc = tex2D(_MatCap, capCoord*0.5+0.5);
    115.                     #endif
    116.                     // ** added " * atten " to this line
    117.  
    118.                     float4 c = (_Color * _LightColor0) * mc * diffuse;
    119.                     float4 shadow = (1 - c) * UNITY_LIGHTMODEL_AMBIENT;
    120.                     return saturate(c + shadow);
    121.                 }
    122.             ENDCG
    123.         }
    124.  
    125.         Pass
    126.         {
    127.             // **changed to ForwardAdd
    128.             Tags { "LightMode" = "ForwardAdd" }
    129.             Blend One One
    130.            
    131.             CGPROGRAM
    132.                 #pragma vertex vert
    133.                 #pragma fragment frag
    134.                 #pragma fragmentoption ARB_precision_hint_fastest
    135.                 #pragma shader_feature MATCAP_ACCURATE
    136.                 // **added the the pragma below
    137.                 #pragma multi_compile_fwdadd
    138.                 #pragma debug
    139.                 #include "UnityCG.cginc"
    140.                 // **added the include below
    141.                 #include "AutoLight.cginc"
    142.                
    143.                 struct v2f
    144.                 {
    145.                     float4 pos    : SV_POSITION;
    146.                     float2 uv_bump : TEXCOORD0;
    147.                     float3 normal : TEXCOORD1;
    148.                     float3 lightDir : TEXCOORD2;
    149.  
    150.  
    151.                    
    152.             #if MATCAP_ACCURATE
    153.                     fixed3 tSpace0 : TEXCOORD3;
    154.                     fixed3 tSpace1 : TEXCOORD4;
    155.                     fixed3 tSpace2 : TEXCOORD5;
    156.                     // **added lowest possible lighting_coords
    157.                     LIGHTING_COORDS(6,7)
    158.             #else
    159.                     float3 c0 : TEXCOORD3;
    160.                     float3 c1 : TEXCOORD4;
    161.                     // **added lowest possible lighting_coords
    162.                     LIGHTING_COORDS(5,6)
    163.             #endif
    164.                 };
    165.                
    166.                 uniform float4 _BumpMap_ST;
    167.                
    168.                 v2f vert (appdata_tan v)
    169.                 {
    170.                     v2f o;
    171.                     o.pos = mul (UNITY_MATRIX_MVP, v.vertex);
    172.                     o.uv_bump = TRANSFORM_TEX(v.texcoord,_BumpMap);
    173.                    
    174.                     #if MATCAP_ACCURATE
    175.                     //Accurate bump calculation: calculate tangent space matrix and pass it to fragment shader
    176.                     fixed3 worldNormal = UnityObjectToWorldNormal(v.normal);
    177.                     fixed3 worldTangent = UnityObjectToWorldDir(v.tangent.xyz);
    178.                     fixed3 worldBinormal = cross(worldNormal, worldTangent) * v.tangent.w;
    179.                     o.tSpace0 = fixed3(worldTangent.x, worldBinormal.x, worldNormal.x);
    180.                     o.tSpace1 = fixed3(worldTangent.y, worldBinormal.y, worldNormal.y);
    181.                     o.tSpace2 = fixed3(worldTangent.z, worldBinormal.z, worldNormal.z);
    182.                     // **added o.normal output
    183.                     o.normal = worldNormal;
    184.                     #else
    185.                     //Faster but less accurate method (especially on non-uniform scaling)
    186.                     v.normal = normalize(v.normal);
    187.                     v.tangent = normalize(v.tangent);
    188.                     TANGENT_SPACE_ROTATION;
    189.                     o.c0 = mul(rotation, normalize(UNITY_MATRIX_IT_MV[0].xyz));
    190.                     o.c1 = mul(rotation, normalize(UNITY_MATRIX_IT_MV[1].xyz));
    191.                     // **added o.normal output
    192.                     o.normal = UnityObjectToWorldNormal(v.normal);
    193.                     #endif
    194.                     // **added the below code to sample the lighting/shadow map
    195.                     TRANSFER_VERTEX_TO_FRAGMENT(o);
    196.                     o.lightDir = normalize(ObjSpaceLightDir(v.vertex));
    197.  
    198.                     return o;
    199.                 }
    200.                
    201.                 uniform float4 _Color;
    202.                 uniform float4 _LightColor0;
    203.                 uniform sampler2D _MatCap;
    204.                 uniform sampler2D _BumpMap;
    205.                
    206.                 float4 frag (v2f i) : COLOR {
    207.                     // **added below line to get the light attenuation after the transfer (see above)
    208.                     float atten = LIGHT_ATTENUATION(i);
    209.                     fixed3 normals = UnpackNormal(tex2D(_BumpMap, i.uv_bump));
    210.  
    211.                     float3 L = normalize(i.lightDir);
    212.                     float3 N = normalize(i.normal);
    213.  
    214.                     float NdotL = saturate(dot(N,L));
    215.                     float4 diffuse = NdotL * atten;
    216.                    
    217.                     #if MATCAP_ACCURATE
    218.                     //Rotate normals from tangent space to world space
    219.                     float3 worldNorm;
    220.                     worldNorm.x = dot(i.tSpace0.xyz, normals);
    221.                     worldNorm.y = dot(i.tSpace1.xyz, normals);
    222.                     worldNorm.z = dot(i.tSpace2.xyz, normals);
    223.                     worldNorm = mul((float3x3)UNITY_MATRIX_V, worldNorm);
    224.                     float4 mc = tex2D(_MatCap, worldNorm.xy * 0.5 + 0.5);
    225.                     #else
    226.                     half2 capCoord = half2(dot(i.c0, normals), dot(i.c1, normals));
    227.                     float4 mc = tex2D(_MatCap, capCoord*0.5+0.5);
    228.                     #endif
    229.                     // ** added " * atten " to this line
    230.  
    231.                     float4 c = (_Color * mc * _LightColor0 * atten);
    232.                     return c;
    233.                 }
    234.             ENDCG
    235.         }
    236.  
    237.     }
    238.     Fallback "VertexLit"
    239. }
    The base is actually JMO's fantastic (and free!) MatCap shader pack, so for the sake of transparency I'll admit I don't understand all of the math completely but I'm hoping that won't be an issue to solve this

    Also if anyone happens to see other issues with my code, I'd appreciate it if you pointed them out. My understanding of shader code is still a little shaky