Unity Shader 数学与几何变换 深入理解渲染管线中的坐标系转换:从模型空间到屏幕空间的完整变换链

变换链概览

理解渲染管线中顶点数据的完整变换过程

在 Unity Shader 中,顶点从模型数据到最终显示在屏幕上,需要经过一系列坐标系转换。这个过程被称为顶点变换管线,是理解 3D 渲染的核心基础。

💡

为什么需要这么多坐标系?

每个坐标系都有其特定的用途:模型空间方便建模,世界空间用于场景管理,观察空间简化投影计算,裁剪空间用于视锥体裁剪,屏幕空间对应最终像素位置。

模型空间 (Model Space)

顶点数据的原始坐标系,以模型自身为参考

📐定义与特性

  • 局部坐标系

    每个模型都有自己的坐标系原点,通常位于模型的几何中心或底部中心。

  • 建模坐标系

    3D 建模软件(如 Blender、Maya)中创建模型时使用的坐标系。

  • 顶点属性

    顶点位置、法线、切线等数据在模型空间中定义,存储在 Mesh 中。

🎯实际应用

在 Unity Shader 中,模型空间顶点数据通过顶点着色器输入获取:

cs 复制代码
struct appdata {
    float4 vertex : POSITION;    // 模型空间顶点位置
    float3 normal : NORMAL;    // 模型空间法线
    float2 uv : TEXCOORD0;     // 纹理坐标
};

03

世界空间 (World Space)

场景的统一坐标系,所有模型的公共参考系

🌍模型到世界的变换

其中 Mmodel 是模型变换矩阵,由平移、旋转、缩放组合而成:

cs 复制代码
// Unity 内置矩阵:unity_ObjectToWorld
float4 worldPos = mul(unity_ObjectToWorld, vertex);

// 或者使用 TransformObjectToWorld 函数
float3 worldPos = TransformObjectToWorld(vertex.xyz);

⚠️

注意法线变换

法线需要使用逆转置矩阵进行变换,以保证在非标量缩放时保持正确:worldNormal = normalize(mul((float3x3)unity_WorldToObject, normal))

观察空间 (View Space)

以摄像机为原点的坐标系,简化投影计算

📷观察空间特性

  • 摄像机坐标系

    原点位于摄像机位置,Z轴指向摄像机朝向的反方向(观察方向)。

  • 右手坐标系

    Unity 使用右手坐标系:X 向右,Y 向上,Z 向后(远离摄像机)。

  • 视图变换

    将世界空间转换为以摄像机为中心的局部空间。

🔢观察矩阵推导

观察矩阵是摄像机变换矩阵的逆矩阵:

包含两个步骤:

  1. 平移:将世界原点移动到摄像机位置
  2. 旋转:对齐坐标轴到摄像机朝向

💻Shader 实现

cs 复制代码
// 方法1:使用内置矩阵 unity_MatrixV
float4 viewPos = mul(unity_MatrixV, worldPos);

// 方法2:使用 UNITY_MATRIX_V 宏
float4 viewPos = mul(UNITY_MATRIX_V, worldPos);

// 方法3:URP/HDRP 中的变换函数
float3 viewPos = TransformWorldToView(worldPos.xyz);

裁剪空间 (Clip Space)

投影变换后的齐次裁剪坐标系

🔺投影变换

裁剪空间是顶点着色器的输出空间,通过投影矩阵将观察空间转换为裁剪空间。这个变换同时处理透视除法前的齐次坐标。

投影类型 特点 应用场景
透视投影 近大远小,符合人眼视觉 3D 游戏、真实感渲染
正交投影 平行线保持平行,无透视变形 2D 游戏、UI、工程制图
cs 复制代码
// 顶点着色器输出裁剪空间位置
float4 vert (appdata v) : SV_POSITION {
    float4 worldPos = mul(unity_ObjectToWorld, v.vertex);
    float4 viewPos = mul(UNITY_MATRIX_V, worldPos);
    float4 clipPos = mul(UNITY_MATRIX_P, viewPos);
    return clipPos;
}

// 或者使用 MVP 矩阵一次性变换
return mul(UNITY_MATRIX_MVP, v.vertex);

屏幕空间 (Screen Space)

最终的像素坐标系,对应显示器上的实际位置

📝屏幕空间坐标获取

cs 复制代码
// 片段着色器中获取屏幕坐标
float4 frag (float4 pos : SV_POSITION) : SV_Target {
    // pos.xy 已经是屏幕空间坐标 (像素位置)
    float2 screenUV = pos.xy / _ScreenParams.xy;
    
    // 或者使用内置宏
    float2 screenUV = ComputeScreenPos(pos).xy;
    
    return float4(screenUV, 0, 1);
}

总结与速查表

坐标系转换的核心要点回顾

坐标系 范围 变换矩阵/函数 用途
模型空间 模型局部 顶点输入数据 存储顶点原始位置
世界空间 场景全局 unity_ObjectToWorld 光照计算、物理模拟
观察空间 摄像机局部 UNITY_MATRIX_V 视锥体剔除、投影准备
裁剪空间 齐次坐标 UNITY_MATRIX_P 顶点着色器输出
NDC -1, 1³ 透视除法 (w 除法) 硬件裁剪
屏幕空间 0, W×0, H 视口变换 像素位置、后处理

🎓

学习建议

理解这些坐标系转换是掌握 Shader 编程的基础。建议通过实际编写 Shader 来加深理解,尝试在顶点着色器中输出不同空间的坐标作为颜色,观察变换效果。

相关推荐
叶帆2 天前
【YFIOs】用C#开发硬件之设备上云
开发语言·unity·c#
久数君2 天前
AI三维建模工具“造形家”:地理场景三维化的高效解决方案
unity·glb·ai算法·ai三维建模工具·地图框选·造形家·城市建筑模型
会思考的猴子3 天前
Unity VFX 属性 Postion 和 TargetPostion
unity
hai3152475433 天前
九章编程法 · 猜数字游戏 (GW-BASIC 重构版) *
人工智能·microsoft·游戏引擎·游戏程序
心前阳光3 天前
Unity资源导入之自动化资源导入
unity·自动化·游戏引擎
心前阳光3 天前
Unity之2021.3.45f2c1发布安卓程序遇到的问题
android·unity·游戏引擎
纪纯3 天前
PicoVR Unity Integration SDK 3.4 常用交互API
unity·游戏引擎·vr·pico
龙智DevSecOps解决方案3 天前
3A 游戏优化技术栈:如何打通引擎级分析工具与 DevOps 持续集成管线?
unity·性能优化·游戏开发·技术美术·perforce·unrealengine
葛兰岱尔3 天前
从 SolidWorks 到 Three.js,从 Inventor 到 Unity——制造业CAD模型“几何-语义一体化“转换,不再是天方夜谭!
开发语言·javascript·unity
鼎艺创新科技3 天前
三维电子沙盘中OSGB倾斜摄影数据的加载与渲染
游戏引擎·cocos2d