跳过正文

Unity的旋转、缩放、移动矩阵

·3613 字·8 分钟
杂谈 Unity 算法
AxonSin
作者
AxonSin
梦想是复活在赛博世界,成为一名赛博垃圾人。
目录

在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) 改变原点位置(保持坐标轴的方向和缩放) 移动物体到目标位置,但不改变尺寸或方向

遵循此顺序的原因

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

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

Reply by Email

相关文章

常见的引擎物理算法
·3458 字·7 分钟
杂谈 Unity Blender Animation Houdini Git 渲染 算法 物理 色彩 MMD
Blender导入Unity指南
Unity实现体积光(GodRay)的三种方案
·2317 字·5 分钟
杂谈 Unity Shader 渲染 光照 算法
体积光实现方案
反射算法
·46 字·1 分钟
杂谈 Unity Blender Shader 渲染 算法
Blender导入Unity指南