Unity3d 坐标变换

本文记录一些Unity中可能用到的坐标变换的方法,包括在C#脚本中及在ShaderLab中:

CS脚本中

在C#脚本中会用到的坐标转换:

local(parent) -> world

本地坐标和世界坐标的转化,local实际上就是此对象的父节点空间,以下三行代码都会输出该GameObject的世界坐标(有父节点的情况下):

1
2
3
Debug.Log(transform.position);
Debug.Log(transform.parent.TransformPoint(transform.localPosition));
Debug.Log(transform.parent.localToWorldMatrix.MultiplyPoint(transform.localPosition));

world -> local(parent)

将世界坐标转换为本地坐标,以下三行代码都会输出该GameObject的本地坐标(有父节点的情况下):

1
2
3
Debug.Log(transform.localPosition);
Debug.Log(transform.parent.InverseTransformPoint(transform.position));
Debug.Log(transform.parent.worldToLocalMatrix.MultiplyPoint(transform.position));

如果需要计算某对象在另一个空间中的坐标,可通过local->world->someparent转换,也可以得出相对于父节点的变换矩阵,逐级变换:

逐级变换

假设现在有四个GameObject对象,它们的分别被引用为t1t2t3t4

1
2
3
4
public Transform t1;
public Transform t2;
public Transform t3;
public Transform t4;

设置它们的父子关系如下:

1
2
3
t4.SetParent(t3, false);
t3.SetParent(t2, false);
t2.SetParent(t1, false);

使用m1m2m3来保存t1t2t3 的变换矩阵(TRS),则可以看到下边的三个Debug.Log都会输出t4的世界坐标(t1有父节点):

1
2
3
4
5
6
Debug.Log(t4.position);
Matrix4x4 m1 = Matrix4x4.TRS(t1.localPosition, t1.localRotation, t1.localScale);
Matrix4x4 m2 = Matrix4x4.TRS(t2.localPosition, t2.localRotation, t2.localScale);
Matrix4x4 m3 = Matrix4x4.TRS(t3.localPosition, t3.localRotation, t3.localScale);
Debug.Log(t1.parent.localToWorldMatrix.MultiplyPoint(m1.MultiplyPoint(m2.MultiplyPoint(m3.MultiplyPoint(t4.localPosition)))));
Debug.Log((t1.parent.localToWorldMatrix * m1 * m2 * m3).MultiplyPoint(t4.localPosition));

t4连续的施以m3m2m1,即可得到t4t1.parent之下的局部坐标。

shader中

在顶点着色器中常常会使用一些变换,如下:

local -> world

本地坐标到世界坐标的转换,借助于内置变量unity_ObjectToWorld,旧版本中叫做_Object2World,将本地坐标pos转换到为世界坐标的方法如下:

1
mul(unity_ObjectToWorld, float4(pos, 1.0));

world -> local

世界坐标到本地坐标的转换,借助于内置变量unity_WorldToObject,旧版本中叫做_World2Object,将世界坐标pos转换到为本地坐标的方法如下:

1
mul(unity_WorldToObject, float4(pos, 1.0));

obj -> clip

最常用到的还是本地坐标到裁剪空间的坐标转换,如将本地坐标pos转化为裁剪屏幕的坐标,可以调用第一行的函数,也可以使用第二行的矩阵乘法,Unity似乎会自动把mul(UNITY_MATRIX_MVP, *)转化成前者:

1
2
float4 UnityObjectToClipPos(float3 pos);
mul(UNITY_MATRIX_MVP, float4(pos, 1.0));

REFERENCE

https://docs.unity3d.com/Manual/class-Transform.html

https://docs.unity3d.com/Manual/SL-UnityShaderVariables.html