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

相关推荐
魔士于安34 分钟前
Unity 简单水面效果URP
游戏·unity·游戏引擎·贴图·模型
mxwin39 分钟前
Unity Shader 毛发 & 草海渲染Alpha‑to‑Coverage 抗锯齿技术详解
unity·游戏引擎·shader
张老师带你学11 小时前
unity TerrainSampleAssets
科技·游戏·unity·游戏引擎·模型
亿元程序员11 小时前
亿元Cocos小游戏实战合集2.0
游戏·游戏引擎
RReality14 小时前
【Unity Shader URP】色带渐变着色(Ramp Shading)实战教程
ui·unity·游戏引擎·图形渲染
mxwin1 天前
Unity URP 体积光与雾效 基于深度重建世界空间位置,实现体积雾与体积光
unity·游戏引擎
张老师带你学1 天前
unity 树资源 有樱花树 buildin
科技·游戏·unity·游戏引擎·模型
魔士于安1 天前
unity 植物 不常见 花 触手植物
游戏·unity·游戏引擎·贴图·模型
魔士于安1 天前
unity=>传送门特效 带自由视角旋转放大 鼠标操作
前端·游戏·unity·游戏引擎·贴图·模型
南無忘码至尊1 天前
Unity学习90天 - 第4天 - 认识物理系统基础并实现物体碰撞反弹
学习·unity·游戏引擎