17. Cloth Physics

By Diederick Huijberts en Rick Companje (Feb 2011)

Springs are structural elements that, when connected between two objects (particles), apply equal and opposite forces to each object. 
Simple cloth physics use multiple springs connected to particles in a grid.

Vimeo video


The rule related to spring forces is called Hooks law: f = -k * delta L
-k  = spring length: in code just a float strength which often gets a value like 0.1 or 0.001 etc.
delta L = difference between springs "compressed/rest length" and current length.

In simple cloth physics particles are positioned on a grid and then connected by 3 kind of springs:
  • structural springs
  • shear springs
  • bending springs



testApp.h

#ifndef _TEST_APP
#define _TEST_APP

#include "ofMain.h"
#include "ofxVectorMath.h"
#include "Particle.h"
#include "Spring.h"

class testApp : public ofBaseApp{
public:
    void setup();
    void update();
    void draw();
    
    vector<Particle> ps;
    vector<Spring> sp;
};

#endif

Particle.h

#ifndef PARTICLE_H
#define PARTICLE_H

#include "ofMain.h"

struct Particle {
    ofxVec3f pos,vel,forces;
    float mass,inverse_mass,drag;
    
    Particle(ofxVec3f pos, float mass, float drag = .96) : pos(pos), mass(mass), drag(drag) {
        if (mass==0.0f) inverse_mass = 0;
        else if (mass<0.001) mass=0.001;
        if (mass!=0.0f) inverse_mass = 1/mass;
    }
    
    void update() {
        forces *= inverse_mass;
        vel += forces;
        forces = 0;
        vel.limit(15);
        pos += vel;
        vel *= drag;
    }
    
    void addForce(ofxVec3f oForce) {
        forces += oForce;
    }
};

Spring.h

#ifndef SPRING_H
#define SPRING_H

#include "ofMain.h"
#include "Particle.h"

struct Spring {
    Particle *a, *b;
    float k;
    float rest_length;
    
    Spring(Particle *a, Particle *b, float k = .2) : a(a), b(b), k(k) {
        rest_length = (b->pos - a->pos).length();
    }
    
    void update() {
        ofxVec3f dir = b->pos - a->pos;
        float dist = dir.length();
        if (dist == 0.0) dist = 0.0001; // prevent division by zero
        float f = (rest_length - dist) * k; // linear force spring
        dir.normalize();
        a->addForce(dir * -f);
        b->addForce(dir * f);
    }
};

#endif

testApp.cpp

#include "testApp.h"

//--------------------------------------------------------------
void testApp::setup(){
    ofBackground(0,0,0);
    ofSetFrameRate(60);
    ofEnableSmoothing();
    
    int rows = 20;
    int cols = 20;

    //position all particles
    for (int i=0; i<rows*cols; i++) {
        int x = int(i) % cols * 20;
        int y = int(i) / cols * 20;
        Particle p(ofxVec3f(x,y,0), y==0 ? 0 : 1, .96);
        ps.push_back(p);
    }
    
    //create all springs
    for (int i=0; i<rows*cols; i++) {
        int x = int(i) % cols;
        int y = int(i) / cols;
        
        //horizontal structural springs
        if (x<cols-1) {
            sp.push_back(Spring(&ps[i],&ps[i+1]));
        }
        
        //vertical structural springs
        if (y<rows-1) {
            sp.push_back(Spring(&ps[i],&ps[i+cols]));
        }
        
        //shear springs left to right
        if (x<cols-1 && y<rows-1) {
            sp.push_back(Spring(&ps[i],&ps[i+cols+1]));
        }
        
        //shear springs right to left
        if (y>0 && x<cols-1 && y<rows) {
            sp.push_back(Spring(&ps[i],&ps[i-cols+1]));
        }
        
        //bending springs horizontal
        if (x<cols-2) {
            sp.push_back(Spring(&ps[i],&ps[i+2]));
        }
        
        //bending springs vertical
        if (y<rows-2) {
            sp.push_back(Spring(&ps[i],&ps[i+2*cols]));
        }
        
        //bending springs diagonal
        if (y<rows-2 && x<cols-2) {
            sp.push_back(Spring(&ps[i],&ps[i+2+2*cols]));
        }
    }
        
    
}

//--------------------------------------------------------------
void testApp::update(){

    //apply forces
    for (int i=0; i<ps.size(); i++) {
        ps[i].addForce(ofxVec3f(0,1.1,0));
        ps[i].addForce(ofxVec3f(0,0,sin(ofGetElapsedTimef() * 1.6)*8));
    }
    
    //update springs
    for (int i=0; i<sp.size(); i++) {
        sp[i].update();
    }
    
    //update particles
    for (int i=0; i<ps.size(); i++) {
        ps[i].update();
    }
    
}

//--------------------------------------------------------------
void testApp::draw() {
    
    ofTranslate(ofGetWidth()/2-200, 100, -300);
    
    //springs
    ofSetColor(255, 255, 255);
    glBegin(GL_LINES);
    for (int i=0; i<sp.size(); i++) {
        glVertex3f(sp[i].a->pos.x, sp[i].a->pos.y, sp[i].a->pos.z);
        glVertex3f(sp[i].b->pos.x, sp[i].b->pos.y, sp[i].b->pos.z);
    }    
    glEnd();
    
    //particles
    ofSetColor(0, 0, 255);
    glPointSize(5);
    glBegin(GL_POINTS);
    for (int i=0; i<ps.size(); i++) {
        glVertex3f(ps[i].pos.x, ps[i].pos.y, ps[i].pos.z);
    }    
    glEnd();
}
Č
ċ
Rick Companje,
6 dec. 2011 10:20
Comments