Curtain and How To Build a Fabric Simulator

Posted on February 5, 2011 | Category :Processing App, Source Code, Tutorial | 5 Comments

A cloth simulator is one of those things I’ve always wanted to make. I’ve given it a few attempts in the past, but hadn’t made much progress. Here I managed to make something that works (and pretty darn well, too) after doing about a week’s worth of research. If you’re a programmer or just plain interested, check out the details of the simulator after the jump.

Basic Particle Simulator

Most of my programs start out the same. Of course, with the traditional setup and draw functions Processing includes, I often make a Particle class (Ball class for my last program). Typically the particle class has 3 things: the position, the velocity, and the update function. Curtain was different though. When using Verlet Integration, the motion of a particle is mainly based around acceleration and change in position. To launch a particle towards a direction, you simply move it’s position. What’s great about this, especially for physics engines, is that you could just apply constraints to the position and a lot of the physics is practically done on its own.

Integration

So what is Verlet Integration? First of all, we need to understand what a Numerical Integration is. It can be described pretty well in Wikipedia

the part of numerical analysis which studies the numerical solution of ordinary differential equations (ODEs). This field is also known under the name numerical integration, but some people reserve this term for the computation of integrals.

Many differential equations cannot be solved analytically, in which case we have to satisfy ourselves with an approximation to the solution. The algorithms studied here can be used to compute such an approximation. An alternative method is to use techniques from calculus to obtain a series expansion of the solution.

Euler Integration

When you program any sort of physics simulator, you need to calculate where an object is. In order to calculate where an object is, you have to use the Equations of Motion.

` newPosition = position + velocity * deltaTime `

That, alone, is Euler Integration (Which is pronounce “Oiler Integration”, according to Glenn Fiedler). For each “update”, you add the velocity vector to the position vector and whenever you’d like to move the particle, you change the velocity. Velocity is multiplied by “deltaTime”, or change in time, to keep the simulation somewhat accurate. There’s a good reason for this. By not using deltaTime, each step size is basically 1. The position will move at the speed your program is running, and since no program is consistently any frame rate, we need to account for the change in time. Hence, deltaTime.

The main issue with Euler Integration is it’s inaccuracy. Unless we use an extremely small timestep size (which we have no control over), it’ll be inaccurate. Take a look at Wikipedia’s example:

The red line is approximated using the Euler Method, the blue is the actual curve

Verlet Integration

Verlet Integration is very similar to Euler Integration. Basically, we get rid of velocity. Instead we account for acceleration and change in position (which is basically velocity, except the physics isn’t done by changing the velocity vector).

` newPosition = position + (position - lastPosition) + 0.5 * acceleration * deltaTime * deltaTime `

Why would anyone want to do it this way, instead of the good old fashioned Euler way? I’ll tell you why. The physics basically does itself!

That means we don’t have to solve for velocity when solving for constraints. So when we’re building our cloth simulator, all that needs to be done is for the constraints to be solved and nothing else. You don’t need to calculate the resulting velocity or anything like that. The Verlet equation above does it for us. This is perfect for a cloth simulation. When we simulate our particles, we just need to move them towards each other and that’s it.

I use the verlet equation based off of GameDev’s Verlet Integration method.

``` velocity = position - lastPosition
deltaVelocity = velocity - lastPosition - twoStepsAgo
newPosition = position + velocity + 0.5 * acceleration * deltaTime * deltaTime
acceleration = deltaVelocity * deltaTime // (for the next iteration) ```

More Physics!

Using that, we can create an “Apply Force” function for things like gravity:

```
void applyForce (force) {
acceleration += force / mass
} ```

After adding an applyForce function, we can add gravity and a friction function. Since the friction takes into account velocity, we need to put it after velocity is calculated for that iteration.

``` // gravity: // f(gravity) = m * g, g = (0,9.8,0)
Vector gravityForce = new Vector(0, mass * 98, 0)
this.applyForce(gravityForce)
// friction (damping):
acceleration -= velocity * damping / mass ```

When you’d like to add on any sort of velocity, you could simply add the value to the position, rather than velocity.

Constraints

Constraints is the most important part of a cloth simulator. A constraint is a limit. In the case of our program, the constraint would be the distance between connected points. This will actually be a lot like the mtd (minimum translation distance) correction in the Ball simulator!

``` p1 = particle1 p2 = particle2
Vector delta = p1.position - p2.position
float dist = sqrt(delta.x * delta.x + delta.y * delta.y)
float difference = (restingDistance - d) / d
im1 = 1 / p1.mass // inverse mass quantities
im2 = 1 / p2.mass
p1.position += delta * (im1 / (im1 + im2)) * stiffness * difference
p2.position -= delta * (im2 / (im1 + im2)) * stiffness * difference ```

To optimize this, you can store the “(im1 / (im1 + im2)) * stiffness” and “(im2 / (im1 + im2)) * stiffness” portions in variables. The stiffness and restingDistance values are both pretty self explanatory. I use 0.8 for stiffness, and 5 for restingDistance, but it’s all personal preference, and I encourage you to experiment on different values.

Accuracy

Much like the ball simulator, you’ll probably find that this isn’t perfectly accurate. If you try to set the stiffness to 1, the cloth will still show elasticity. There’s a few ways to try and account for this, and they’re a lot like the ball simulator.

• A smaller step size can make the simulation a lot more accurate. The problem with this is that we can’t guarantee a consistently small step size. You could try out Runge-Kutta integration, which Glenn Fiedler and MyPhysicsLab both explain about in full detail.

• Solve the constraints more than once before updating the physics. This is what I’m doing right now (it’s solved 3 times in the demo). If the constraint solver isn’t too resource intensive, solving it more than once shouldn’t make too huge of an impact on your algorithm’s speed. This method isn’t fool proof though. After too many iterations, your program will slow down and with a larger step size (or slower frame rate), it becomes inaccurate again. So there needs to be a balance between iterations of constraint solving, and the frame rate in order for this to work ideally.

The rest of this you can program any way you’d like. If you want an example source, you can check out Curtain’s source at OpenProcessing. It’s programmed in Processing, a simplified Java API, and I did my best to document it for people to understand.

Resources

» Tags:

11/04/28

That’s a very interesting read and I love playing around with the simulator.
I’ll have to print out the code and your resources for my daily way to the university.
Very interesting to see theoretical things I have learnt and will learn as an interactive program.

11/04/30

Hi, your cloth simulation is awesome…
I want to implement it on my own, but I have two questions:

1 – Why do you multiply by 0.5 the acceleration term in the Verlet integration? Is it a mistake or is it due to something else?
I’ve seen Verlet position as:
x(t+dt)=2*x(t)-x(t-dt)+a(t)*dt^2

Here, however, there’s 0.5 that multiplies the acceleration term:
x(t+dt)=2*x(t)-x(t-dt)+0.5*a(t)*dt^2

2- I read the GameDev article. Verlet integration assumes a constant acceleration. Then, how should the (velocity dependent) friction be included?

The same thing happens with velocity Verlet integration: Wikipedia says that the algorithm assumes that the acceleration is not be dependent on velocity. How must friction be dealt with?

3. 11/04/30

1. I don’t remember. Some resources mention that a should be multiplied by 1/2 (eg. http://www.ch.embnet.org/MD_tutorial/pages/MD.Part1.html#Velocity Verlet and http://library.thinkquest.org/27948/accel.html# )
2. As for friction, I’m not too entirely sure. Perhaps if we applied it to (t-dt) in the equation? If you ever find out, I’d like to know.