Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

刚体状态

在物理引擎中,一个刚体是模拟的基本单元。为了完整地描述一个刚体在任何时刻的物理状态,并为其运动演化提供必要的数据,我们需要一个精心设计的数据结构。这个数据结构不仅要包含物体的当前位置和朝向,还要存储其速度、质量属性、受力情况以及与其他物体交互所需的参数。

静态属性

这些属性在物体被创建后通常不会改变。它们定义了物体的内在物理特性。

  • 质量 (Mass) m: 一个标量,描述物体抵抗线性加速度的程度。
  • 逆质量 (Inverse Mass) 1/m: 在计算中,我们更常用到质量的倒数。这样做可以将除法运算转换成乘法运算,效率更高。对于质量无穷大的静态物体(如地面),其逆质量为0。这是一种优雅的处理方式,使得求解器无需为静态物体编写特殊代码——施加在它们身上的冲量乘以0后,速度变化自然也为0。
  • 惯性张量 (Inertia Tensor) I_body: 一个 3x3 矩阵,在物体的局部坐标系(body space)中定义,描述物体抵抗角加速度的程度。
  • 逆惯性张量 (Inverse Inertia Tensor) I_body⁻¹: 同样,我们预先计算并存储惯性张量的逆,以提高计算效率。对于不希望旋转的物体,可以将其逆惯性张量设为零矩阵。
  • 碰撞形状 (Collision Shape): 指向物体碰撞几何体(如球体、盒子、凸包)的指针或引用。这是碰撞检测系统需要的核心数据。
  • 物理材质 (Material): 包含摩擦系数(friction)和恢复系数(restitution, a.k.a. bounciness)等参数。

动态状态 (Dynamic State)

这些是描述物体当前运动状态的变量,它们在每个模拟时间步都会被积分器更新。

  • 位置 (Position) x: 一个 3D 向量,描述物体质心在世界空间中的位置。
  • 朝向 (Orientation) q: 一个单位四元数,描述物体从其局部坐标系到世界坐标系的旋转。
  • 线速度 (Linear Velocity) : 一个 3D 向量,描述质心的速度。
  • 角速度 (Angular Velocity) : 一个 3D 向量,描述物体围绕其质心的角速度。

派生数据 (Derived Data)

这些数据可以由上述核心状态计算得出,但为了性能考虑,可能会在每帧开始时计算并缓存起来。

  • 世界空间逆惯性张量 (World Inverse Inertia Tensor) I_world⁻¹: 其中 是由朝向四元数 导出的旋转矩阵。这个矩阵在求解器计算角加速度时频繁使用。

  • 变换矩阵 (Transform Matrix): 一个 4x4 矩阵,结合了位置和朝向,用于将顶点从局部空间变换到世界空间,主要供渲染系统使用。

临时变量 (Temporary Variables)

这些变量用于在单个时间步内累积结果。

  • 总受力 (Total Force) F: 在施加力阶段累积的所有外力(如重力、玩家施加的力)的合力。
  • 总力矩 (Total Torque) τ: 累积的所有外力矩的合力。

在每个积分步骤结束时,这些累加器都需要被清零。

数据结构示例

一个典型的刚体数据结构可能如下所示:

struct RigidBody {
    // --- 静态属性 ---
    float mass;                 // 质量
    float inverseMass;          // 逆质量
    Matrix3x3 inertiaTensorBody; // 局部坐标系下的惯性张量
    Matrix3x3 inverseInertiaTensorBody; // 局部坐标系下的逆惯性张量

    CollisionShape* shape;      // 指向碰撞形状
    Material material;          // 物理材质 (摩擦, 恢复系数)

    // --- 动态状态 ---
    Vector3 position;           // 位置
    Quaternion orientation;     // 朝向

    Vector3 linearVelocity;     // 线速度
    Vector3 angularVelocity;    // 角速度

    // --- 派生数据 (可缓存) ---
    Matrix3x3 inverseInertiaTensorWorld; // 世界坐标系下的逆惯性张量
    Matrix4x4 transformMatrix;           // 变换矩阵

    // --- 临时变量 ---
    Vector3 force;              // 总受力
    Vector3 torque;             // 总力矩

    // --- 标志位 ---
    bool isStatic;              // 是否为静态物体
    bool isAwake;               // 是否处于激活状态
};

在面向数据的设计中,我们不会创建这样一个大的结构体数组。相反,我们会为每个成员创建一个独立的数组:

struct RigidBodySystem {
    std::vector<float> masses;
    std::vector<float> inverseMasses;
    // ...
    std::vector<Vector3> positions;
    std::vector<Quaternion> orientations;
    // ...
};

虽然在概念上我们可以将所有数据封装在一个 RigidBody 类中,但在追求极致性能的现代引擎中,采用面向数据的设计,将状态分解为多个并行的数组,是最大化缓存利用率和释放SIMD潜力的关键。