Spoon-Body

https://youtu.be/H_0f3B_2JLY

This project ended up being more of an exploration of motion than an art piece. The goal was to take a motion capture skeleton and have it interact with some physics objects -- like springs and particles -- to produce an interesting piece. I achieved about half of that. Using the physics engine found in the Toxiclibs library in Processing, I attached a series of short springs and particles (which look like yellow strings in the video) to various points of the body. When the person moves, the springs move around and respond, accentuating the person's movement.

The affectation on the motion definitely came first. To be honest, the skeleton used in the piece was almost an afterthought. If I had left myself more time, I would have liked to get some motion capture footage of someone doing quick motions that cover a lot of space. This would have likely made the springs move all over the place and produce interesting paths and curves as the person moved.

 

 

import toxi.geom.*;
import toxi.geom.mesh.*;
import toxi.geom.mesh.subdiv.*;
import toxi.geom.mesh2d.*;
import toxi.geom.nurbs.*;
import toxi.physics3d.*;
import toxi.physics3d.behaviors.*;
import toxi.physics3d.constraints.*;
 
public class PBvh
{
  public BvhParser parser;  
 
  private ArrayList controlPoints;
  private ArrayList trailingPoints;
  private Particle finalPoint;
  private ArrayList springs;
  private VerletPhysics3D physics;
 
  private float w = 10;
 
  public PBvh(String[] data) {
    parser = new BvhParser();
    parser.init();
    parser.parse( data );
  }
 
  public void update( int ms ) {
    parser.moveMsTo( ms );//30-sec loop 
    parser.update();
  }
 
  public void setup() {
    controlPoints = new ArrayList();
    trailingPoints = new ArrayList();
    springs = new ArrayList();
    physics = new VerletPhysics3D();
    Vec3D gravity = new Vec3D(0, -10, 0);
    GravityBehavior3D gb = new GravityBehavior3D(gravity);
    physics.addBehavior(gb);
 
    finalPoint = new Particle(0, 0, 0);
 
    for( BvhBone b : parser.getBones())
    {
      if (true/*!b.hasChildren()*/)
      {
        Particle p1;
        ArrayList p2;
        p1 = new Particle(b.absEndPos.x, 
                          b.absEndPos.y, 
                          b.absEndPos.z);
        p2 = new ArrayList();
 
        for(int i = 0; i < 10; i++) {
          Particle p = new Particle(b.absPos.x, 
                                    b.absPos.y, 
                                    b.absPos.z);
          p2.add(p);
        }
 
        p1.lock();
        ArrayList armSprings;
        armSprings = new ArrayList();//new VerletSpring3D(p1, p2.get(0), 5, 0.05);
        armSprings.add(new VerletSpring3D(p1,
                                          p2.get(0),
                                          1,
                                          0.1));
        for(int i = 1; i < 10; i++) {
          VerletSpring3D s = new VerletSpring3D(p2.get(i - 1),
                                                p2.get(i),
                                                1,
                                                0.1);
          armSprings.add(s);
        }
        armSprings.add(new VerletSpring3D(armSprings.get(armSprings.size() - 1)
                                          finalPoint,
                                          1
                                          0.1)
        controlPoints.add(p1);
        physics.addParticle(p1);
        for(Particle p : p2) {
          trailingPoints.add(p);
          physics.addParticle(p);
        }
        for(VerletSpring3D spring : armSprings) {
          springs.add(spring); 
          physics.addSpring(spring);
        }
      } 
    }
  }
 
  public void draw() {
    fill(color(255));
    int counter = 0;
    for( BvhBone b : parser.getBones())
    {
      pushMatrix();
      translate(b.absPos.x, b.absPos.y, b.absPos.z);
      ellipse(0, 0, 2, 2);
      popMatrix();
 
      Particle p1 = controlPoints.get(counter);
      p1.x = b.absPos.x;
      p1.y = b.absPos.y;
      p1.z = b.absPos.z;
      counter++;
 
      if (!b.hasChildren())
      {
        pushMatrix();
        translate(b.absEndPos.x, b.absEndPos.y, b.absEndPos.z);
        println("xbody = ", b.absEndPos.x);
        println("ybody = ", b.absEndPos.y);
        println("zbody = ", b.absEndPos.z);
        ellipse(0, 0, 10, 10);
        popMatrix();  
 
        /*Particle p1 = controlPoints.get(counter);
        p1.x = b.absEndPos.x;
        p1.y = b.absEndPos.y;
        p1.z = b.absEndPos.z;
        counter++;*/
      }
 
    }
 
    physics.update();
    counter = 0;
    /*for(Particle p1 : controlPoints) {
      counter++;
      int bvhCounter = 0;
      for( BvhBone b : parser.getBones()) {
        if(!b.hasChildren()) {
          bvhCounter++;
        }
        if(bvhCounter == counter) {
          p1.lock();
          p1.x = b.absEndPos.x;
          p1.y = b.absEndPos.y;
          p1.z = b.absEndPos.z;
 
          println("xpoint = ", p1.x);
          println("ypoint = ", p1.y);
          println("zpoint = ", p1.z);
        }
      }
    }*/
 
    /*for(Particle p2 : trailingPoints) {
      p2.display();
    }*/
    for(VerletSpring3D spring : springs) {
      Particle p1 = (Particle) spring.a;
      Particle p2 = (Particle) spring.b;
 
      p1.display(2);
      p2.display(2);
 
      float x1 = p1.x;
      float y1 = p1.y;
      float z1 = p1.z;
 
      float x2 = p2.x;
      float y2 = p2.y;
      float z2 = p2.z;
 
      stroke(255, 198, 0);
      line(x1, y1, z1, x2, y2, z2);
    }
  }
}
// Originally from http://perfume-dev.github.io/
 
BvhParser parserA = new BvhParser();
PBvh /*bvh1,*/ /*bvh2,*/ bvh3;
 
public void setup()
{
  size( 1280, 720, P3D );
  background( 0 );
  noStroke();
  frameRate( 30 );
 
//  bvh1 = new PBvh( loadStrings( "A_test.bvh" ) );
//  bvh2 = new PBvh( loadStrings( "B_test.bvh" ) );
  bvh3 = new PBvh( loadStrings( "C_test.bvh" ) );
 
//  bvh1.update(0);
//  bvh2.update(0);
  bvh3.update(0);
 
//  bvh1.setup();
//  bvh2.setup();
  bvh3.setup();
 
  loop();
}
 
public void draw()
{
  background( 0 );
 
  //camera
  float _cos = cos(millis() / 7000.f);
  float _sin = sin(millis() / 5000.f);
  camera(width/8.f + width/8.f /** _sin +200*/, height/2.0f-100, 550 + 150/* * _cos*/, width/2.0f + 400, height/2.0f, -400, 0, 1, 0);
 
  //ground 
  /*fill( color( 255 ));
  stroke(127);
  line(width/2.0f, height/2.0f, -30, width/2.0f, height/2.0f, 30);
  stroke(127);
  line(width/2.0f-30, height/2.0f, 0, width/2.0f + 30, height/2.0f, 0);
  */stroke(255);
 
  pushMatrix();
  translate( width/2, height/2-10, 0);
  scale(-1, -1, -1);
 
  //model
//  bvh1.update( millis() );
//  bvh2.update( millis() );
  bvh3.update( millis() );
 
//  bvh1.draw();
//  bvh2.draw();
  bvh3.draw();
 
  popMatrix();
}
class Particle extends VerletParticle3D {
  Particle(float x, float y, float z) {
    super(x, y, z);
  }

void display(int n) {
pushMatrix();
translate(x, y, z);
//ellipse(0, 0, n, n);
popMatrix();
}
}