What is cloth simulation?
Cloth simulation models a piece of fabric as a grid of particles connected by distance constraints. Each particle has position and velocity; each constraint tries to maintain a rest length between two particles. When you combine these with gravity and collision, you get realistic draping, billowing, and folding behavior.
The particle grid
A cloth mesh is typically a 2D grid of particles. Each particle stores its current position and its previous position (for Verlet integration). Constraints connect each particle to its horizontal and vertical neighbors, and sometimes diagonally for shear resistance.
// Create a cloth grid
const cols = 20, rows = 20;
const restLength = 1.0;
for (let y = 0; y < rows; y++) {
for (let x = 0; x < cols; x++) {
particles.push({
pos: { x: x * restLength, y: y * restLength, z: 0 },
prev: { x: x * restLength, y: y * restLength, z: 0 },
pinned: y === 0, // pin top row
});
}
}Verlet integration
Instead of storing velocity explicitly, Verlet integration derives velocity from the difference between current and previous positions. This makes it trivially stable for constraint systems — the constraints just move particles directly and the integration naturally handles the resulting velocity change.
function integrate(particle, dt, gravity) {
if (particle.pinned) return;
const vx = particle.pos.x - particle.prev.x;
const vy = particle.pos.y - particle.prev.y;
const vz = particle.pos.z - particle.prev.z;
particle.prev = { ...particle.pos };
particle.pos.x += vx * 0.99; // damping
particle.pos.y += vy * 0.99 + gravity * dt * dt;
particle.pos.z += vz * 0.99;
}Distance constraints
After integration, each constraint checks whether its two particles are at the correct distance. If not, it pushes them apart (or pulls them together) by half the error each. Running multiple constraint iterations per frame increases stiffness.
function solveConstraint(a, b, restLength) {
const dx = b.pos.x - a.pos.x;
const dy = b.pos.y - a.pos.y;
const dz = b.pos.z - a.pos.z;
const dist = Math.sqrt(dx*dx + dy*dy + dz*dz);
const diff = (dist - restLength) / dist * 0.5;
if (!a.pinned) {
a.pos.x += dx * diff;
a.pos.y += dy * diff;
a.pos.z += dz * diff;
}
if (!b.pinned) {
b.pos.x -= dx * diff;
b.pos.y -= dy * diff;
b.pos.z -= dz * diff;
}
}Wind and external forces
Wind is applied per-triangle as a force proportional to the triangle's area facing the wind direction. This creates the realistic billowing effect. You can also add drag, turbulence (using Perlin noise), and interaction forces for mouse/touch input.
Key parameters to experiment with
In the ThinkInsideTheBox cloth editor, you can adjust: stiffness (constraint iterations), damping, wind strength and direction, gravity, pin positions, and grid resolution. Try reducing iterations to see how cloth becomes stretchy, or cranking wind to see dramatic billowing.