Unity Shader中如何学习阴影技术 产生阴影,接受阴影,联级阴影,软阴影
在Unity Shader里学习阴影关键是理解其核心——Shadow Map阴影贴图并掌握一套清晰的学习路径。你可以从了解全局开始然后逐步深入到各个技术点。 先构建全局视角阴影技术概览在深入代码之前建议先理清这些基础概念它们能帮你更好地理解后续的具体实现Shadow Map 原理它是现代实时阴影技术的基石。过程分两步第一步从光源视角将场景深度渲染到一张贴图里第二步在正常渲染时将当前片段的位置转换到光源空间比较其深度值与Shadow Map中存储的深度值以此判断该点是否处于阴影中。硬阴影 vs. 软阴影光线完全被遮挡会产生边缘锐利的硬阴影而现实中光源有体积会造成半影区产生边缘过渡柔和的软阴影真实感更强但性能开销也更大。阴影级联 (Shadow Cascades)专为解决方向光如太阳光在近处阴影出现的“透视锯齿”问题。它将摄像机的视锥体从近到远划分成多个区域级联为近处区域分配更高的阴影贴图分辨率来保证近处阴影的清晰度。关键API和宏编写Shader时Unity提供了便捷的宏。例如SHADOW_COORDS用于定义阴影坐标TRANSFER_SHADOW用于计算阴影坐标SHADOW_ATTENUATION用于获取阴影衰减值。不同渲染管线的差异内置渲染管线实现方式较直接但宏较多容易让新手混淆。URP推荐新手从URP开始。它的API和命名更清晰Shader结构也更现代化是Unity未来的主流方向。HDRP主要用于追求顶尖画质的项目默认阴影效果已经很完善通常不需要开发者从头编写阴影Shader。 循序渐进分步学习指南1. 产生阴影投射阴影这是实现阴影功能的基础让物体能够在地面或其他物体上留下影子。核心ShadowCasterPass一个物体要向场景投射阴影它的Shader必须包含ShadowCaster这个Pass。Unity在渲染阴影贴图时就是通过它来获取物体从光源视角看到的“样子”。快速实现方法一推荐新手使用UsePass命令。它能直接复用Unity内置Shader中的ShadowCasterPass是生成可投射阴影Shader最简单的方法。方法二手动实现在Shader中显式定义一个ShadowCasterPass。这能让你更深入地理解阴影贴图的渲染过程但代码会复杂一些。2. 接受阴影这是让你的Shader能够正确地响应其他物体投射过来的阴影。核心步骤声明阴影坐标在顶点着色器的输出结构体v2f中使用SHADOW_COORDS宏来定义一个用于存储阴影贴图采样坐标的成员。计算阴影坐标在顶点着色器中使用TRANSFER_SHADOW宏来计算阴影坐标并传递给片元着色器。采样并应用阴影在片元着色器中使用SHADOW_ATTENUATION宏来获取当前像素的阴影强度0为全阴影1为全光照然后用这个值乘以光照颜色即可得到阴影效果。完整的内置管线示例下面是一个内置管线中实现了接受阴影的完整Shader示例结合了漫反射光照Shader Lit/Diffuse With Shadows { Properties { _MainTex (Texture, 2D) white {} } SubShader { Pass { Tags {LightModeForwardBase} CGPROGRAM #pragma vertex vert #pragma fragment frag #include UnityCG.cginc #include Lighting.cginc #pragma multi_compile_fwdbase nolightmap nodirlightmap nodynlightmap novertexlight #include AutoLight.cginc struct v2f { float2 uv : TEXCOORD0; SHADOW_COORDS(1) // 1. 声明阴影坐标 fixed3 diff : COLOR0; fixed3 ambient : COLOR1; float4 pos : SV_POSITION; }; v2f vert (appdata_base v) { v2f o; o.pos UnityObjectToClipPos(v.vertex); o.uv v.texcoord; half3 worldNormal UnityObjectToWorldNormal(v.normal); half nl max(0, dot(worldNormal, _WorldSpaceLightPos0.xyz)); o.diff nl * _LightColor0.rgb; o.ambient ShadeSH9(half4(worldNormal,1)); TRANSFER_SHADOW(o); // 2. 传递阴影坐标 return o; } sampler2D _MainTex; fixed4 frag (v2f i) : SV_Target { fixed4 col tex2D(_MainTex, i.uv); fixed shadow SHADOW_ATTENUATION(i); // 3. 获取阴影衰减 fixed3 lighting i.diff * shadow i.ambient; col.rgb * lighting; return col; } ENDCG } UsePass Legacy Shaders/VertexLit/SHADOWCASTER // 复用投射阴影的Pass } FallBack Diffuse }3. 级联阴影 (Cascaded Shadow Maps)主要用于解决方向光阴影在近处的“透视锯齿”问题通过为不同距离的区域分配不同分辨率的阴影贴图来保证近处阴影清晰。配置与可视化在项目的Quality Settings内置管线或URP AssetURP管线中设置级联数量0、2或4。可以使用Rendering DebuggerWindow Analysis Rendering Debugger的Lighting Shadow Cascades选项来可视化每个级联的覆盖范围方便调优。Shader支持在Shader中只需要添加对应的预处理宏如_MAIN_LIGHT_SHADOWS_CASCADE引擎会自动处理级联的选择和采样。4. 软阴影 (Soft Shadows)通过模拟半影区域让阴影边缘看起来更柔和增强真实感。如何在项目中开启在光源的Inspector面板中将Shadow Type设置为Soft Shadows。在URP Asset中确保Soft Shadows选项已勾选。性能与技巧软阴影开销更大因为它需要对阴影贴图进行多重采样滤波。一个优化技巧是使用较低的阴影分辨率如1024并开启软阴影反而能获得视觉上更柔和的阴影效果。进阶PCSS (Percentage-Closer Soft Shadows)这是一种更高级的软阴影技术能根据遮挡物距离光源的远近动态改变阴影的软硬程度。PCSS的性能开销很高需要你编写复杂的自定义Shader或在Asset Store中寻找解决方案。⚡ 高级技巧与优化材质与物体设置在编辑器中物体的Mesh Renderer组件可单独控制是否“Cast Shadows”投射阴影和“Receive Shadows”接受阴影。处理透明材质Alpha Test镂空材质需要在ShadowCasterPass中进行裁剪以投射出符合形状的阴影。阴影顽疾 (Shadow Artifacts) 的解决常见问题包括阴影痤疮表面出现条纹状伪影和Peter Panning阴影与物体分离可以通过调整光源设置里的Bias参数来修复。Bias 的深刻影响Bias分为Depth Bias深度偏移和Normal Bias法线偏移。Depth Bias主要解决阴影痤疮而Normal Bias主要解决Peter Panning。调整这两个值是阴影调试中最关键的一步需要根据你的场景反复试验。性能调优级联阴影性能级联数量增加会成倍增加渲染开销建议在Quality Settings中严格限制阴影的Shadow Distance阴影距离。移动平台优化在移动设备上尽量使用硬阴影并限制阴影距离。如果必须使用软阴影务必做好性能分析Profiling。复杂几何体阴影对于高模或远处的物体可以考虑使用低模LOD来投射阴影以降低GPU负担。 总结与学习路径建议从URP开始建立新项目选择URP模板。理解原理学习Shadow Map的基本原理通过光源Shadow Type的不同设置直观对比硬阴影与软阴影、有无级联的视觉效果。编写Shader使用Shader Graph或手写HLSL Shader从最基本的“接受阴影”功能开始确保物体能正确响应光照和阴影。进阶实现手动添加ShadowCasterPass实现完整的阴影投射与接收。优化与调试学习调整光源的Bias、Shadow Distance等参数并使用Frame Debugger和Rendering Debugger来分析和优化阴影性能。