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:

  1. The polygon vertex set is divided into two or more distinct sets of vertices.
  2. The center of mass (centroid) shifts for each new piece.
  3. The surface area decreases, which should lower the total mass if material density remains constant.
  4. 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:

  1. Decompose the piece into convex parts using a decomposition library (such as poly-decomp.js, which Matter.js supports natively).
  2. Pass the decomposed vertex array into Bodies.fromVertices(x, y, [partA, partB, ...]).
  3. 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.