直接跳到内容

变换与矩阵

3D 变换是计算机图形学的核心数学基础,它通过矩阵运算实现对物体的移动、旋转、缩放等操作。在 Web 3D 开发中,理解变换矩阵的原理和应用对于创建动态、交互式的 3D 场景至关重要。

变换基础

3D 变换是通过数学运算改变物体位置、方向和大小的过程。矩阵作为线性代数的工具,为这些变换提供了统一而高效的表示方法。

特点:

  • 使用 4×4 齐次坐标矩阵表示所有变换
  • 支持变换的组合和逆运算
  • 硬件加速优化,适合实时渲染

示意图 (基本变换类型):

平移:移动位置
   O    →    O
  / \       / \
   |         |

旋转:改变方向
   ↑    →    →
  / \       / \
   |         |

缩放:改变大小
   O    →   BIG O
  / \       /   \
   |         |

齐次坐标

齐次坐标使用四个分量 (x,y,z,w) 表示三维空间中的点,其中 w 分量用于区分点和向量,并支持透视变换。

特点:

  • 点表示为 (x,y,z,1),向量表示为 (x,y,z,0)
  • 统一处理仿射变换和投影变换
  • w 分量支持透视除法

示意图 (齐次坐标转换):

3D 点: (x, y, z) → 齐次坐标: (x, y, z, 1)
3D 向量:(x, y, z) → 齐次坐标: (x, y, z, 0)

透视除法: (x, y, z, w) → (x/w, y/w, z/w)

平移变换

平移变换改变物体的位置,在三维空间中沿 X、Y、Z 轴移动。平移矩阵是一个单位矩阵加上位移分量。

特点:

  • 保持物体形状和方向不变
  • 可逆操作,逆矩阵为反向平移
  • 与其他变换可交换顺序

平移矩阵:

[ 1 0 0 Tx ]
[ 0 1 0 Ty ]
[ 0 0 1 Tz ]
[ 0 0 0 1  ]

示意图 (沿 X 轴平移):

平移前:    平移后:
  Y           Y
  |           |
  |           |
 []         []
  |           |
--+-- X     --+-- X

旋转变换

旋转变换改变物体的方向,围绕特定轴旋转指定角度。每个坐标轴都有对应的旋转矩阵。

特点:

  • 保持物体形状和大小不变
  • 旋转顺序影响最终结果 (不可交换)
  • 使用弧度制表示角度

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 ]

示意图 (绕 Z 轴旋转):

旋转前:    旋转后:
   ↑          ↗
  / \        / \
   |          |

缩放变换

缩放变换改变物体的大小,可以沿各轴均匀或非均匀缩放。缩放矩阵是对角矩阵,对角线元素为缩放因子。

特点:

  • 可以统一缩放或非均匀缩放
  • 缩放因子为负值时产生镜像效果
  • 零缩放因子会使物体坍缩

缩放矩阵:

[ Sx 0  0  0 ]
[ 0  Sy 0  0 ]
[ 0  0  Sz 0 ]
[ 0  0  0  1 ]

示意图 (Y 轴缩放):

原始大小:   Y轴放大:
   O          O
  /|\        /|\
   |          |
   |          |
   |          |
              |

组合变换

多个变换可以通过矩阵乘法组合成单个变换矩阵。变换顺序很重要,因为矩阵乘法不满足交换律。

特点:

  • 从右到左应用变换:M = T × R × S
  • 预计算组合矩阵提高性能
  • 支持复杂的动画和层次变换

变换顺序示意图:

局部坐标 → 缩放 → 旋转 → 平移 → 世界坐标
      S        R       T
      ↓        ↓       ↓
      [局部到世界矩阵] = T × R × S

矩阵乘法示意图:

[T] × [R] × [S] × [顶点] = [变换后的顶点]

注意:从右向左应用
S 先应用,然后是 R,最后是 T

模型矩阵

模型矩阵将物体从局部坐标系变换到世界坐标系,是平移、旋转、缩放变换的组合。

特点:

  • 定义物体在世界空间中的位置和方向
  • 每个物体有自己独立的模型矩阵
  • 支持层次化变换 (父子关系)

示意图 (模型变换流程):

局部坐标系 → 模型矩阵 → 世界坐标系
   O           O
  /|\         /|\
   |           |

          在世界位置

视图矩阵

视图矩阵 (观察矩阵) 将世界坐标系变换到视图坐标系,以相机为参考点。视图矩阵是相机变换的逆矩阵。

特点:

  • 相机位于原点,看向 Z 轴负方向
  • 支持相机移动和旋转
  • 便于后续的投影计算

视图矩阵构造:

[ Rx  Ry  Rz  -dot(R, position) ]
[ Ux  Uy  Uz  -dot(U, position) ]
[ Dx  Dy  Dz  -dot(D, position) ]
[ 0   0   0          1         ]

其中 R, U, D 为相机的右、上、前向量

示意图 (视图变换):

世界坐标系:    视图坐标系:
   Y             Y
   |             |
   |   C         |   Z(观察方向)
   |  /          |  /
   | /           | /
   +--- X        +--- X
相机 C 在世界中   相机在原点

投影矩阵

投影矩阵将视图坐标系变换到裁剪坐标系,主要分为透视投影和正交投影两种类型。

透视投影

透视投影模拟人眼视觉效果,产生近大远小的透视效果。

特点:

  • 创建深度感和真实感
  • 视锥体为平头锥体
  • 适合大多数 3D 应用场景

透视投影矩阵:

[ 2n/(r-l)  0        (r+l)/(r-l)     0    ]
[ 0        2n/(t-b)  (t+b)/(t-b)     0    ]
[ 0         0       -(f+n)/(f-n)  -2fn/(f-n)]
[ 0         0           -1           0    ]

示意图 (透视投影):

   眼睛
   / \
  /   \   视锥体
 /     \
/       \
--------- 近平面
\       /
 \     /   远平面
  \   /
   \ /

正交投影

正交投影保持物体大小不变,无视距离影响,常用于工程绘图和 2.5D 游戏。

特点:

  • 平行投影,无透视变形
  • 视锥体为长方体
  • 保持测量精度

正交投影矩阵:

[ 2/(r-l)  0        0      -(r+l)/(r-l) ]
[ 0       2/(t-b)   0      -(t+b)/(t-b) ]
[ 0        0       -2/(f-n)  -(f+n)/(f-n)]
[ 0        0        0          1        ]

示意图 (正交投影):

视锥体:
+-------+
|       |
|       | → 平行投影
|       |
+-------+

法线变换

变换物体时,法线向量需要特殊处理。法线变换矩阵是模型矩阵的逆转置矩阵,以保持法线与表面的垂直关系。

特点:

  • 保持法线与表面的垂直性
  • 使用模型矩阵的逆转置矩阵
  • 对于只包含旋转的变换,可直接使用模型矩阵

法线变换矩阵:

法线变换矩阵 = transpose(inverse(Model矩阵))

示意图 (法线变换):

变换前:    变换后:
   ↑           ↗
  / \         / \
表面 → 法线   表面 → 法线
   ⊥           ⊥

矩阵栈与层次变换

复杂场景中,物体通常以层次结构组织。矩阵栈管理父子关系的组合变换。

特点:

  • 支持骨骼动画和场景图
  • 通过 push/pop 操作管理变换状态
  • 提高复杂场景的变换效率

示意图 (矩阵栈操作):

push()      | 当前矩阵 |   push()    | 父矩阵 |
当前矩阵 →  |----------| → 应用变换 → |--------|
            |          |             |子矩阵 |
pop() ← ... ←          ← ... ← ... ←

WebGL 中的矩阵实现

在 WebGL 和 Three.js 中,矩阵操作通过 JavaScript 库实现,如 glMatrix 或 Three.js 的 Matrix4 类。

特点:

  • 使用 Float32Array 优化性能
  • 提供矩阵运算的实用函数
  • 与 GPU 着色器紧密集成

示例代码结构:

javascript
// 创建模型矩阵
const modelMatrix = mat4.create();
mat4.translate(modelMatrix, modelMatrix, [x, y, z]);
mat4.rotateY(modelMatrix, modelMatrix, angle);
mat4.scale(modelMatrix, modelMatrix, [sx, sy, sz]);

// 传递给着色器
gl.uniformMatrix4fv(modelMatrixLocation, false, modelMatrix);
变换与矩阵已经加载完毕