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 来加深理解,尝试在顶点着色器中输出不同空间的坐标作为颜色,观察变换效果。

相关推荐
心前阳光4 小时前
Unity使用Luban之Luban配置
unity
mxwin4 小时前
Unity ShaderLab 完全指南深入了解 Unity 特有的声明式语法,用于定义材质面板、渲染回退、细节层次等核心功能
unity·游戏引擎·材质·shader
qq1315306246 小时前
Unity 渲染优化核心总结(Draw Call / SetPass / Batch 全体系)
unity·游戏引擎·batch
美团骑手阿豪7 小时前
C#语法:HashSet与List对比,适合场景
unity·c#
平行云PVT18 小时前
数字孪生信创云渲染技术解析:从混合信创到全国产化架构
linux·unity·云原生·ue5·图形渲染·webgl·gpu算力
小小数媒成员1 天前
Unity的包含文件
unity·游戏引擎
mxwin1 天前
Unity Shader 实战屏幕颜色抓取实现径向模糊 (URP)
unity·游戏引擎·shader·uv
林枫依依1 天前
Unity2017 项目源码打开即崩溃,无法打开的解决办法
unity
wearegogog1231 天前
ESP32迷你无人机开发代码详解
游戏引擎·无人机·cocos2d