Created
November 28, 2012 19:42
-
-
Save lizkhoo/4163577 to your computer and use it in GitHub Desktop.
Feather Wall
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
}*/ | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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