2D物理效果代码实现思路(8)逆质量

By pocaster

逆质量:质量的倒数(inverse mass, 1/mass)


1. 为什么要用逆质量(Inverse Mass)?

(1)避免重复除法计算

在实时物理系统中,经常需要计算 F/m (例如加速度 a = F_net / m)。如果每次计算都做除法,当物体数量较大时会显著增加计算开销。而用逆质量后:

a = F_net * inv_mass; // inv_mass = 1/mass,提前预计算一次
  • 除法变乘法:除法运算在多数CPU架构中代价更高,替换为乘法可提升性能。

(2)数学表达更简洁

许多物理公式(如碰撞冲击响应、约束力求解)涉及 1/mass 的项。例如动量守恒中的相对速度修正: \(\Delta v = \frac{J}{m}\) 如果预先存入逆质量 inv_mass,可直接调用乘积,避免公式中出现除法符号。

(3)特殊情况的统一处理

  • 无限大质量(静态物体):设置 inv_mass = 0,表示静态物体(质量极大,无法移动)。
  • 零质量(非法值):不允许设置为零,通过 inv_mass 的参数设计提前杜绝除以零的风险。

2. 逆质量的代码实现

(1)基础实现

Particle 类添加逆质量成员,并确保与 mass 的参数同步:

class Particle {
public:
    Vector2 position;
    Vector2 velocity;
    Vector2 force;
    float inv_mass; // 关键变化:用逆质量代替质量

    // 设置初始质量
    void SetMass(float mass) {
        // 质量必须严格大于零
        if (mass <= 0.0f) {
            inv_mass = 0.0f; // 默认为静态物体
            return;
        }
        inv_mass = 1.0f / mass;
    }

    // 外力累加逻辑不变
    void ApplyForce(Vector2 f) {
        force += f;
    }

    void Update(float dt) {
        // 关键不同点:直接用逆质量计算加速度
        Vector2 acceleration = force * inv_mass; 

        velocity += acceleration * dt;
        position += velocity * dt;

        force = Vector2(0, 0);
    }
};

(2)静态物体的标识

例如设置一堵墙的质量为无穷大,对应的 inv_mass = 0

Particle static_obstacle;
static_obstacle.SetMass(0.0f); // inv_mass 设为0,永远不受力

(3)动态调整质量

修改质量后需要更新 inv_mass(如爆炸后物体质量变化):

void Particle::ChangeMass(float new_mass) {
    SetMass(new_mass); // 更新 inv_mass 值
}

3. 逆质量在物理引擎中的应用

(1)力-加速度类计算

所有需要计算 a=F/m 的地方直接替换为 a=F*inv_mass。 例如全局重力应用:

Vector2 gravity(0, 9.8f);
void ApplyGravity(Particle& p) {
    Vector2 force = gravity * (p.inv_mass > 0.0f ? (1.0f / p.inv_mass) : 0.0f);
    p.ApplyForce(force);
}

更优化的写法:根据 inv_mass 是否为0区分静态物体,避免判断 mass 有效性。

(2)碰撞响应中的冲量(Impulse)计算

碰撞处理中冲量公式的核心是: \(J = \frac{-(1 + e) \cdot v_{\text{rel}} \cdot n}{n \cdot n \cdot (inv\_mass_A + inv\_mass_B)}\) 代码中直接使用 inv_mass 可以让表达式更短且无除法:

Vector2 normal = GetCollisionNormal();
float inv_mass_sum = bodyA.inv_mass + bodyB.inv_mass;

float impulse = -(1.0f + restitution) * dot(relative_velocity, normal);
impulse /= dot(normal, normal) * inv_mass_sum;

bodyA.velocity += impulse * bodyA.inv_mass * normal;
bodyB.velocity -= impulse * bodyB.inv_mass * normal;

4. 深度优化:Scalar Inv_Mass 的扩展

一些引擎会引入 标量逆质量(scalar inverse mass),用于处理旋转惯性矩:

struct RigidBody {
    Vector2 position;
    float rotation;
    Vector2 velocity;
    float angular_velocity;
    float inv_mass;
    float inv_inertia; // 标量逆转动惯量

    // 动力学方程中扭矩到角加速度的转换:
    // angular_acceleration = torque * inv_inertia
};

用统一模式处理平动和旋转的动力学计算,提升代码一致性。

总结

逆质量是工业级物理系统的核心优化方向之一,其价值贯穿于以下三点:

  1. 加速计算:除法转乘法优化高频代码路径。
  2. 代码清晰:消弭公式中的除法干扰,易于阅读。
  3. 逻辑统一:无缝支持动态/静态物体区分。
Tags: Gamedev Public