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 函数。

相关推荐
mxwin8 小时前
unity shader中 ddx ddy是什么
unity·游戏引擎·shader
郝学胜-神的一滴11 小时前
[简化版 GAMES 101] 计算机图形学 08:三角形光栅化上
c++·unity·游戏引擎·godot·图形渲染·opengl·unreal
nnsix11 小时前
Unity ILRuntime 笔记
unity·游戏引擎
nnsix13 小时前
Unity API 兼容的 .NET Standard 2.1 和 .NET Framework 区别
unity·游戏引擎·.net
mxwin13 小时前
Unity Shader 制作半透明物体 使用多Pass提前写入深度的方式 避免穿模
unity·游戏引擎
nnsix15 小时前
Unity HybridCLR 笔记
笔记·unity·游戏引擎
nnsix16 小时前
Unity Addressables 笔记
unity·游戏引擎
RReality16 小时前
【Unity Shader URP】视差贴图 实战教程
ui·平面·unity·游戏引擎·图形渲染·贴图
小清兔1 天前
Addressable的设置打包流程
笔记·游戏·unity·c#
3D霸霸1 天前
Sourcetree 拉取新工程
数据仓库·unity