• fullscreen
  • FlagSim.pde
  • collision.pde
  • subs.pde
  • surfaceForces.pde
  • windForces.pde
  • int numa = 40;
    int numb = 21;
    int elementWidth = 10;
    PVector[][] X = new PVector[numa][numb];
    PVector[][] V = new PVector[numa][numb];
    PVector[][] F = new PVector[numa][numb];
    float k = 0.1;
    float c = 0.01;
    float gravity = 0.01;
    float wind = 0.01;
    PVector[] constraint = new PVector[numb];
    boolean flagBool = false;
    PImage flag;
    void setup(){
      size(520,400,P3D);
      flag = loadImage("flag (2).jpg");
      reset();
      setupConstraint();
    }
    void draw(){
      background(0);
      physics();
      lights();
      drawSheet();
    }
    void keyPressed(){
      if (key==' '){
        if (flagBool == false){
          flag = loadImage("flag (3).jpg");
          flagBool = true;
        }else{
          flag = loadImage("flag (2).jpg");
          flagBool = false;
        }
      }
    }
    
    int[][] slate = new int[numa*numb][2];
    int nodeCount = 0;
    void collisionSetup(){
      for (int i=0; i<numa; i++){
        for (int j=0; j<numb; j++){
          slate[nodeCount][0] = i;
          slate[nodeCount][1] = j;
          nodeCount++;
        }
      }
    }
    boolean hasBeen = false;
    void collide(){
      float bumpRad = elementWidth * 1.5;
      if (hasBeen == false){
        collisionSetup();
        hasBeen = true;
      }
      for (int i=1; i<nodeCount; i++){
        for (int j=0; j<i; j++){
          if (testAdjacency(i,j)){
            PVector dx = PVector.sub(X[slate[j][0]][slate[j][1]],
                                     X[slate[i][0]][slate[i][1]]);
            if (abs(dx.x)<bumpRad){
              if (abs(dx.y)<bumpRad){
                if (abs(dx.z)<bumpRad){
                  if (dx.mag()<bumpRad){
                    float delta = (bumpRad - dx.mag()) * k;
                    dx.normalize();
                    F[slate[j][0]][slate[j][1]].add(PVector.mult(
                                                      dx,delta));
                    F[slate[i][0]][slate[i][1]].sub(PVector.mult(
                                                      dx,delta));
                  }
                }
              }
            }
          }
        }
      }
    }
    boolean testAdjacency(int i,int j){
      int a = slate[i][0];
      int b = slate[i][1];
      int c = slate[j][0];
      int d = slate[j][1];
      boolean val = false;
      if (((abs(a-c)<2)&&(abs(b-d)<2))==false){
        val = true;
      }
      return val;
    }
    
    void reset(){
      for (int i=0; i<numa; i++){
        for (int j=0; j<numb; j++){
          X[i][j] = new PVector(elementWidth * (i)+width/8,
                                elementWidth * (j)+height/8,
                                random(-0.1,0.1));
          V[i][j] = new PVector();
        }
      }
    }
    void physics(){
      for (int i=0; i<numa; i++){
        for (int j=0; j<numb; j++){
          F[i][j] = new PVector(0.0,gravity,0.0);
        }
      }
      for (int i=0; i<numa; i++){
        for (int j=0; j<numb; j++){
          normalForce(i,j);
          windForce(i,j);
        }
      }
      collide();
      for (int i=0; i<numa; i++){
        for (int j=0; j<numb; j++){
          V[i][j].add(F[i][j]);
          X[i][j].add(V[i][j]);
        }
      }
      useConstraint();
    }
    void drawSheet(){
      noStroke();
      for (int j=0; j<numb-1; j++){
        beginShape(TRIANGLE_STRIP);
        texture(flag);
        float xtweek = 1.02;
        float ytweek = 1.05;
        for (int i=0; i<numa; i++){
          vertex(X[i][j].x, X[i][j].y, X[i][j].z,
                 elementWidth*i*xtweek, elementWidth*j*ytweek);
          vertex(X[i][j+1].x, X[i][j+1].y, X[i][j+1].z,
                 elementWidth*i*xtweek, elementWidth*(j+1)*ytweek);      
        }
        endShape();
      }
    }
    void setupConstraint(){
      for (int j=0; j<numb; j++){
        constraint[j] = new PVector(X[0][j].x,
                                    X[0][j].y,
                                    X[0][j].z);
      }
    }
    void useConstraint(){
      for (int j=0; j<numb; j++){
        X[0][j] = new PVector(constraint[j].x,
                              constraint[j].y,
                              constraint[j].z);
        V[0][j] = new PVector();
      }
    }
    
    void normalForce(int i, int j){
      int a = i+1;
      int b = j;
      force2(i,j,a,b,1);
      a = i-1;
      b = j;
      force2(i,j,a,b,1);
      a = i;
      b = j+1;
      force2(i,j,a,b,1);
      a = i;
      b = j-1;
      force2(i,j,a,b,1);
      a = i+1;
      b = j+1;
      force2(i,j,a,b,pow(2,0.5));
      a = i-1;
      b = j+1;
      force2(i,j,a,b,pow(2,0.5));
      a = i+1;
      b = j-1;
      force2(i,j,a,b,pow(2,0.5));
      a = i-1;
      b = j-1;
      force2(i,j,a,b,pow(2,0.5));
      boolean jump = true;
      if (jump == true){
        int jumper = 2;
        a = i+jumper;
        b = j;
        force2(i,j,a,b,jumper);
        a = i-jumper;
        b = j;
        force2(i,j,a,b,jumper);
        a = i;
        b = j+jumper;
        force2(i,j,a,b,jumper);
        a = i;
        b = j-jumper;
        force2(i,j,a,b,jumper);
        a = i+jumper;
        b = j+jumper;
        force2(i,j,a,b,jumper*pow(2,0.5));
        a = i-jumper;
        b = j+jumper;
        force2(i,j,a,b,jumper*pow(2,0.5));
        a = i+jumper;
        b = j-jumper;
        force2(i,j,a,b,jumper*pow(2,0.5));
        a = i-jumper;
        b = j-jumper;
        force2(i,j,a,b,jumper*pow(2,0.5));
      }
    }
    void force2(int i,int j,int a,int b,float distMult){
      float eW2 = elementWidth * distMult;
      if ((a>=0)&&(b>=0)&&(a<numa)&&(b<numb)){
        PVector dx = PVector.sub(X[a][b], X[i][j]);
        float bufferWidth = 0.01 * elementWidth;
        float delta = 0;
        if ((dx.mag() < eW2 - bufferWidth/2)||
            (dx.mag() > eW2 + bufferWidth/2)){
          delta = abs(dx.mag() - eW2)
                       - bufferWidth/2;
        }
        int sighn = 0;
        if (dx.mag() < eW2 - bufferWidth/2){
          sighn = -1;
        }else if (dx.mag() > eW2 + bufferWidth/2){
          sighn = +1;
        }
        dx.normalize();
        float v1 = dx.dot(V[i][j]);
        float v2 = dx.dot(V[a][b]);
        float dv = v2 - v1;
        float fmag = k * delta * sighn + c * dv;
        PVector df = PVector.mult(dx,fmag);
        F[i][j].add(df);
        F[a][b].sub(df);
      }
    }
    
    void windForce(int i,int j){
      // NOTE: vector selected based on right hand rule
      int a = i+1;
      int b = j;
      int c = i;
      int d = j+1;
      wind2(i,j,a,b,c,d);
      a = i;
      b = j+1;
      c = i-1;
      d = j;
      wind2(i,j,a,b,c,d);
      a = i-1;
      b = j;
      c = i;
      d = j-1;
      wind2(i,j,a,b,c,d);
      a = i;
      b = j-1;
      c = i+1;
      d = j;
      wind2(i,j,a,b,c,d);
    }
    void wind2(int i,int j,int a,int b,int c,int d){
      PVector windV = new PVector(wind,0.0,0.0);
      if ((a>=0)&&(b>=0)&&(a<numa)&&(b<numb)){
        if ((c>=0)&&(d>=0)&&(c<numa)&&(d<numb)){
          PVector ab = PVector.sub(X[a][b], X[i][j]);
          PVector cd = PVector.sub(X[c][d], X[i][j]);
          PVector un = ab.cross(cd);
          un.normalize();
          float fmag = un.dot(windV);
          F[i][j].add(PVector.mult(un,fmag));
        }
      }
    }
    

    code

    tweaks (0)

    about this sketch

    This sketch is running as Java applet, exported from Processing.

    license

    advertisement

    Asher Salomon
    bejoscha
    6 Apr 2010
    Nice. Thanks for sharing.
    Axel Duch
    19 Aug 2010
    This is... flagberghasting.
    Where are you from? If you don't mind me asking...
    Jean Gilbert
    21 Feb 2014
    Hi Asher,
    I adapted your sketch for an interactive video about the history of Karlsruhe town and hope you like it.
    Find out the credits on
    http://www.jean-gilbert.com/#!karlsruhe-1715---2015/ccjr
    and leave a message, if you want.
    Best Regards
    Jean Gilbert
    You need to login/register to comment.