跳到主要内容

Unity Shader 的坐标空间转换(图解)

这篇小笔记主要是把 Unity Shader 里的坐标空间关系 用一张图梳理出来, 方便记忆模型空间、世界空间、观察空间、裁剪空间之间的转换, 以及对应的 Unity 内置矩阵与宏。


坐标空间关系概览

从模型导入到最终显示在屏幕上,顶点通常会经历以下几个空间:

  • 模型空间(Model / Object / Local Space):模型自带的局部坐标系。
  • 世界空间(World Space):把所有物体放到同一世界坐标系后的位置。
  • 观察空间(View / Camera Space):以相机为原点、相机方向为轴的坐标系。
  • 裁剪空间(Clip Space):应用投影矩阵后的空间,用于裁剪视锥体外的内容。

示意图大致如下:

模型空间 → 世界空间 → 观察空间 → 裁剪空间

最下方可以理解为「从模型空间一步步乘上 M、V、P 矩阵, 最后得到可以送去做裁剪和投影的裁剪空间坐标」。


常用矩阵与 Unity 内置宏

在 Unity 中,常用的几个矩阵含义可以简要整理如下:

  • 模型到世界(M)unity_ObjectToWorld / UNITY_MATRIX_M
  • 世界到观察(V)unity_MatrixV / UNITY_MATRIX_V
  • 观察到裁剪(P)glstate_matrix_projection / UNITY_MATRIX_P

组合之后就有:

  • 模型到观察(M × V)UNITY_MATRIX_MVmul(unity_MatrixV, unity_ObjectToWorld)
  • 世界到裁剪(V × P)UNITY_MATRIX_VP / unity_MatrixVP
  • 模型到裁剪(M × V × P,通常叫 MVP)UNITY_MATRIX_MVP

下面按转换路径再拆一遍。

模型空间 → 世界空间(Model → World)

模型空间下的顶点位置 v.vertex,乘以模型变换矩阵即可得到世界空间坐标:

float4 worldPos = mul(unity_ObjectToWorld, v.vertex);

世界空间 → 观察空间(World → View)

把世界空间坐标乘以视图矩阵:

float4 viewPos = mul(unity_MatrixV, worldPos);

观察空间 → 裁剪空间(View → Clip)

再乘投影矩阵:

float4 clipPos = mul(UNITY_MATRIX_P, viewPos);

这一步会把视锥体变换到一个规则的立方体内,方便后续裁剪和归一化。

世界空间 → 裁剪空间(World → Clip)

如果你已经有世界空间坐标,也可以直接用 VP 矩阵:

float4 clipPos = mul(UNITY_MATRIX_VP, worldPos);

模型空间 → 观察空间(Model → View)

有时只需要到观察空间,而不是直接裁剪空间,可以使用 MV 矩阵:

float4 viewPos = mul(UNITY_MATRIX_MV, v.vertex);

// 或明确写出:V * M
float4 viewPos2 = mul(unity_MatrixV, mul(unity_ObjectToWorld, v.vertex));

模型空间 → 裁剪空间(Model → Clip / MVP)

最常见的完整路径就是「MVP 变换」:

float4 clipPos = mul(UNITY_MATRIX_MVP, v.vertex);

在 Unity 提供的辅助函数中,等价写法是:

o.pos = UnityObjectToClipPos(v.vertex);

这里 UnityObjectToClipPos 就是帮你把「对象空间顶点」 依次乘上 M、V、P 三个矩阵,得到可以直接用来输出到 SV_POSITION 的裁剪空间坐标。


顶点着色器中的典型用法

一个最基础的顶点着色器,一般至少会把输入的对象空间顶点转换到裁剪空间:

struct appdata
{
    float4 vertex : POSITION;
    // 其他属性:法线、UV 等
};

struct v2f
{
    float4 pos : SV_POSITION;
    // 其他插值数据
};

v2f vert (appdata v)
{
    v2f o;
    // 对象空间 → 裁剪空间
    o.pos = UnityObjectToClipPos(v.vertex);
    return o;
}

当你需要在世界空间做额外运算(比如基于世界坐标的光照、投影等), 就再额外计算一份 worldPos 并通过 v2f 传给片元着色器即可。


小结

  • 记住四个主要空间:模型 → 世界 → 观察 → 裁剪
  • 熟悉 Unity 内置矩阵:UNITY_MATRIX_MUNITY_MATRIX_VUNITY_MATRIX_P 和组合形式 MVVPMVP
  • 在 Shader 里最常见的就是直接调用 UnityObjectToClipPos, 但理解背后做了什么,有助于你在需要世界空间或观察空间时写出更灵活的效果。

版权声明:本文最初发布于 CSDN「uniGame」,遵循 CC 4.0 BY-SA 协议,转载请附上原文链接及本声明。
原文链接:https://blog.csdn.net/alla_Candy/article/details/121176275