前言
在Godot(以及Unity、Unreal等)引擎中,所有物体的位置、旋转、缩放都是基于坐标空间来定义的。理解坐标空间及其变换规则,是掌握节点树、摄像机跟随、模型变换等操作的数学基础。
1. 坐标空间的组成
要定义一个坐标空间,必须明确两个要素:
原点位置:空间中的参考点 (0,0,0)。
三个坐标轴的方向:在3D空间中,即 X轴、Y轴、Z轴的正方向。
Godot 提示:在Godot中,2D场景使用X(右)和Y(下/上)轴;3D场景使用X(右)、Y(上)、Z(前)轴。每个
Node2D或Node3D节点都定义了自己相对于父节点的局部坐标空间。
2. 坐标空间之间的关系
在Godot的场景树结构中,坐标空间形成层级关系:
世界空间:最顶层的“绝对”空间,是所有坐标的基准(在Godot中对应根视图或
/root)。局部/子空间:大多数坐标空间都是世界空间的“子空间”。一个子空间的原点和轴方向,都是基于它的父空间来定义的。
变换的本质:坐标空间的变换,实际上就是在父空间与子空间之间,对点(位置)或向量进行转换。
Godot 实例:
如果将
CharacterBody3D放在场景中,它的位置是基于世界空间的。如果将一把剑作为角色的子节点,剑的位置是基于角色空间(角色的原点)的。如果角色移动,剑也会相对移动。
3. 坐标空间之间的变换矩阵
为了在数学上实现空间转换,我们使用矩阵。
3.1 问题定义
假设我们有两个空间:
父空间 F
子空间 S(基于F定义)
已知信息(基于父空间F的数据):
Os:子空间S的原点位置。Xs, Ys, Zs:子空间S的三个坐标轴的方向向量。
3.2 两种变换需求
子 → 父:将子空间S下的点
As转换到父空间F中,记为Af。父 → 子:将父空间F下的点
Bf转换到子空间S中,记为Bs。
3.3 核心公式
如果子空间S中的点坐标为 P(a, b, c),那么它在父空间F中的坐标 Pf 可以通过以下方式计算:
父空间坐标 = 子空间原点 + a × 子X轴向量 + b × 子Y轴向量 + c × 子Z轴向量
即:Pf = Os + a·Xs + b·Ys + c·Zs
3.4 变换矩阵
3.4.1 子空间 → 父空间 变换矩阵
记作 M(s→f),它是一个 4×4 的矩阵,结构如下:
解释:
前三列分别是子空间的X、Y、Z轴在父空间中的方向向量。
第四列是子空间的原点在父空间中的位置。
3.4.2 父空间 → 子空间 变换矩阵
记作 M(f→s),它是 M(s→f) 的逆矩阵。
即:M(f→s) = (M(s→f))⁻¹
3.5 关于缩放
如果子空间没有缩放(即轴向量是单位向量),前三列表示纯旋转。
如果子空间有缩放,
Xs, Ys, Zs的长度就不再是1,而是代表了缩放因子。
Godot 实践:
在Godot中,你不需要手动计算这些矩阵。引擎通过Transform3D(3D)或Transform2D(2D)结构体封装了这些数学运算。
获取子节点相对父节点的变换:
child.global_transform与child.transform的关系。使用
to_global()和to_local()方法:例如var world_pos = node.to_global(Vector3(1,0,0))可以直接完成空间转换,底层正是应用了上述矩阵原理。
总结
新人建议:刚开始学习Godot时,不需要深究矩阵内部数值的推导,但一定要理解“世界坐标”与“局部坐标”的概念,以及为什么子物体会跟随父物体移动。当你需要做高级效果(如自定义着色器、骨骼动画或物理计算)时,这些矩阵知识会让你事半功倍。