2754 words
14 minutes
Unity的旋转、缩放、移动矩阵
2025-06-17
No Tags

在Unity中,移动(平移)、旋转、缩放的矩阵变换是通过4×4的齐次坐标矩阵实现的,这些矩阵共同构成了物体在3D空间中的变换。以下是每个部分的详细解释及其作用:


1. 平移(Translation)矩阵#

作用#

  • 移动物体:将物体在空间中沿X、Y、Z轴方向平移,改变物体的位置。

矩阵结构#

| 1 0 0 tx |
| 0 1 0 ty |
| 0 0 1 tz |
| 0 0 0 1 |
  • 参数tx, ty, tz 是沿X、Y、Z轴的位移量。
  • 位置:平移向量位于矩阵的第四列(前三行最后一列)。

关键点#

  • 仅对点有效:平移仅对具有位置的点(w=1)生效,对方向向量(w=0)无效。
  • 变换顺序:平移通常在旋转和缩放之后应用(如复合变换M = T * R * S)。

2. 旋转(Rotation)矩阵#

作用#

  • 改变物体方向:绕X、Y、Z轴旋转,保持物体形状不变。

矩阵结构#

旋转矩阵是3×3的正交矩阵,位于齐次矩阵的左上角(前3行前3列)。具体形式取决于旋转轴:

绕X轴旋转(θ角)#

| 1 0 0 0 |
| 0 cosθ -sinθ 0 |
| 0 sinθ cosθ 0 |
| 0 0 0 1 |

绕Y轴旋转(θ角)#

| cosθ 0 sinθ 0 |
| 0 1 0 0 |
| -sinθ 0 cosθ 0 |
| 0 0 0 1 |

绕Z轴旋转(θ角)#

| cosθ -sinθ 0 0 |
| sinθ cosθ 0 0 |
| 0 0 1 0 |
| 0 0 0 1 |

关键点#

  • 正交性:旋转矩阵的行/列向量是单位向量且彼此正交(确保不扭曲形状)。
  • 组合旋转:多个旋转可通过矩阵相乘组合(如欧拉角Rx * Ry * Rz)。
  • Unity中的实现:Unity使用四元数(Quaternion)简化旋转操作,但底层仍通过矩阵计算。

3. 缩放(Scaling)矩阵#

作用#

  • 改变物体尺寸:沿X、Y、Z轴缩放,控制物体的大小。

矩阵结构#

| sx 0 0 0 |
| 0 sy 0 0 |
| 0 0 sz 0 |
| 0 0 0 1 |
  • 参数sx, sy, sz 是沿X、Y、Z轴的缩放因子。
  • 位置:缩放因子位于矩阵的主对角线(左上3×3子矩阵的对角线)。

关键点#

  • 均匀/非均匀缩放
    • 均匀缩放sx = sy = sz):保持物体形状比例。
    • 非均匀缩放(如sx ≠ sy):可能导致物体变形(如拉伸)。
  • 对旋转的影响:非均匀缩放会改变旋转轴的方向,需谨慎使用。

4. 齐次坐标(Homogeneous Coordinates)#

作用#

  • 统一表示变换:通过添加w分量,将平移、旋转、缩放统一为矩阵乘法。

结构#

齐次坐标将3D点(x, y, z)扩展为(x, y, z, 1),向量扩展为(x, y, z, 0)

  • 点(w=1:参与平移和线性变换。
  • 向量(w=0:仅参与旋转和缩放(无平移)。

关键点#

  • 矩阵乘法兼容性:齐次坐标允许将平移、旋转、缩放组合成单个4×4矩阵。
  • Unity中的应用:所有变换矩阵(如ModelViewProjection)均基于齐次坐标。

5. 复合变换(Combined Transform)#

在Unity中,物体的变换通常通过缩放→旋转→平移的顺序组合:

M_{\text{复合}} = T \times R \times S

矩阵结构#

| Rx*x Ry*x Rz*x tx |
| Rx*y Ry*y Rz*y ty |
| Rx*z Ry*z Rz*z tz |
| 0 0 0 1 |
  • 左上3×3:旋转后的缩放矩阵(R × S)。
  • 第四列:平移向量T
  • 最后一行:始终为(0, 0, 0, 1)

Unity中的实现#

  • Transform组件:封装了位置(Position)、旋转(Rotation)、缩放(Scale),底层通过矩阵运算实现。
  • Matrix4x4类:直接操作矩阵(如Matrix4x4.TRS生成复合矩阵)。

6. 典型应用示例#

(1) 移动物体#

// 生成平移矩阵
Matrix4x4 translation = Matrix4x4.Translate(new Vector3(5, 0, 0));
Vector3 point = new Vector3(1, 2, 3);
Vector3 translatedPoint = translation.MultiplyPoint(point); // 结果(6,2,3)

(2) 旋转物体#

// 绕Y轴旋转90度
Matrix4x4 rotation = Matrix4x4.Rotate(Quaternion.Euler(0, 90, 0));
Vector3 rotatedPoint = rotation.MultiplyPoint(new Vector3(1, 0, 0)); // 结果(0,0,-1)

(3) 缩放物体#

// X轴缩放2倍
Matrix4x4 scale = Matrix4x4.Scale(new Vector3(2, 1, 1));
Vector3 scaledPoint = scale.MultiplyPoint(new Vector3(1, 2, 3)); // 结果(2,2,3)

(4) 复合变换#

// 缩放→旋转→平移
Matrix4x4 transformMatrix = Matrix4x4.TRS(
position: new Vector3(5, 0, 0), // 平移
rotation: Quaternion.Euler(0, 90, 0), // 旋转
scale: new Vector3(2, 1, 1) // 缩放
);

7. 注意事项#

  1. 矩阵相乘顺序
    • 右乘优先M = T × R × S 表示先缩放,再旋转,最后平移(矩阵相乘顺序与操作顺序相反)。
  2. 非均匀缩放的风险
    • 非均匀缩放会破坏旋转矩阵的正交性,可能导致法线方向错误(需重新计算法线)。
  3. Unity的优化
    • Unity通过四元数(Quaternion)和欧拉角(EulerAngles)封装旋转,避免直接操作旋转矩阵的复杂性。

总结#

  • 平移矩阵:控制物体位置(第四列)。
  • 旋转矩阵:控制物体方向(左上3×3的正交子矩阵)。
  • 缩放矩阵:控制物体尺寸(左上3×3的对角线)。
  • 齐次坐标:统一平移、旋转、缩放的计算。

通过这些矩阵的组合,Unity实现了物体在3D空间中的灵活变换,开发者可通过Transform组件或直接操作矩阵实现复杂效果。

为什么是这个顺序?#

在3D图形学和Unity引擎中,变换操作的顺序必须遵循“先缩放(Scale)→再旋转(Rotation)→最后平移(Translation)”,这是因为矩阵乘法的非交换性和变换的几何意义所决定的。以下是详细解释:


1. 变换顺序的核心原因:矩阵乘法的非交换性#

矩阵乘法不满足交换律(即 (image)),因此变换的顺序直接影响最终结果。复合变换的矩阵乘法顺序需要从右到左依次应用,即:

image

但实际操作顺序是先缩放、再旋转、最后平移(即从右到左读取矩阵相乘的顺序)。


2. 顺序分解:缩放 → 旋转 → 平移#

(1) 先缩放(Scale)#

  • 作用:改变物体的尺寸(沿坐标轴方向放大或缩小)。
  • 关键点
    • 缩放操作不改变坐标轴的方向和原点,因此后续的旋转和平移不会受到缩放的影响。
    • 如果先缩放,后续的旋转将以缩放后的坐标轴为基准(例如,缩放后旋转会以缩放后的轴方向进行旋转)。

(2) 再旋转(Rotation)#

  • 作用:改变物体的方向(绕坐标轴旋转)。
  • 关键点
    • 旋转会改变坐标轴的方向,但不改变原点
    • 如果旋转在缩放之后,旋转后的坐标轴方向是基于缩放后的物体尺寸(例如,旋转后的轴方向不会因后续的平移而改变)。
    • 如果旋转在平移之前,旋转是围绕原点进行的,而平移后的物体位置不会被旋转影响。

(3) 最后平移(Translation)#

  • 作用:移动物体到目标位置。
  • 关键点
    • 平移会改变物体的原点位置,但不会改变坐标轴的方向或缩放后的尺寸。
    • 如果平移在最后,它将物体从原点移动到目标位置,而缩放和旋转已经确定了物体的尺寸和方向。

3. 顺序错误的后果#

(1) 先平移再缩放#

  • 问题:平移后的物体距离原点更远,缩放会放大或缩小平移的距离。
    • 例如:先平移 (2, 0, 0),再缩放 2,最终位置会是 (4, 0, 0)(缩放影响了平移的距离)。
    • 预期:可能希望缩放仅改变尺寸,但平移后的缩放会扭曲位置。

(2) 先旋转再缩放#

  • 问题:旋转后的坐标轴方向可能与缩放方向不一致,导致物体沿旋转后的轴方向缩放,产生意外变形。
    • 例如:先绕Y轴旋转90°,再沿X轴缩放2倍,实际会沿旋转后的X轴(原Z轴方向)缩放,导致方向错误。

(3) 先平移再旋转#

  • 问题:旋转会围绕原点进行,而平移后的物体远离原点,导致旋转中心不正确。
    • 例如:先平移 (5, 0, 0),再绕原点旋转90°,物体将绕原点旋转,而非自身的中心。

4. 为什么Unity和其他引擎遵循此顺序?#

(1) 符合数学定义#

  • 复合变换矩阵
    Unity的Transform组件默认的变换顺序是缩放→旋转→平移,其矩阵表达式为:
    image
    • 其中,(S)是缩放矩阵,(R)是旋转矩阵,(T)是平移矩阵。
    • 这样,物体的变换过程是:先缩放自身,再旋转自身方向,最后平移到目标位置。

(2) 父子对象的层级关系#

  • 本地坐标系的继承
    子对象的变换是基于父对象的变换后的坐标系。例如:
    • 如果父对象先缩放,子对象的旋转和后续平移会基于父对象缩放后的坐标轴。
    • 如果父对象先平移,子对象的缩放和旋转会基于父对象的位置,可能导致位置偏移。

(3) 避免几何错误#

  • 保持旋转中心
    默认顺序确保旋转和缩放均以物体的本地原点(通常是几何中心)为基准,避免因平移导致旋转中心偏移。

5. 实际应用中的验证#

(1) 场景中的立方体#

  • 正确顺序(缩放→旋转→平移)
    一个立方体先缩放为 2x2x2,绕Y轴旋转90°,最后平移到 (5, 0, 0),结果符合预期。
  • 错误顺序(平移→旋转→缩放)
    先平移到 (5, 0, 0),再旋转会导致物体绕原点旋转(远离中心),缩放会改变平移后的距离,导致位置混乱。

(2) Unity代码示例#

// 正确顺序:缩放→旋转→平移
transform.localScale = new Vector3(2, 2, 2); // 缩放
transform.Rotate(0, 90, 0); // 旋转(绕Y轴)
transform.position = new Vector3(5, 0, 0); // 平移
// 错误顺序:平移→旋转→缩放
transform.position = new Vector3(5, 0, 0); // 平移
transform.Rotate(0, 90, 0); // 旋转(绕原点,导致位置偏移)
transform.localScale = new Vector3(2, 2, 2); // 缩放会放大平移后的距离

6. 总结#

操作顺序数学意义几何意义
缩放(S)改变坐标轴的长度(保持原点和方向)改变物体尺寸,但不移动或旋转
旋转(R)改变坐标轴的方向(保持原点和缩放后的长度)改变物体方向,但不改变尺寸或位置
平移(T)改变原点位置(保持坐标轴的方向和缩放)移动物体到目标位置,但不改变尺寸或方向

遵循此顺序的原因

  • 缩放确保后续旋转和移动的基准是物体的原始尺寸。
  • 旋转基于缩放后的坐标轴方向,避免方向错误。
  • 平移最后执行,确保物体移动到正确的位置,不受缩放或旋转的影响。

通过这种方式,可以精确控制物体的变换,避免因顺序错误导致的逻辑或视觉错误。

Unity的旋转、缩放、移动矩阵
https://fuwari.vercel.app/posts/unity的旋转缩放移动矩阵/
Author
Axon
Published at
2025-06-17
License
CC BY-NC-SA 4.0