源码 / Ch03/C03_07_ShadowDepth.shader
Ch03/C03_07_ShadowDepth.shader
// 第 7 步:补上 ShadowCaster 和 DepthOnly 两个 Pass —— 能投射阴影,也能出现在深度图里。 Shader "Cookbook/Ch03/ShadowDepth" { Properties { [MainTexture] _BaseMap ("Base Map", 2D) = "white" {} [MainColor] _BaseColor ("Base Color", Color) = (1, 1, 1, 1) _Cutoff ("Alpha Cutoff", Range(0, 1)) = 0.5 [Enum(UnityEngine.Rendering.CullMode)] _Cull ("Cull", Float) = 2 } SubShader { Tags { "RenderType"="TransparentCutout" "RenderPipeline"="UniversalPipeline" "Queue"="AlphaTest" } HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; half4 _BaseColor; half _Cutoff; CBUFFER_END TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); // 三个 Pass 都要做同样的裁剪,抽成函数,保证“看到的形状 = 阴影形状 = 深度形状” void ClipByAlpha(float2 uv) { half a = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv).a * _BaseColor.a; clip(a - _Cutoff); } ENDHLSL // ---------------- 1. 颜色 Pass(与第 6 步相同) ---------------- Pass { Name "Unlit" Tags { "LightMode"="UniversalForward" } Cull [_Cull] HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile_fog struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; half4 color : COLOR; }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; half4 color : COLOR; float fogFactor : TEXCOORD1; }; Varyings vert (Attributes input) { Varyings output; output.positionCS = TransformObjectToHClip(input.positionOS.xyz); output.uv = TRANSFORM_TEX(input.uv, _BaseMap); output.color = input.color; output.fogFactor = ComputeFogFactor(output.positionCS.z); return output; } half4 frag (Varyings input) : SV_Target { half4 tex = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv); // 裁剪只看 贴图a × 颜色a,与 ClipByAlpha 完全一致;顶点色只影响 rgb clip(tex.a * _BaseColor.a - _Cutoff); half3 rgb = tex.rgb * _BaseColor.rgb * input.color.rgb; rgb = MixFog(rgb, input.fogFactor); return half4(rgb, 1); } ENDHLSL } // ---------------- 2. 阴影投射 Pass:把物体画进光源的 Shadow Map ---------------- Pass { Name "ShadowCaster" Tags { "LightMode"="ShadowCaster" } ZWrite On ZTest LEqual ColorMask 0 // 只要深度,不写颜色 Cull [_Cull] HLSLPROGRAM #pragma vertex ShadowVert #pragma fragment ShadowFrag // 点光/聚光的阴影要用 _LightPosition 逐顶点求光方向,方向光用 _LightDirection #pragma multi_compile_vertex _ _CASTING_PUNCTUAL_LIGHT_SHADOW // Shadows.hlsl 用到了 CommonMaterial.hlsl 里的 LerpWhiteTo,单独引用时要先包含它 #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/CommonMaterial.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Shadows.hlsl" // 由 URP 在渲染阴影前设置(ShadowUtils.SetupShadowCasterConstantBuffer) float3 _LightDirection; float3 _LightPosition; struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float2 uv : TEXCOORD0; }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; }; Varyings ShadowVert (Attributes input) { Varyings output; float3 positionWS = TransformObjectToWorld(input.positionOS.xyz); float3 normalWS = TransformObjectToWorldNormal(input.normalOS); #if defined(_CASTING_PUNCTUAL_LIGHT_SHADOW) float3 lightDirectionWS = normalize(_LightPosition - positionWS); #else float3 lightDirectionWS = _LightDirection; #endif // 沿光方向和法线方向各推一点,减轻自阴影条纹(Shadow Acne),细节见第 6 章 positionWS = ApplyShadowBias(positionWS, normalWS, lightDirectionWS); output.positionCS = TransformWorldToHClip(positionWS); // 把超出近平面的投射体压回近平面,避免被裁掉导致阴影缺块 #if UNITY_REVERSED_Z output.positionCS.z = min(output.positionCS.z, UNITY_NEAR_CLIP_VALUE); #else output.positionCS.z = max(output.positionCS.z, UNITY_NEAR_CLIP_VALUE); #endif output.uv = TRANSFORM_TEX(input.uv, _BaseMap); return output; } half4 ShadowFrag (Varyings input) : SV_Target { ClipByAlpha(input.uv); // 镂空的地方不投影 return 0; } ENDHLSL } // ---------------- 3. 深度 Pass:深度预渲染(Depth Prepass)时把物体写进 _CameraDepthTexture ---------------- Pass { Name "DepthOnly" Tags { "LightMode"="DepthOnly" } ZWrite On ColorMask R // URP 自带 Shader 的写法;深度写进深度缓冲,颜色通道基本用不到 Cull [_Cull] HLSLPROGRAM #pragma vertex DepthVert #pragma fragment DepthFrag struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; }; Varyings DepthVert (Attributes input) { Varyings output; output.positionCS = TransformObjectToHClip(input.positionOS.xyz); output.uv = TRANSFORM_TEX(input.uv, _BaseMap); return output; } half DepthFrag (Varyings input) : SV_Target { ClipByAlpha(input.uv); return input.positionCS.z; } ENDHLSL } } }