Category: Assignment-05-FaceOSC

Deer Hunter

face1

face2

I once participated in a game design conversation, and one of the ideas we developed was to have a predator hiding its size so it can sneak up on its prey. The devouring idea is also inspired by Thatgamecompany’s Flow. I feel by using the mouth as the catalyst for consuming, I can put the player into a more emersive atmosphere, and maybe make them feel either bad or empowered as they turn deer into explosions of blood. I feel I can improve upon the game by adding in sound effects and music, but finding the perfect ones take more time than I anticipated.

I used the position of the head to determine whether the blob should go left or right on screen. Changing the height of my mouth will change the size of the blob, and when that height go past a certain threshold, the blob turns into a monster and devour the deer. It will revert back to a small blob once the player closes his/her mouth again.

Angwy Face

I have always been afraid of upsetting people and invoking their wrath. I always try to leave an encounter without making another person angry, as I am especially afraid of being yelled at. This fear has been eating at me recently as I try to navigate a new place with new people and new different personalities. I chose to make a face, modeled on the PLZ face memes because of their wide range of over the top expressions, that confronted this fear by always being angry. The point of interacting with the face is to make it angrier. I wanted to make the angry face cuter and cuter the more aggressive it tried to be, negating its negativity. The angriest features correspond to the happiest features on the viewer, leaving the viewer smiling while the face is raging at them. I used right and left eyebrow heights and the mouth height OSC properties as I felt these features give the widest range of happy/angry facial triggers. This too was a choice to negate the face’s negativity. I like the way this turned out; it gives me a little more confidence in my fuddlings with Processing.

FaceOSC Bot

While I was brainstorming ideas for my FaceOSC character, my first ideas were three dimensional creatures like giraffes or other animals. These are ideas that I would actually like to animate in the future, but I have yet to fully understand how to create complex 3D shapes in Processing.

Anyways, I decided to shift gears to a deconstructed face, so I could work with the component parts: the eyes, eyebrows, nose, and mouth. And I think the webcam icon on my laptop subconsciously inspired me, because I didn’t realize how similar my initial eyeball sketches were to the design of a webcam. And that turned out to be just fine because it adds to the idea of how FaceOSC interacts with people.

A great deal of my time was spent figuring out how to animate the propellers. I decided to go with a 3-frame GIF and just import it as an image. But the more I think of it, my program could have had a lot more flexibility and interactivity if I created a 3D sphere and somehow stuck a propeller and pupil on it. Anywho, I am still quite proud of the propeller GIF though.

My second challenge was figuring out the design for the mouth (I scrapped the nose). I couldn’t really imagine a shape that fit with the theme of circular robots, so I went with red laser beams shooting through robo-dimples. I’m not sure if that idea comes across with other people, though. Unfortunately, my mouth portion is a bit glitchy as the endpoints don’t properly line up with the robo-dimples when I move my mouth in certain areas.

Finally, the properties I used from FaceOSC are the x-position and y-position of the face, the face scale, the eyebrow height (the eyebrows move the eyeballs, I thought it would be more fun that way), the mouth width, and the mouth height. And even though the variables I used are limited, the sinusoidal movements kind of make it more enjoyable to look at.

Here are some sketches I did first, followed by my code:
sketchface

facesketch2

//Kyle McDonald's FaceOSC https://github.com/kylemcdonald/ofxFaceTracker
import oscP5.*;
OscP5 oscP5;

Animation animation1, animation2, animation3, animation4;

int found;

float poseScale;
PVector posePosition = new PVector();
PVector poseOrientation = new PVector();

float mouthHeight;
float mouthWidth;
float eyebrowLeft;
float eyebrowRight;

float theta1 = 0;
float theta2 = 0;
float xposLEye;
float yposLEye;
float xposREye;
float yposREye;
float xposLDimple;
float yposLDimple;
float xposRDimple;
float yposRDimple;
float a1;
float b1;
float c1;
float a2;
float b2;
float c2;

void setup() {
  size(500, 550);
  frameRate(30);
  
  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, "eyebrowLeftReceived", "/gesture/eyebrow/left");
  oscP5.plug(this, "eyebrowRightReceived", "/gesture/eyebrow/right");
  
  animation1 = new Animation("roboeye", 3);
  animation2 = new Animation("roboeye", 3);
  animation3 = new Animation("roboballL", 3);
  animation4 = new Animation("roboballR", 3);
}

void draw() {
  background(255);
  backdrop(255,210);
  
  float a1 = map(sin(theta1),-1,1,-10,10);
  float b1 = map(cos(theta1),-1,1,-10,10);
  float c1 = map(sin(theta1),-1,1,-0.1,0.1);
  float a2 = map(sin(theta2),-1,1,-15,15);
  float b2 = map(cos(theta2),-1,1,-8,8);
  float c2 = map(sin(theta2),-1,1,-0.1,0.1);
  theta1+=0.15;
  theta2+=0.08;
  
  xposLEye = -width/2;
  yposLEye = eyebrowLeft * -11;
  xposREye = 0;
  yposREye = eyebrowRight * -10;
  xposLDimple = -mouthWidth * 7-75;
  yposLDimple = height/3-50;
  xposRDimple = mouthWidth * 7-75;
  yposRDimple = height/3-50;
  
  if(found>0) {
    translate(posePosition.x-50, posePosition.y-50);
    
    pushMatrix();
    translate(a1,b1);
    rotate(c1);
    animation1.display(xposLEye,yposLEye);
    popMatrix();
    
    pushMatrix();
    scale(0.85);
    translate(b2,a2);
    rotate(c2);
    animation1.display(xposREye,yposREye);
    popMatrix();
    
    pushMatrix();
    translate(b1,a1);
    rotate(c1);
    laserArc(xposLDimple+160,yposLDimple+50,mouthWidth*11.5,mouthHeight*30,0,PI);
    laserArc(xposLDimple+160,yposLDimple+50,mouthWidth*11.5,mouthHeight*2,-PI,0);
    animation3.display(xposLDimple,yposLDimple);
    animation4.display(xposRDimple,yposRDimple);
    popMatrix();
  }
}

// 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 eyebrowLeftReceived(float f) {
  println("eyebrow left: " + f);
  eyebrowLeft = f;
}

public void eyebrowRightReceived(float f) {
  println("eyebrow right: " + f);
  eyebrowRight = 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);
  }
}

void laserArc(float x0, float y0, float wid, float hgt, float start, float stop){
  noFill();
  
  strokeWeight(15);
  stroke(240,0,0,75);
  arc(x0,y0,wid,hgt,start,stop);
  
  strokeWeight(12);
  stroke(240,0,0,75);
  arc(x0,y0,wid,hgt,start,stop);
  
  strokeWeight(5);
  stroke(255,100);
  arc(x0,y0,wid,hgt,start,stop);
  
  strokeWeight(3);
  arc(x0,y0,wid,hgt,start,stop);
}

void backdrop(color c1, color c2){
  noFill();
  for(int i=0;i< =height-50;i++){
      float inter=map(i,0,height-50,0,1);
      color c=lerpColor(c1,c2,inter);
      stroke(c);
      line(0,i+100,width,i+100);
  }
}

// Class for animating a sequence from Processing.org

class Animation {
  PImage[] images;
  int imageCount;
  int frame;
  
  Animation(String imagePrefix, int count) {
    imageCount = count;
    images = new PImage[imageCount];

    for (int i = 0; i < imageCount; i++) {
      // Use nf() to number format 'i' into four digits
      String filename = imagePrefix + i + ".gif";
      images[i] = loadImage(filename);
    }
  }

  void display(float xpos, float ypos) {
    frame = (frame+1) % imageCount;
    image(images[frame], xpos, ypos);
  }
}

Ticha-Creature designs

bud thing

sheep

chimera

forest spirit

 

Sorry for the photo spam – I just wanted to create a separate post for documenting the initial designs for my FaceOSC creature/character. While these aren’t exactly faces, they can still be viewed as ‘avatars’ whose movements correspond to the user’s facial expressions.

A disgruntled llama:

como se llama