word vomit.
this began as a concept where moving elements of your face would cause marks of this motion to appear, without actually showing your face back. This eventual evolved into leaving falling characters in this style. In the end, It seemed more natural to have words pouring from your mouth. The face I used is heavily inspired by my previous face projects. I enjoy serious faces that wobble.
the face’s primary control is how open the mouth is, which dictates rate of word pour, thickness of lines, and amour of wobble. the rest of the facial properties are used to handle the rendering of the face in 3D space.
The last part of this may or may not be lines from Blue Swede’s Hooked on a Feeling.
import oscP5.*;
OscP5 oscP5;
//class that handles the falling letters
class Letter {
char c;
int x;
int y;
float scale;
float speed;
Letter(char tempc, int tempx, int tempy, float tempscale){
c = tempc;
x = tempx;
y = tempy;
scale = tempscale;
speed = 0.0;
}
void update(){
speed = speed + 0.5;
y += int(speed*scale);
}
void display(){
textSize(25*scale);
fill(map(mouthHeight,0,7,100,0));
text(c,x,y,0);
}
Boolean finished(){
return y >= height + 20;
}
}
String words;
int textLen;
int textInd;
int spaceInd;
ArrayList<Letter> letters;
// 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;
void setup() {
textMode(SHAPE);
size(640, 480, OPENGL);
frameRate(30);
//chars are selected in order from this text. Lorem Ipsum
//because I am too lazy
words="Lorem ipsum dolor sit amet, consectetur adipisicing elit,"
+" sed do eiusmod tempor incididunt ut labore et dolore "
+"magna aliqua. Ut enim ad minim veniam, quis nostrud "
+"exercitation ullamco laboris nisi ut aliquip ex ea commodo"
+" consequat. Duis aute irure dolor in reprehenderit in "
+"voluptate velit esse cillum dolore eu fugiat nulla "
+"pariatur. Excepteur sint occaecat cupidatat non proident, "
+"sunt in culpa qui officia deserunt mollit anim id est "
+"laborum.";
textLen = words.length();
textInd = 0;
spaceInd = 0;
letters = new ArrayList<Letter>();
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");
}
void draw() {
//face drawing
background(255);
stroke(0);
float nscale = poseScale/3.0;
noFill();
pushMatrix();
translate (posePosition.x, posePosition.y, 0);
scale(nscale);
rotateY (0 - poseOrientation.y);
rotateX (0 - poseOrientation.x);
rotateZ ( poseOrientation.z);
int r1 = int(random(-1*mouthHeight, mouthHeight)/1.4);
int r2 = int(random(-1*mouthHeight, mouthHeight)/1.4);
int r3 = int(random(-1*mouthHeight, mouthHeight)/1.4);
line(-40 + r1, eyeLeft * -9, -5, -10 + r1, eyeLeft * -9,0);
line(40 + r1, eyeRight * -9, -5, 10 + r1, eyeRight * -9,0);
line(-50 + r2, eyebrowLeft * -5, -5, -8 + r2, eyebrowLeft * -5,0);
line(50 + r2, eyebrowRight * -5, -5, 8 + r2, eyebrowRight * -5,0);
line(-5 + r3,nostrils * 1,0,5 + r3,nostrils*1,0);
strokeWeight(mouthHeight);
line(-mouthWidth + r3,45,0,mouthWidth + r3,45,0);
popMatrix();
println("mWidth: " + mouthWidth + ", mHeight: " + mouthHeight);
//generates new falling letters
for(int i = 0; i < int(mouthHeight/1.4); i++){
if (spaceInd % 2 == 0){
letters.add(new Letter(words.charAt(textInd),
int(posePosition.x + random(-2*mouthWidth - mouthHeight,
2*mouthWidth + mouthHeight)),
int(posePosition.y + 65), nscale));
textInd = (textInd + 1) % textLen;
}
spaceInd++;
}
//updates and displays letters
for (int i = letters.size()-1; i >= 0; i--) {
Letter letter = letters.get(i);
letter.update();
letter.display();
if (letter.finished()) {
letters.remove(i);
}
}
}
// OSC CALLBACK FUNCTIONS
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) {
/* print the address pattern and the typetag of the received OscMessage */
println("#received an osc message");
println("Complete message: "+m);
println(" addrpattern: "+m.addrPattern());
println(" typetag: "+m.typetag());
println(" arguments: "+m.arguments()[0].toString());
if(m.isPlugged() == false) {
println("UNPLUGGED: " + m);
}
}