Page 2: Cloth Simulation

In this page, we’re going to learn how to create a simple cloth simulator using THREE.js and the CS559 framework. We’ll start from the basics and build things up step by step.

Here’s what we’ll cover:

  • Modeling cloth with a mass–spring system: how to represent cloth as particles and springs (spatial discretization).
  • Simulating motion over time: how to update the cloth step by step so it moves naturally (temporal discretization).
  • Numerical issues: what can go wrong (like instability or stretching) and how to address these problems.
  • Making it realistic: adding details so the cloth looks and behaves more like the real thing.

By the end, you’ll have your very own cloth simulation running in the browser — and a better understanding of how physics-based simulation works in computer graphics.

(If you need a bit of convincing about why cloth simulation matters, check out this Virtual Runway demo. It shows how realistic cloth movement can bring graphics and animation to life.)


Modeling Cloth with a Mass–Spring System

When building a cloth simulation, the first question you might ask is:

“How can we represent cloth in a computer so that it makes sense to the program?”

The key difference between cloth and the rigid objects we’ve dealt with so far is that cloth cannot be represented by a single transformation matrix. For rigid objects, the relative positions of vertices never change, so storing one matrix for translation, rotation, and scaling is sufficient.

Cloth, however, behaves differently. The relative positions between its particles change over time because it deforms. That means we need to track the position of every vertex individually and compute the forces acting on each one.

One of the simplest and most intuitive ways to model this behavior is with a mass–spring system, as shown below:

Mass–Spring model

In this tutorial, we’ll represent cloth as a mass–spring model, where each mass point is connected to its neighbors by springs. These springs follow Hooke’s law, which states that the force of a spring is proportional to how much it is stretched or compressed:

F=k(xx0)dF = -k (x - x_0) d
  • kk: spring stiffness constant
  • xx0x - x_0: amount of stretch or compression (current length – rest length)
  • dd: unit vector pointing from one mass point to the other

For more details on the physics, see Hooke’s law.


Time Integration

In the previous section, we learned how to model cloth with a data structure that the computer can understand — a process called spatial discretization. Now, we need to think about time discretization: how to update the system step by step over time.

In other words:

“If we know the current positions and velocities of the mass points, how can we determine their positions in the next moment?”

Explicit Euler Integration

One of the simplest approaches is the Explicit Euler method. The idea is straightforward:

  1. Compute acceleration using Newton’s second law:

    at=Ft/ma_t = F_t / m
  2. Update velocity:

    vt+1=vt+atΔtv_{t+1} = v_t + a_t Δt
  3. Update position:

    xt+1=xt+vtΔtx_{t+1} = x_t + v_t Δt

Now, we have all the core components needed to build a basic cloth simulation!


Simple Mass–Spring Simulation

Let’s start with a simple mass–spring simulation. Please read 10-02-01.js , which implements a single mass–spring system.
In this code, the stepWorld function performs time integration: it calculates spring forces using Hooke’s law, computes acceleration, updates velocity, and finally determines the next position of the mass point. The code is short, so you should be able to follow it easily.

Box 10-02-01   10-02-01.html   10-02-01.js

Try increasing the timestep or the spring constant. You’ll notice the simulation becomes inaccurate and eventually blows up (values go to NaN).
Is this a bug in our code? Fortunately (or unfortunately), it isn’t. The instability comes from numerical errors in the time integration method. Since Explicit Euler updates positions and velocities using only the current state, errors accumulate over time, leading to increasingly large spring forces and eventual instability.

Things get worse in more complex systems:

Box 10-02-02   10-02-02.html   10-02-02.js

In 10-02-02.js , which implements four connected mass–spring points, try running the same settings with timestep = 0.03 in both 10-02-01.js (single spring) and 10-02-02.js (four springs). You’ll see that while the single spring might remain stable, the four-spring system blows up. This shows that larger systems with more springs are much more susceptible to instability.

Simulation code can be tricky — when something goes wrong, it’s often hard to tell whether it’s a bug or numerical instability. To handle this, always start with simple scenarios and mild settings (small timestep, low spring stiffness), and include code that checks for NaN values (NaN means “Not a Number”). You can find NaN detection code inside the stepWorld function.

In the next example, you can experiment with higher-resolution cloth and observe how instability increases with more mass points, stiffer springs, or stronger gravity:

Box 10-02-03   10-02-03.html   10-02-03.js

The UI also includes a “damping” slider. Damping helps reduce instability by scaling down velocity each timestep:

mass.velocity.multiplyScalar(damping);

You’ll notice that higher damping (smaller damping factor) makes the simulation more stable. However, this damping is not physically realistic — it doesn’t follow any real-world physics. If the damping is too strong, the motion freezes; if it’s too weak, the system becomes unstable.

In the next section, you will learn how to make the simulation more stable in a physically accurate way.


Toward More Stable and Realistic Simulation

Our simulator ( 10-02-03.js ) works, but it’s far from realistic. It’s either unstable or static due to excessive damping. In this section, we’ll add new features to improve both realism and stability.

1. Realistic Damping

Previously, we used a non-physical damping term. In reality, drag force is proportional to the square of velocity:

Fdrag=cvvF_{drag} = -c |v| v

Here, cc is the drag coefficient. This force slows particles down in a way that resembles air resistance. The total acceleration becomes:

a=(Fspring+Fgravity+Fdrag)/ma = (F_{spring} + F_{gravity} + F_{drag}) / m

Unlike artificial damping, this model is physically realistic. Because it scales with velocity, it applies stronger damping only when particles move faster — keeping motion lively and natural.

2. More Stable Integration

Previously, our Explicit Euler integration updated blindly using only the current values:

vt+1=vt+atΔtv_{t+1} = v_t + a_t Δt
xt+1=xt+vtΔtx_{t+1} = x_t + v_t Δt

What if we try updating with future values instead?

vt+1=vt+at+1Δtv_{t+1} = v_t + a_{t+1} Δt
xt+1=xt+vt+1Δtx_{t+1} = x_t + v_{t+1} Δt

Here, at+1a_{t+1} depends on the unknown future state.
To compute this, we need to solve a nonlinear equation, for example:

m(vt+1vt)/Δt=F(xt+1,vt+1)m (v_{t+1} - v_t) / Δt = F(x_{t+1}, v_{t+1})
xt+1=xt+vt+1Δtx_{t+1} = x_t + v_{t+1} Δt

By substituting the second equation into the first, we end up with a root-finding problem in terms of xt+1x_{t+1}.
This is the Implicit Euler integration scheme.

The benefit is that it’s extremely stable — instead of letting errors grow, it tends to damp them out over time.
The downside is that each timestep requires solving a nonlinear equation, which is computationally expensive.
Still, implicit schemes are the industry standard — as you saw in the Virtual Runway video, most state-of-the-art cloth simulation systems and commercial software rely on them.

Since solving nonlinear equations is a deeper topic (if you’re interested, check out a Numerical Analysis course at UW–Madison), we won’t go into it here.
Instead, we’ll look at an integration scheme that lies between explicit and implicit methods.

It’s called the Symplectic Euler (Semi-Implicit Euler) scheme.
It uses the current acceleration to update velocity, and then uses the updated velocity to compute the next position:

vt+1=vt+atΔtv_{t+1} = v_t + a_t Δt
xt+1=xt+vt+1Δtx_{t+1} = x_t + v_{t+1} Δt

This small change makes the simulation much more stable than the explicit Euler scheme, while still keeping the implementation simple.

(Other integration schemes, such as Verlet integration, are also simple to implement and help improve stability.)

3. Additional Spring Types

So far, we have only used structural springs, which makes the simulation look more like a net than actual cloth. To improve realism, we can add other types of springs, as shown below:

Three spring types
  • Shear springs: connect diagonal neighbors to prevent the cloth from collapsing into parallelogram shapes.
  • Bending springs: connect vertices two steps apart, adding resistance to folding and floppiness.

Implementing these springs results in much more natural-looking motion.

4. Meshing the Cloth

Up to this point, our cloth ( 10-02-03.js ) has existed only as a grid of particles connected by springs. To visualize it as real cloth, we need to convert this grid into a triangular mesh that can be rendered. Each particle becomes a vertex, and every small square of four neighboring points is divided into two triangles. By connecting all the points this way, we form a smooth rectangular surface — the standard representation used by rendering engines like THREE.js.

If you complete meshing the cloth, you can also try adding texture. For texturing, you have to manually map each mass point to texture coordinates (UVs).

Now, let’s create your own cloth simulator!

Box 10-02-04  (5 basic + 5 advanced)   10-02-04.html   10-02-04.js

Implement the concepts discussed so far in 10-02-04.js .
If you successfully complete this step, your cloth should appear both stable and realistic. You are also encouraged to add your own improvements to make the simulation more dynamic and visually appealing.

Below are the requirements for this exercise.

Basic Items

10-02-04

  1. The default simulation settings should be numerically stable.
  2. Include UI controls for interactivity (e.g., moving or adjusting cloth corners through the interface).
  3. Implement a more stable integration method such as Symplectic Euler or Verlet integration.
  4. Implement a drag (air resistance) force, with parameters adjustable through the UI.
  5. Convert the cloth into a triangular mesh for rendering.

Advanced Items

10-02-04

  1. The simulation should show dynamic motion (e.g., fluttering in the wind). Be creative with your scenario!
  2. Implement shear and bending springs, and add a wireframe view option in the UI to visually show different spring connections.
  3. Add texture mapping to the cloth surface.
  4. Implement collision with an object (e.g., a sphere).
  5. Introduce technically challenging and visually noticeable features, such as:
    • self-collision (collision between cloth particles and springs)
    • collision with complex objects or meshes
    • tearing effects
    • or other creative extensions
Hints

To handle collisions, we usually need two steps: detection and resolution.

  1. Collision Detection
    In general, there are two types: mass point (vertex) vs. object and spring (line segment) vs. object.
    For this exercise, detecting mass point vs. object collisions is sufficient. When the object has a simple analytic shape (like a sphere or a plane), detection is easy — you can simply check the distance from each mass point to the object surface.

  2. Collision Resolution
    Once a collision is detected, we need to push the mass point back to the surface. A common approach is to apply a penalty force proportional to the penetration depth (how far the mass has gone inside the object). This creates a restoring force that prevents the cloth from passing through.

For more complex collisions, for example between the cloth and an arbitrary mesh, you would need to test each triangle of the mesh against the cloth particles or springs. This is computationally more expensive but necessary for precise simulation in advanced systems.


Advanced References

If you’d like to learn more about physics-based simulation, check out these resources: