Idle:
Blinking:
Mouth open:
My first idea (scratched):
Idea that I pursued:
Starting off this project, I was debating between two ideas. One where I would play around with rotations, and the other where I would manipulate the eyes depending on the facial expression. (especially the mouth) I decided that I would like to express emotions creatively, so I decided to pursue that. At first, I wanted the face to express sadness by crying whenever the mouth opened and the eyebrows were furrowed, but I had some issues with creating the tears to be more fluid-like, so it kind of just looked like a scary person shooting out spherical beams. I got some new ideas with that mistake; and I thought it would be cool for the person to transform into an evil medusa with red pupils when you made a scary face. Also, I ended up removing the mouth entirely because the focus was in the eyes. Aesthetically speaking, I wish I played around with the eyes' outlines more because I think it's quite distracting especially since none of the other shapes have an outline. I also wish I could diversify the eyes' shapes to make it more evil-looking and scary. (possibly?) Functionally, I wish the eyes would have shot out beams rather than circles or better conveyed the user being frozen by her stone-turning eye beams. In terms of the relationship between the facial motions and the treatment of it, I would say that the motions came first and I only adapted to the possibilities of those motions.
// // a template for receiving face tracking osc messages from // Kyle McDonald's FaceOSC https://github.com/kylemcdonald/ofxFaceTracker // // 2012 Dan Wilcox danomatika.com // for the IACD Spring 2012 class at the CMU School of Art // // adapted from from Greg Borenstein's 2011 example // http://www.gregborenstein.com/ // https://gist.github.com/1603230 // import oscP5.*; OscP5 oscP5; //I used Dan Shiffman's box2d adaptation: https://github.com/shiffman/Box2D-for-Processing import shiffman.box2d.*; import org.jbox2d.collision.shapes.*; import org.jbox2d.common.*; import org.jbox2d.dynamics.*; import org.jbox2d.dynamics.joints.*; Box2DProcessing box2d; ArrayList<Boundary> boundaries; ArrayList<ParticleSystem> systems; ArrayList<Box> boxes; // num faces found int found; // pose float poseScale; PVector posePosition = new PVector(); PVector poseOrientation = new PVector(); // gesture float mouthHeight; float mouthWidth; float eyeLeft; float eyeRight; float eyebrowLeft; float eyebrowRight; float jaw; float nostrils; PImage outerEye; float aVelocity = .05; boolean mouseVelocity = false; float angle = 0; float amplitudeX = 200; float amplitudeY = 200; float theta = 0; PVector location; float centerX; float centerY; void setup() { size(640, 480); frameRate(30); smooth(); box2d = new Box2DProcessing(this); box2d.createWorld(); box2d.setGravity(0, -20); systems = new ArrayList<ParticleSystem>(); boundaries = new ArrayList<Boundary>(); boxes = new ArrayList<Box>(); oscP5 = new OscP5(this, 8338); oscP5.plug(this, "found", "/found"); oscP5.plug(this, "poseScale", "/pose/scale"); oscP5.plug(this, "posePosition", "/pose/position"); oscP5.plug(this, "poseOrientation", "/pose/orientation"); oscP5.plug(this, "mouthWidthReceived", "/gesture/mouth/width"); oscP5.plug(this, "mouthHeightReceived", "/gesture/mouth/height"); oscP5.plug(this, "eyeLeftReceived", "/gesture/eye/left"); oscP5.plug(this, "eyeRightReceived", "/gesture/eye/right"); oscP5.plug(this, "eyebrowLeftReceived", "/gesture/eyebrow/left"); oscP5.plug(this, "eyebrowRightReceived", "/gesture/eyebrow/right"); oscP5.plug(this, "jawReceived", "/gesture/jaw"); oscP5.plug(this, "nostrilsReceived", "/gesture/nostrils"); outerEye = loadImage("circlebig.png"); //boundaries.add(new Boundary(0,490,1280,10,0)); } void draw() { semiTransparent(); box2d.step(); for (ParticleSystem system: systems) { system.run(); int n = (int) random(0, 2); system.addParticles(n); } for (Boundary wall: boundaries) { wall.display(); } float varVelocity = calcVelocity(aVelocity); PVector angularVelocity = new PVector (angle, varVelocity); PVector amplitude = new PVector (amplitudeX, amplitudeY); PVector location = calculateCircle(angularVelocity, amplitude); //PVector centerCircle = calculateCenter(centerX, centerY); pushMatrix(); if(found > 0) { drawOscillatingX(location); } popMatrix(); for (Box b: boxes) { b.display(); } } void semiTransparent() { rectMode(CORNER); noStroke(); float backColor = map (mouthHeight, 1, 5, 255, 0); fill(backColor, backColor, backColor, 40); rect(0,0, width, height); stroke(0); noFill(); } //basics of eye blink, iris movement from: https://raw.githubusercontent.com/jayjaycody/ComputationalCameras/master/wk3_Face/jai_face_keyPressComplexity/jai_face_keyPressComplexity.pde float calcVelocity(float aVelocity) { float velocity = aVelocity; if (mouseVelocity == false) { } if (mouseVelocity == true) { velocity = map(mouseX, 0, width, -1, 1); } return velocity; } PVector calculateCircle (PVector angularVelocity, PVector amplitude) { float x = amplitude.x * cos (theta); float y = amplitude.y * sin (theta); location = new PVector (x, y); theta += angularVelocity.y; return location; } PVector calculateCenter (float centerX, float centerY) { PVector centerCircle = new PVector (centerX, centerY); return centerCircle; } void drawOscillatingX (PVector location) { float mouthScalar = map(mouthWidth, 10, 18, 0, 1.5); // make a scalar for location.x as a function of mouth location.mult(mouthScalar); float newPosX = map (posePosition.x, 0, 640, 0, width); float newPosY = map(posePosition.y, 0, 480, 0, height); translate(width - newPosX, newPosY-100); scale(poseScale*.3); float irisColR = map (mouthHeight, 1, 5, 102, 204); float irisColG = map (mouthHeight, 1, 5, 204, 51); float irisColB = map (mouthHeight, 1, 5, 255, 0); float leftEyeMove = map(location.x, - amplitudeX, amplitudeX, -25, 33); pushMatrix(); translate (leftEyeMove, 0); //Left iris fill(irisColR, irisColG, irisColB); noStroke(); float eyeMult = map (mouthHeight, 1, 5, 1, 2); float irisSizeL = map (eyeLeft, 2, 3.5, 0, 50); ellipse(-100, 0, irisSizeL * eyeMult, irisSizeL * eyeMult); ////LeftPupil float eyeOutlineCol = map (mouthHeight, 1, 5, 0, 255); popMatrix(); float rightEyeMove = map(location.x, - amplitudeX, amplitudeX, -33, 25); pushMatrix(); translate(rightEyeMove, 0); //right EYE //Right Iris fill(irisColR, irisColG, irisColB); noStroke(); float irisSizeR = map (eyeRight, 2, 3.5, 0, 50); ellipse(100, 0, irisSizeR * eyeMult, irisSizeR * eyeMult); //Right Pupil stroke(eyeOutlineCol); popMatrix(); noFill(); //get eye informatio and set scalar float blinkAmountRight = map (eyeRight, 2.5, 3.8, 0, 125); float blinkAmountLeft = map (eyeLeft, 2.5, 3.8, 0, 125); float eyeMultiplier = map (mouthHeight, 1, 5, 1, 3); // right eye size, blink and movement ellipse (100, 0, amplitudeX *.6, blinkAmountRight * eyeMultiplier); //scalar added to eyeHeight if (eyeRight < 2.7) { fill(255, 230, 204); ellipse (100, 0, amplitudeX *.6, blinkAmountRight*1.6 * (4 * eyeMultiplier/5)); //scalar added to eyeHeight noFill(); } //left eye size, blink, and movement ellipse (-100, 0, amplitudeX *.6, blinkAmountLeft * eyeMultiplier); if (eyeLeft < 2.7) { fill(255, 230, 204); ellipse (-100, 0, amplitudeX *.6, blinkAmountLeft*1.6 * (4 * eyeMultiplier/5)); //scalar added to eyeHeight noFill(); } if (mouthHeight > 3.3) { //float mapScale = map (poseScale, 0, 4, 0, 1); pushMatrix(); //translate(posePosition.x, posePosition.y); //scale(poseScale); Box p = new Box((width - posePosition.x - 100), (posePosition.y - 50)); Box q = new Box((width - posePosition.x + 100), (posePosition.y - 50)); boxes.add(p); boxes.add(q); popMatrix(); } } public void found(int i) { println("found: " + i); found = i; } public void poseScale(float s) { println("scale: " + s); poseScale = s; } public void posePosition(float x, float y) { println("pose position\tX: " + x + " Y: " + y ); posePosition.set(x, y, 0); } public void poseOrientation(float x, float y, float z) { println("pose orientation\tX: " + x + " Y: " + y + " Z: " + z); poseOrientation.set(x, y, z); } public void mouthWidthReceived(float w) { println("mouth Width: " + w); mouthWidth = w; } public void mouthHeightReceived(float h) { println("mouth height: " + h); mouthHeight = h; } public void eyeLeftReceived(float f) { println("eye left: " + f); eyeLeft = f; } public void eyeRightReceived(float f) { println("eye right: " + f); eyeRight = f; } public void eyebrowLeftReceived(float f) { println("eyebrow left: " + f); eyebrowLeft = f; } public void eyebrowRightReceived(float f) { println("eyebrow right: " + f); eyebrowRight = f; } public void jawReceived(float f) { println("jaw: " + f); jaw = f; } public void nostrilsReceived(float f) { println("nostrils: " + f); nostrils = f; } // all other OSC messages end up here void oscEvent(OscMessage m) { if(m.isPlugged() == false) { println("UNPLUGGED: " + m); } } |