2025-11-30 · game_math
【游戏中的数学】游戏中的数学 (4) - 矩阵与变换
深入理解游戏开发中的矩阵:TRS 变换与代码实践、矩阵乘法与组合变换、MVP 管线详解、逆矩阵、法线变换,以及旋转表示方式对比。
引擎语境:本文主要以 Unity / C# 视角讲解,概念同样适用于 Unreal / Godot / 自研引擎。
在游戏开发中,向量 (Vector) 是最基础也是最重要的数学工具之一。无论是角色的位置、速度,还是光照的方向、摄像机的朝向,几乎所有的空间概念都离不开向量。 可以把向量想成“有长度的箭头”:长度表示“有多大”,方向表示“往哪边”。
在几何意义上,向量是一个既有大小 (Magnitude/Length) 又有方向 (Direction) 的量。 在编程中,我们通常用一个包含 \(x, y\) (2D) 或 \(x, y, z\) (3D) 分量的结构体或类来表示。
struct Vector3 {
float x, y, z;
};向量的加法符合三角形法则。 - 加法:\(A + B\) 表示从 \(A\) 的起点出发,经过 \(A\) 到达 \(A\) 的终点,再以 \(A\) 的终点为起点,经过 \(B\) 到达 \(B\) 的终点。结果向量是从 \(A\) 的起点指向 \(B\) 的终点。 - 应用:位置更新 (新位置 = 旧位置 + 位移)。 - 减法:\(B - A\) 表示从 \(A\) 的终点指向 \(B\) 的终点的向量。 - 应用:计算从一个物体指向另一个物体的向量 (目标位置 - 玩家位置)。
将向量的每个分量乘以一个标量 \(k\)。 - 应用:缩放物体,或者根据时间步长缩放速度向量 (\(Position += Velocity * \Delta t\))。
点积是两个向量之间的一种运算,结果是一个标量。 公式:\(A \cdot B = |A| |B| \cos \theta\) 或者代数形式:\(A \cdot B = A_x B_x + A_y B_y + A_z B_z\)
点积描述了两个向量方向的相似程度。 - 如果 \(A \cdot B > 0\),夹角小于 90度 (方向大致相同)。 - 如果 \(A \cdot B = 0\),夹角等于 90度 (垂直)。 - 如果 \(A \cdot B < 0\),夹角大于 90度 (方向大致相反)。
叉积仅在 3D 空间中有定义,结果是一个新的向量,该向量垂直于参与运算的两个向量构成的平面。 公式:\(A \times B = (A_y B_z - A_z B_y, A_z B_x - A_x B_z, A_x B_y - A_y B_x)\)
结果向量的方向遵循右手定则。大小等于以 \(A\) and \(B\) 为边的平行四边形的面积。
归一化是将一个向量的长度变为 1,但保持方向不变的过程。结果向量称为单位向量 (Unit Vector)。
\[ \hat{v} = \frac{v}{|v|} \] 即:将向量的每个分量除以它的长度。
Vector3 direction = (targetPos - currentPos).normalized;
// 现在 direction 的长度是 1,我们可以乘以速度
velocity = direction * speed;计算向量长度需要开平方根(sqrt),这是一个相对昂贵的操作。如果只是比较两个距离的大小,可以直接比较平方长度:
// 慢:计算两次 sqrt
if ((a - b).magnitude < (a - c).magnitude) { ... }
// 快:省掉 sqrt
if ((a - b).sqrMagnitude < (a - c).sqrMagnitude) { ... }在每帧需要对成百上千个物体做范围检测时,这个优化非常显著。
严格来说叉积只定义在 3D 空间,但在 2D 游戏中,我们经常用一个”伪叉积”来判断方向:
\[cross_{2D}(A, B) = A_x B_y - A_y B_x\]
float Cross2D(Vector2 a, Vector2 b) {
return a.x * b.y - a.y * b.x;
}
// 判断转弯方向(AI 寻路、赛车游戏)
float turn = Cross2D(forward, toTarget);
if (turn > 0) TurnLeft();
else TurnRight();将向量 \(A\) 投影到方向 \(B\) 上:
\[proj_B A = rac{A \cdot B}{B \cdot B} B\]
如果 \(B\) 是单位向量,则简化为 \((A \cdot B) B\)。
投影在游戏中非常常用: - 斜坡移动:将移动向量投影到斜面上 - 阴影计算:将光线投影到平面上 - 速度分解:将速度分解为沿墙面和垂直墙面的两个分量
角色在斜坡上移动时,我们不希望移动方向”钻入”地面。解决方法是将移动向量投影到斜坡平面上:
// slopeNormal: 斜坡法线(单位向量)
// moveDir: 玩家输入的移动方向
Vector3 projectedMove = moveDir - Vector3.Dot(moveDir, slopeNormal) * slopeNormal;
// projectedMove 现在平行于斜面,长度略小于原 moveDir角色撞墙后不应该完全停下,而应该沿着墙面滑动:
// wallNormal: 墙面法线
// velocity: 碰撞前的速度
Vector3 slideVelocity = velocity - Vector3.Dot(velocity, wallNormal) * wallNormal;这两个场景的数学本质完全一样:从向量中减去法线方向的分量。
掌握向量运算是进行 3D 编程和物理模拟的第一步。下一章我们将讨论矩阵与坐标变换。
< 上一篇: 三角函数入门 | 回到目录 | 下一篇: 矩阵与变换 >
把当前热点继续串成多页阅读,而不是停在单篇消费。
2025-11-30 · game_math
深入理解游戏开发中的矩阵:TRS 变换与代码实践、矩阵乘法与组合变换、MVP 管线详解、逆矩阵、法线变换,以及旋转表示方式对比。
2025-11-30 · game_math
为什么游戏引擎都用四元数来表示旋转?详解欧拉角的万向节死锁问题,以及四元数的定义、运算和 Slerp 插值。
2025-11-30 · game_math
游戏开发数学专题索引。从标量函数到四元数,从碰撞检测到骨骼动画——一条完整的游戏数学学习路径。
2025-11-30 · game_math
详解游戏引擎中常用的标量数学函数:Lerp, InverseLerp, Remap, Clamp, SmoothStep 等。不仅有公式,更有实际应用场景。
引擎语境:本文主要以 Unity / C# 视角讲解,概念同样适用于 Unreal / Godot / 自研引擎。
在游戏开发中,向量 (Vector) 是最基础也是最重要的数学工具之一。无论是角色的位置、速度,还是光照的方向、摄像机的朝向,几乎所有的空间概念都离不开向量。 可以把向量想成“有长度的箭头”:长度表示“有多大”,方向表示“往哪边”。
在几何意义上,向量是一个既有大小 (Magnitude/Length) 又有方向 (Direction) 的量。 在编程中,我们通常用一个包含 \(x, y\) (2D) 或 \(x, y, z\) (3D) 分量的结构体或类来表示。
struct Vector3 {
float x, y, z;
};向量的加法符合三角形法则。 - 加法:\(A + B\) 表示从 \(A\) 的起点出发,经过 \(A\) 到达 \(A\) 的终点,再以 \(A\) 的终点为起点,经过 \(B\) 到达 \(B\) 的终点。结果向量是从 \(A\) 的起点指向 \(B\) 的终点。 - 应用:位置更新 (新位置 = 旧位置 + 位移)。 - 减法:\(B - A\) 表示从 \(A\) 的终点指向 \(B\) 的终点的向量。 - 应用:计算从一个物体指向另一个物体的向量 (目标位置 - 玩家位置)。
将向量的每个分量乘以一个标量 \(k\)。 - 应用:缩放物体,或者根据时间步长缩放速度向量 (\(Position += Velocity * \Delta t\))。
点积是两个向量之间的一种运算,结果是一个标量。 公式:\(A \cdot B = |A| |B| \cos \theta\) 或者代数形式:\(A \cdot B = A_x B_x + A_y B_y + A_z B_z\)
点积描述了两个向量方向的相似程度。 - 如果 \(A \cdot B > 0\),夹角小于 90度 (方向大致相同)。 - 如果 \(A \cdot B = 0\),夹角等于 90度 (垂直)。 - 如果 \(A \cdot B < 0\),夹角大于 90度 (方向大致相反)。
叉积仅在 3D 空间中有定义,结果是一个新的向量,该向量垂直于参与运算的两个向量构成的平面。 公式:\(A \times B = (A_y B_z - A_z B_y, A_z B_x - A_x B_z, A_x B_y - A_y B_x)\)
结果向量的方向遵循右手定则。大小等于以 \(A\) and \(B\) 为边的平行四边形的面积。
归一化是将一个向量的长度变为 1,但保持方向不变的过程。结果向量称为单位向量 (Unit Vector)。
\[ \hat{v} = \frac{v}{|v|} \] 即:将向量的每个分量除以它的长度。
Vector3 direction = (targetPos - currentPos).normalized;
// 现在 direction 的长度是 1,我们可以乘以速度
velocity = direction * speed;计算向量长度需要开平方根(sqrt),这是一个相对昂贵的操作。如果只是比较两个距离的大小,可以直接比较平方长度:
// 慢:计算两次 sqrt
if ((a - b).magnitude < (a - c).magnitude) { ... }
// 快:省掉 sqrt
if ((a - b).sqrMagnitude < (a - c).sqrMagnitude) { ... }在每帧需要对成百上千个物体做范围检测时,这个优化非常显著。
严格来说叉积只定义在 3D 空间,但在 2D 游戏中,我们经常用一个”伪叉积”来判断方向:
\[cross_{2D}(A, B) = A_x B_y - A_y B_x\]
float Cross2D(Vector2 a, Vector2 b) {
return a.x * b.y - a.y * b.x;
}
// 判断转弯方向(AI 寻路、赛车游戏)
float turn = Cross2D(forward, toTarget);
if (turn > 0) TurnLeft();
else TurnRight();将向量 \(A\) 投影到方向 \(B\) 上:
\[proj_B A = rac{A \cdot B}{B \cdot B} B\]
如果 \(B\) 是单位向量,则简化为 \((A \cdot B) B\)。
投影在游戏中非常常用: - 斜坡移动:将移动向量投影到斜面上 - 阴影计算:将光线投影到平面上 - 速度分解:将速度分解为沿墙面和垂直墙面的两个分量
角色在斜坡上移动时,我们不希望移动方向”钻入”地面。解决方法是将移动向量投影到斜坡平面上:
// slopeNormal: 斜坡法线(单位向量)
// moveDir: 玩家输入的移动方向
Vector3 projectedMove = moveDir - Vector3.Dot(moveDir, slopeNormal) * slopeNormal;
// projectedMove 现在平行于斜面,长度略小于原 moveDir角色撞墙后不应该完全停下,而应该沿着墙面滑动:
// wallNormal: 墙面法线
// velocity: 碰撞前的速度
Vector3 slideVelocity = velocity - Vector3.Dot(velocity, wallNormal) * wallNormal;这两个场景的数学本质完全一样:从向量中减去法线方向的分量。
掌握向量运算是进行 3D 编程和物理模拟的第一步。下一章我们将讨论矩阵与坐标变换。
< 上一篇: 三角函数入门 | 回到目录 | 下一篇: 矩阵与变换 >
把当前热点继续串成多页阅读,而不是停在单篇消费。
2025-11-30 · game_math
深入理解游戏开发中的矩阵:TRS 变换与代码实践、矩阵乘法与组合变换、MVP 管线详解、逆矩阵、法线变换,以及旋转表示方式对比。
2025-11-30 · game_math
为什么游戏引擎都用四元数来表示旋转?详解欧拉角的万向节死锁问题,以及四元数的定义、运算和 Slerp 插值。
2025-11-30 · game_math
游戏开发数学专题索引。从标量函数到四元数,从碰撞检测到骨骼动画——一条完整的游戏数学学习路径。
2025-11-30 · game_math
详解游戏引擎中常用的标量数学函数:Lerp, InverseLerp, Remap, Clamp, SmoothStep 等。不仅有公式,更有实际应用场景。