Soft Body Balloon Pressure in Matter.js
Simulating a realistic, pressurized soft body balloon in Matter.js requires augmenting standard distance constraints with an active volume preservation mechanism. By default, soft bodies created with perimeter springs collapse under external forces because the physics engine does not natively calculate enclosed volume or internal fluid dynamics. To maintain internal pressure and prevent collapse, you must either dynamically apply outward normal forces based on the balloon's changing area or reinforce the structure with internal radial constraints.
Why Default Soft Bodies Collapse
Matter.js provides Composites.softBody, which generates
a grid or ring of rigid bodies linked by Constraint
instances. While perimeter constraints maintain the distance between
adjacent vertices, they have zero resistance to shear forces and
buckling. When external forces compress the balloon, the perimeter bends
inward without resistance because the engine does not treat the enclosed
space as an airtight, gas-filled chamber.
Solution 1: Dynamic Outward Normal Forces (Ideal Gas Simulation)
The most physically accurate way to maintain internal pressure is to compute the balloon's 2D area at each physics step and apply an outward force to every perimeter vertex relative to the volume displacement.
1. Calculate the Enclosed Area
Use the Shoelace formula (Gauss's area formula) on the ordered array
of perimeter vertices to find the current area \(A\) during the beforeUpdate
engine event:
function getPolygonArea(vertices) {
let area = 0;
const n = vertices.length;
for (let i = 0; i < n; i++) {
const j = (i + 1) % n;
area += vertices[i].position.x * vertices[j].position.y;
area -= vertices[j].position.x * vertices[i].position.y;
}
return Math.abs(area) / 2;
}2. Compute Pressure Magnitude
Define a target rest area (\(A_0\)) representing the uncompressed volume of the balloon, along with an internal stiffness constant (\(k\)):
\[\text{Pressure} = k \times \max(0, A_0 - A)\]
If the balloon compresses (\(A < A_0\)), the pressure increases, simulating Boyle's Law.
3. Apply Outward Normal Forces
For each vertex along the perimeter, determine the normal vector
pointing outward from the interior. Apply the pressure force along this
normal vector directly to each vertex body using
Matter.Body.applyForce:
Matter.Events.on(engine, 'beforeUpdate', () => {
const currentArea = getPolygonArea(balloonVertices);
const pressure = Math.max(0, (restArea - currentArea) * pressureStiffness);
for (let i = 0; i < balloonVertices.length; i++) {
const prev = balloonVertices[(i - 1 + balloonVertices.length) % balloonVertices.length].position;
const next = balloonVertices[(i + 1) % balloonVertices.length].position;
// Tangent vector between neighbors
const tx = next.x - prev.x;
const ty = next.y - prev.y;
// Perpendicular normal vector (outward facing)
let nx = -ty;
let ny = tx;
const length = Math.hypot(nx, ny);
if (length > 0) {
nx /= length;
ny /= length;
Matter.Body.applyForce(balloonVertices[i], balloonVertices[i].position, {
x: nx * pressure,
y: ny * pressure
});
}
}
});Solution 2: Radial Structural Constraints
If dynamic force calculation creates instability or performance overhead, you can maintain shape using structural distance constraints.
- Central Anchor Node: Place a lightweight central
body inside the balloon and link every perimeter vertex to this center
using
Matter.Constraint.createwith a stiffness between0.1and0.5. - Cross-Diameter Struts: Connect opposing vertices across the balloon directly to each other using spring constraints.
While radial constraints do not behave like a continuous fluid or gas, they provide an efficient geometric approximation that resists crushing and restores the balloon to its circular shape when compressed.