Recalculate Mass and Inertia for Matter.js Bodies
When dynamic slicing or fracturing algorithms split a rigid body into smaller pieces in Matter.js, the resulting polygons require updated physical properties to behave realistically. Matter.js does not automatically synchronize density and rotational inertia if vertices are manually reassigned to an existing body. This guide explains how to properly recalculate mass, center of mass, and moment of inertia for newly sliced body pieces using both Matter.js built-in utilities and custom vertex math.
Understanding the Slicing Problem
When a 2D physics body is cut:
- The polygon vertex set is divided into two or more distinct sets of vertices.
- The center of mass (centroid) shifts for each new piece.
- The surface area decreases, which should lower the total mass if material density remains constant.
- The moment of inertia (resistance to rotational acceleration) drastically changes based on the new mass distribution relative to the new centroid.
Failing to recalculate these values causes sliced objects to rotate around off-center points or spin erratically due to mismatched inertia tensors.
Method 1: Automatic Recalculation Using Built-in Methods
Matter.js provides built-in methods that recompute area, mass, and inertia automatically when new vertices are applied.
Creating New Bodies from Slices
The cleanest approach is instantiating each sliced polygon as a fresh
Body using Bodies.fromVertices. This
automatically calculates the centroid, moment of inertia, and mass based
on the provided density:
// vertices: Array of Matter.Vector objects [{x, y}, ...] forming the sliced polygon
// parentBody: The original Body that was sliced
const centroid = Matter.Vertices.centre(vertices);
const slicedBody = Matter.Bodies.fromVertices(
centroid.x,
centroid.y,
[vertices],
{
density: parentBody.density,
friction: parentBody.friction,
frictionAir: parentBody.frictionAir,
restitution: parentBody.restitution
}
);
Matter.Composite.add(engine.world, slicedBody);Updating an Existing Body
If you mutate an existing body instead of creating a new one, use
Body.setVertices followed by
Body.setDensity:
// 1. Assign the new polygon geometry
Matter.Body.setVertices(body, slicedVertices);
// 2. Re-apply the target density to recalculate mass and inertia automatically
Matter.Body.setDensity(body, targetDensity);Matter.Body.setVertices automatically moves the body's
position to the new geometric centroid and updates the inertia tensor
according to the new vertex distribution.
Method 2: Manual Recalculation of Mass and Inertia
If your application requires custom mass distribution or non-standard polygonal density, manually calculate the properties using Matter.js helper modules.
1. Calculate Area and Centroid
First, determine the geometric centroid and area using
Matter.Vertices:
const area = Matter.Vertices.area(vertices);
const centroid = Matter.Vertices.centre(vertices);2. Recalculate Mass
Mass is defined as area multiplied by density:
const mass = area * density;
Matter.Body.setMass(body, mass);3. Recalculate the Moment of Inertia
The moment of inertia \(I\) for an
arbitrary 2D polygon about its centroid can be calculated directly using
Matter.Vertices.inertia:
// Vertices must be centered relative to (0, 0) before calculating inertia
const centeredVertices = vertices.map(v => ({
x: v.x - centroid.x,
y: v.y - centroid.y
}));
const inertia = Matter.Vertices.inertia(centeredVertices, mass);
Matter.Body.setInertia(body, inertia);Under the hood, Matter.Vertices.inertia computes the
second moment of area for a polygon using the cross-product summation
formula:
\[I = \frac{\text{mass}}{6} \cdot \frac{\sum |v_i \times v_{i+1}| \left( \|v_i\|^2 + v_i \cdot v_{i+1} + \|v_{i+1}\|^2 \right)}{\sum |v_i \times v_{i+1}|}\]
Handling Non-Convex Slices
Matter.js assumes primitive bodies are convex. Slicing concave shapes can yield complex concave pieces. If a cut produces a concave piece:
- Decompose the piece into convex parts using a decomposition library
(such as
poly-decomp.js, which Matter.js supports natively). - Pass the decomposed vertex array into
Bodies.fromVertices(x, y, [partA, partB, ...]). - Matter.js will assemble a compound body where each sub-part has its own correctly calculated inertia and mass, properly weighted around the combined center of mass.