Skip to content

Instantly share code, notes, and snippets.

@lizkhoo
Created November 28, 2012 19:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lizkhoo/4163577 to your computer and use it in GitHub Desktop.
Save lizkhoo/4163577 to your computer and use it in GitHub Desktop.
Feather Wall
class Feather {
PVector loc;
PVector velo;
PVector accel;
float lifespan;
PImage img;
float t, a;
Feather(PVector l, PImage img_) {
accel = new PVector(0, 0.01);
//nextGaussian is a built-in method in Java
//to generate random numbers with normal distro
float vx = (float) generator.nextGaussian()*0.85;
float vy = (float) generator.nextGaussian();
//println(vx+", "+vy);
if (vy <= 0) {
vy = -vy;
}
velo = new PVector(vx, vy);
loc = l.get();
lifespan = 255.0;
img = img_;
a = 0;
t = 0;
}
void run() {
move();
display();
}
//display objects
void display() {
imageMode(CENTER);
tint(255, lifespan);
pushMatrix();
translate(loc.x, loc.y);
rotate(a/10);
image(img, 0, 0, 25, 12);
popMatrix();
}
//update object location
void move() {
update();
velo.add(accel);
loc.add(velo);
accel.mult(0);
lifespan -= 0.10;
if (loc.y >= height-310) {
velo.mult(0);
accel.mult(0);
lifespan -= 1.0;
}
}
void update() {
//creates back and forth movement
t+=.08;
a = 5*noise(t*0.5)*cos(t);
accel = new PVector(a, 0);
accel.mult(.01);
//reset feathers at top
if (lifespan <= 10.0) {
loc.x = width/4;
loc.y = 0;
lifespan = 255.0;
accel.mult(0);
float vx = (float) generator.nextGaussian()*0.85;
float vy = (float) generator.nextGaussian();
if (vy <= 0) {
vy = -vy;
}
velo = new PVector(vx, vy);
}
}
//apply force vector to object
void applyForce(PVector f) {
accel.add(f);
}
}
//Based on particle system code by Daniel Schiffman,
//and Kinect with blob detection code by Amnon Owed
// import libraries
import processing.opengl.*; // opengl
import SimpleOpenNI.*; // kinect
import blobDetection.*; // blobs
import toxi.geom.*; // toxiclibs shapes and vectors
import toxi.processing.*; // toxiclibs display
import pbox2d.*; // shiffman's jbox2d helper library
import org.jbox2d.collision.shapes.*; // jbox2d
import org.jbox2d.common.*; // jbox2d
import org.jbox2d.dynamics.*; // jbox2d
// declare SimpleOpenNI object
SimpleOpenNI context;
// declare BlobDetection object
BlobDetection theBlobDetection;
// ToxiclibsSupport for displaying polygons
ToxiclibsSupport gfx;
// declare custom PolygonBlob object (see class for more info)
PolygonBlob poly;
// PImage to hold incoming imagery and smaller one for blob detection
PImage cam, blobs;
// the kinect's dimensions to be used later on for calculations
int kinectWidth = 640;
int kinectHeight = 480;
// to center and rescale from 640x480 to higher custom resolutions
float reScale;
// the main PBox2D object in which all the physics-based stuff is happening
PBox2D box2d;
FeatherSystem fs;
Random generator;
void setup() {
size (1280, 720, OPENGL);
context = new SimpleOpenNI(this);
if (!context.enableScene()) {
// if context.enableScene() returns false
// then the Kinect is not working correctly
// make sure the green light is blinking
println("Kinect not connected!");
exit();
} else {
// mirror the image to be more intuitive
context.setMirror(true);
// calculate the reScale value
// currently it's rescaled to fill the complete width (cuts of top-bottom)
// it's also possible to fill the complete height (leaves empty sides)
reScale = (float) width / kinectWidth;
// create a smaller blob image for speed and efficiency
blobs = createImage(kinectWidth/3, kinectHeight/3, RGB);
// initialize blob detection object to the blob image dimensions
theBlobDetection = new BlobDetection(blobs.width, blobs.height);
theBlobDetection.setThreshold(0.2);
// initialize ToxiclibsSupport object
gfx = new ToxiclibsSupport(this);
// setup box2d, create world, set gravity
box2d = new PBox2D(this);
box2d.createWorld();
box2d.setGravity(0, -20);
}
generator = new Random();
PImage fpic = loadImage("feather-clean.png");
//initialize system (pvector, pimg)
fs = new FeatherSystem(new PVector(width/4, 0), fpic);
smooth();
}
void draw() {
background(0);
// update the SimpleOpenNI object
context.update();
// put the image into a PImage
cam = context.sceneImage().get();
// copy the image into the smaller blob image
blobs.copy(cam, 0, 0, cam.width, cam.height, 0, 0, blobs.width, blobs.height);
// blur the blob image
blobs.filter(BLUR, 1);
// detect the blobs
theBlobDetection.computeBlobs(blobs.pixels);
// initialize a new polygon
poly = new PolygonBlob();
// create the polygon from the blobs (custom functionality, see class)
poly.createPolygon();
// create the box2d body from the polygon
poly.createBody();
//set wind force
/*float dx = 0.02; //this will include Kinect input later
PVector wind = new PVector(dx, 0); //stores our wind coordinates
fs.applyForce(wind);*/
updateAndDrawBox2D();
// destroy the person's body (important!)
poly.destroyBody();
}
void updateAndDrawBox2D() {
/* if frameRate is sufficient, add a polygon and a circle with a random radius
if (frameRate > 29) {
polygons.add(new CustomShape(kinectWidth/2, -50, -1));
polygons.add(new CustomShape(kinectWidth/2, -50, random(2.5, 20)));
}*/
// take one step in the box2d physics world
box2d.step();
// center and reScale from Kinect to custom dimensions
translate(0, (height-kinectHeight*reScale)/2);
scale(reScale);
// display the person's polygon
stroke(255);
fill(0);
gfx.polygon2D(poly);
// display all the feathers
float g = 0.8;
PVector gravity = new PVector(0,g);
fs.applyForce(gravity);
fs.run();
}
class FeatherSystem {
ArrayList<Feather> fArrayList; //arraylist for feathers
PVector origin; //origin point for feather birth
PImage img;
FeatherSystem(PVector v, PImage img_) {
fArrayList = new ArrayList<Feather>(); //initialize arraylist
origin = v.get(); //store origin as point v
img = img_;
}
void addFeather() {
fArrayList.add(new Feather(origin, img));
}
void run() {
//Iterator is a built-in Java class
Iterator<Feather> it = fArrayList.iterator();
//hasNext is a function of iterator, tells us if there is a class Feather to run
while (it.hasNext ()) {
//next is a function that grabs the object "f" from class Feather
Feather f = it.next();
f.run();
}
if (fArrayList.size() < 100) {
addFeather();
}
}
//Apply force vector to all objects in system
void applyForce(PVector dir) {
//Enhanced loop goes through all
for (Feather f:fArrayList) {
f.applyForce(dir);
}
}
/*void addFeather(Feather f) {
fArrayList.add(f);
}
// A method to test if the particle system still has particles
boolean dead() {
if (fArrayList.isEmpty()) {
return true;
}
else {
return false;
}
}*/
}
// Kinect Physics Example by Amnon Owed (15/09/12)
// an extended polygon class quite similar to the earlier PolygonBlob class (but extending Toxiclibs' Polygon2D class instead)
// The main difference is that this one is able to create (and destroy) a box2d body from it's own shape
class PolygonBlob extends Polygon2D {
// to hold the box2d body
Body body;
// the createPolygon() method is nearly identical to the one presented earlier
// see the Kinect Flow Example for a more detailed description of this method
void createPolygon() {
ArrayList<ArrayList<PVector>> contours = new ArrayList<ArrayList<PVector>>();
int selectedContour = 0;
int selectedPoint = 0;
// create contours from blobs
for (int n=0 ; n<theBlobDetection.getBlobNb(); n++) {
Blob b = theBlobDetection.getBlob(n);
if (b != null && b.getEdgeNb() > 100) {
ArrayList<PVector> contour = new ArrayList<PVector>();
for (int m=0; m<b.getEdgeNb(); m++) {
EdgeVertex eA = b.getEdgeVertexA(m);
EdgeVertex eB = b.getEdgeVertexB(m);
if (eA != null && eB != null) {
EdgeVertex fn = b.getEdgeVertexA((m+1) % b.getEdgeNb());
EdgeVertex fp = b.getEdgeVertexA((max(0, m-1)));
float dn = dist(eA.x*kinectWidth, eA.y*kinectHeight, fn.x*kinectWidth, fn.y*kinectHeight);
float dp = dist(eA.x*kinectWidth, eA.y*kinectHeight, fp.x*kinectWidth, fp.y*kinectHeight);
if (dn > 15 || dp > 15) {
if (contour.size() > 0) {
contour.add(new PVector(eB.x*kinectWidth, eB.y*kinectHeight));
contours.add(contour);
contour = new ArrayList<PVector>();
} else {
contour.add(new PVector(eA.x*kinectWidth, eA.y*kinectHeight));
}
} else {
contour.add(new PVector(eA.x*kinectWidth, eA.y*kinectHeight));
}
}
}
}
}
while (contours.size() > 0) {
// find next contour
float distance = 999999999;
if (getNumPoints() > 0) {
Vec2D vecLastPoint = vertices.get(getNumPoints()-1);
PVector lastPoint = new PVector(vecLastPoint.x, vecLastPoint.y);
for (int i=0; i<contours.size(); i++) {
ArrayList<PVector> c = contours.get(i);
PVector fp = c.get(0);
PVector lp = c.get(c.size()-1);
if (fp.dist(lastPoint) < distance) {
distance = fp.dist(lastPoint);
selectedContour = i;
selectedPoint = 0;
}
if (lp.dist(lastPoint) < distance) {
distance = lp.dist(lastPoint);
selectedContour = i;
selectedPoint = 1;
}
}
} else {
PVector closestPoint = new PVector(width, height);
for (int i=0; i<contours.size(); i++) {
ArrayList<PVector> c = contours.get(i);
PVector fp = c.get(0);
PVector lp = c.get(c.size()-1);
if (fp.y > kinectHeight-5 && fp.x < closestPoint.x) {
closestPoint = fp;
selectedContour = i;
selectedPoint = 0;
}
if (lp.y > kinectHeight-5 && lp.x < closestPoint.y) {
closestPoint = lp;
selectedContour = i;
selectedPoint = 1;
}
}
}
// add contour to polygon
ArrayList<PVector> contour = contours.get(selectedContour);
if (selectedPoint > 0) { Collections.reverse(contour); }
for (PVector p : contour) {
add(new Vec2D(p.x, p.y));
}
contours.remove(selectedContour);
}
}
// creates a shape-deflecting physics chain in the box2d world from this polygon
void createBody() {
// for stability the body is always created (and later destroyed)
BodyDef bd = new BodyDef();
body = box2d.createBody(bd);
// if there are more than 0 points (aka a person on screen)...
if (getNumPoints() > 0) {
// create a vec2d array of vertices in box2d world coordinates from this polygon
Vec2[] verts = new Vec2[getNumPoints()];
for (int i=0; i<getNumPoints(); i++) {
Vec2D v = vertices.get(i);
verts[i] = box2d.coordPixelsToWorld(v.x, v.y);
}
// create a chain from the array of vertices
ChainShape chain = new ChainShape();
chain.createChain(verts, verts.length);
// create fixture in body from the chain (this makes it actually deflect other shapes)
body.createFixture(chain, 1);
}
}
// destroy the box2d body (important!)
void destroyBody() {
box2d.destroyBody(body);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment