Unity shader中TransformWorldToShadowCoord原理解析

TransformWorldToShadowCoord 的核心作用很简单:将你提供的世界坐标,转换到一个可以用于采样 Shadow Map 的坐标空间。它本质上是为你省去了手动编写矩阵乘法的繁琐步骤。

🔍 核心原理:一个"三步走"的幕后过程

函数内部主要执行了以下三个步骤:

  1. 获取矩阵 :获取从"世界空间"转换到"阴影空间"的核心矩阵 unity_WorldToShadow。

    • 方向光 :需处理阴影级联(Shadow Cascades),因此是一个包含最多4个矩阵的数组 unity_WorldToShadow[4]。

    • 聚光灯/点光源 :通常只用一个矩阵 unity_WorldToLight。

  2. 执行变换 :执行矩阵乘法 mul(unity_WorldToShadow[selectedIndex], float4(worldPos, 1.0)),将世界坐标转换到阴影空间的齐次坐标。

  3. 处理齐次坐标 :对于聚光灯 或点光源 这类透视投影,需要执行透视除法(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中接收阴影的流程大致如下:

cs 复制代码
// 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 通常更高效(只计算一次),但在顶点动画较多时,为了保证阴影准确,可能需要在片元着色器中计算。

  • 管线差异 :该函数主要适用于URP,Built-in管线通常使用TRANSFER_SHADOW宏,而HDRP则使用 EvalShadow_WorldToShadow 函数。

相关推荐
WarPigs4 小时前
Unity对象不应该使用null传播的问题
unity
每日出拳老爷子1 天前
【VR】【Unity】抓走转放系列21|一天搭完门和抽屉工具槽:小场景按这个次序拼装
unity·vr·驱动·排错·snap zone
淡海水2 天前
02-02-原理篇-分代GC
算法·unity·c#·游戏引擎·.net·gc
小贺儿开发2 天前
Unity 文物新生 会讲故事的文物展墙
人工智能·科技·unity·ai·视频·互动·演示
淡海水2 天前
02-03-原理篇-大对象堆
unity·c#·游戏引擎·.net·gc
WarPigs3 天前
Unity在Create菜单添加创建自定义脚本模板选项
unity
郝学胜-神的一滴3 天前
C++ Templates 01:拨开迷雾,读懂C++模板经典著作
开发语言·c++·程序人生·游戏·游戏引擎·软件构建
淡海水3 天前
02-01-原理篇-Mark-Sweep与变种算法
算法·unity·c#·游戏引擎·.net·gc
babywang03 天前
Unity笔记--塔防游戏中的ECS架构:从原理到实战的全面解析
unity·ecs架构
babywang04 天前
Unity笔记--AssetBundle详解
unity·游戏引擎