Why Recalculate Inertia After Scaling Ammo.js Shapes

When working with the ammo.js physics engine, adjusting the local scaling of a collision shape alters its physical dimensions. Because a shape’s mass distribution changes with its size, the rigid body’s local inertia tensor becomes outdated. This article explains the relationship between shape scaling and rotational inertia, detailing why you must manually recompute and apply the new inertia to maintain realistic physical simulations.

Understanding the Physics of Inertia

In physics, the moment of inertia represents an object’s resistance to rotational acceleration. Unlike mass, which is a constant scalar value representing resistance to linear acceleration, inertia depends heavily on how that mass is distributed relative to the object’s axis of rotation.

Mathematically, the moment of inertia (\(I\)) for a given axis is proportional to the mass (\(m\)) and the square of the distance (\(r\)) from the rotation axis:

\[I \propto m \cdot r^2\]

When you change the local scaling of a shape in ammo.js (for example, stretching a sphere into an ellipsoid or making a box twice as wide), you are changing the distance (\(r\)) of the mass points from the center of gravity. Even if the total mass of the object remains exactly the same, spreading that mass over a larger or smaller volume fundamentally alters how difficult it is to rotate the object.

How Ammo.js Handles Shape Scaling

Ammo.js (a JavaScript port of the Bullet physics SDK) separates the collision geometry from the dynamic properties of a rigid body:

  1. btCollisionShape: Defines the geometry and dimensions of the object.
  2. btRigidBody: Manages the dynamics, including velocity, mass, forces, and local inertia.

When you instantiate a rigid body, you calculate its initial local inertia based on the shape’s original dimensions and mass using the calculateLocalInertia method. The rigid body then stores this inertia vector in its internal state.

If you subsequently call shape.setLocalScaling(newScale), you instantly modify the physical dimensions of the collision shape. However, ammo.js does not automatically update the rigid body’s cached dynamics. The rigid body continues to use the inertia tensor calculated for the shape’s original, unscaled dimensions.

The Consequences of Ignoring Recalculation

Failing to recompute inertia after scaling a shape leads to unrealistic and broken physics behaviors:

How to Correctly Update Scale and Inertia

To scale a shape correctly in ammo.js, you must follow a specific sequence of updating the shape, recalculating the inertia, and reapplying those properties to the rigid body.

1. Set the New Scaling

First, apply the new scale vector to the collision shape.

const scaleVector = new Ammo.btVector3(2.0, 2.0, 2.0); // Example: Double the size
collisionShape.setLocalScaling(scaleVector);

2. Recalculate Local Inertia

Use the shape to calculate the new inertia vector based on the rigid body’s existing mass.

const mass = 1.0; // The mass of your rigid body
const localInertia = new Ammo.btVector3(0, 0, 0);
collisionShape.calculateLocalInertia(mass, localInertia);

3. Apply the New Properties to the Rigid Body

Update the rigid body’s mass and inertia properties using the setMassProps method.

rigidBody.setMassProps(mass, localInertia);
rigidBody.updateInertiaTensor();

4. Activate the Body

If the rigid body was asleep (deactivated), force it to re-evaluate its state within the physics world.

rigidBody.activate(true);