Unity shader中TransformWorldToShadowCoord原理解析

张开发
2026/4/18 18:57:25 15 分钟阅读

分享文章

Unity shader中TransformWorldToShadowCoord原理解析
TransformWorldToShadowCoord的核心作用很简单将你提供的世界坐标转换到一个可以用于采样 Shadow Map 的坐标空间。它本质上是为你省去了手动编写矩阵乘法的繁琐步骤。 核心原理一个“三步走”的幕后过程函数内部主要执行了以下三个步骤获取矩阵获取从“世界空间”转换到“阴影空间”的核心矩阵unity_WorldToShadow。方向光需处理阴影级联Shadow Cascades因此是一个包含最多4个矩阵的数组unity_WorldToShadow[4]。聚光灯/点光源通常只用一个矩阵unity_WorldToLight。执行变换执行矩阵乘法mul(unity_WorldToShadow[selectedIndex], float4(worldPos, 1.0))将世界坐标转换到阴影空间的齐次坐标。处理齐次坐标对于聚光灯或点光源这类透视投影需要执行透视除法shadowCoord.xyz / shadowCoord.w将坐标映射到0-1范围以得到最终的Shadow Map UV坐标而方向光由于是正交投影w分量为1则无需此步骤。此外函数内部还会根据是否启用级联阴影映射_MAIN_LIGHT_SHADOWS_CASCADE进行相应处理。当启用时它会选择正确的unity_WorldToShadow矩阵索引来计算坐标。 一个更直观的理解你可以将这个过程类比为TransformWorldToShadowCoord是一个翻译器它将物体的世界坐标翻译成Shadow Map上每个像素点的“门牌号”。Shadow Map是由光源“拍摄”的深度信息图记录了场景中每个点离光源的远近。MainLightRealtimeShadow等采样函数拿着翻译出来的“门牌号”shadowCoord去Shadow Map这张“地图”上找到对应的深度信息进行比较最终判定当前像素点是否处于阴影中。 实际使用示例一个典型的URP Shader中接收阴影的流程大致如下// 1. 在着色器代码中包含必要的头文件并声明编译宏 #include Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl #pragma multi_compile _ _MAIN_LIGHT_SHADOWS #pragma multi_compile _ _MAIN_LIGHT_SHADOWS_CASCADE // ... 顶点着色器中输出世界坐标 VertexPositionInputs vertexInput GetVertexPositionInputs(IN.positionOS.xyz); OUT.positionWS vertexInput.positionWS; // 2. 在片元着色器中将世界坐标转换为阴影坐标 float4 shadowCoord TransformWorldToShadowCoord(IN.positionWS); // 3. 获取主光源传入阴影坐标得到带有阴影衰减值的光源信息 Light mainLight GetMainLight(shadowCoord); float3 attenuatedLightColor mainLight.color * mainLight.shadowAttenuation;⚠️ 注意事项宏定义_MAIN_LIGHT_SHADOWS和_MAIN_LIGHT_SHADOWS_CASCADE宏是正确启用功能的“开关”确保它们被正确定义非常重要。性能考量在顶点着色器中计算shadowCoord通常更高效只计算一次但在顶点动画较多时为了保证阴影准确可能需要在片元着色器中计算。管线差异该函数主要适用于URPBuilt-in管线通常使用TRANSFER_SHADOW宏而HDRP则使用EvalShadow_WorldToShadow函数。

更多文章