phiaq – Speech

Speech Bot // Dummy Pimple Growth

*contains profanity

This is a dummy avatar named “Matthew” that takes in your swear word insults and grows pimples on his skin. It’s a way to release your anger to make a dummy suffer virtually instead of real life. I created Matthew in 3D space with real skin textures because I wanted it to look like a real generic person and have a gross/visceral effect. Matthew is a creation of insults, so he looks as ugly as possible. It parallels what an angry and hateful person wants the insulted to look like. Matthew is average and disgusting looking so you don’t feel guilty for insulting the bot. You can look at the list of swear words I have in the code.

Sketches

My Process

Firstly, I created the 3D model of the dummy. I had to experiment with different forms and textures to get the dummy looking right. So, I had to go into photoshop and make sure that the photos wrapped correctly. Here are a few iterations:

  
The weird image I created for the wrap on the ellipsoid

Here’s the skin I had to create/merge on photoshop to get the right wrapping. I also custom created the pimple on the skin.

 

Conclusion

It looks really gross in the end. Maybe I should have made it less overwhelming. I do want to get better at 3D modeling though so it wouldn’t look so cartoony. Although, part of me likes it because it reminds me of horror film characters.

Code

 

//thanks to alex petrusca and golan levin
 
var swearWords = ["ass", "asshole", "bastard", "bitch", "ugly" , "fucker", "crap", "cunt", "damn", "s***", "piss"
    , "whore", "dick", "f***", "a******", "b******", "f******", "b****", "penis", "nasty", "ugly"];
 
function preload() {
    orange = loadImage('https://i.imgur.com/FwcwdX6.jpg?1');
    man = loadImage('https://i.imgur.com/H08Fcx6.png');
    skin = loadImage('https://i.imgur.com/fW08aXt.png');
    eye = loadImage('https://i.imgur.com/cWXLwqG.png');
    mouth = loadImage('https://i.imgur.com/4qQs8XF.png');
    hair = loadImage('https://i.imgur.com/1qd3Erj.png');
    pimple = loadImage('https://i.imgur.com/mEMMUAT.png');
}
 
//--------------------------
 
var PIMPLE_NUM = 0;
var pimpleArr;
 
var o;
var mySpeechRecognizer;
var mostRecentSpokenWord;
var mostRecentConfidence;
 
function setup() {
    createCanvas(400, 400, WEBGL);
    o = createGraphics(256, 256);
 
    mostRecentConfidence = 0;
    mostRecentSpokenWord = "";
    initializeMySpeechRecognizer();
 
    pimpleArr = [];
}
 
function initializeMySpeechRecognizer(){
    mySpeechRecognizer = new p5.SpeechRec('en-US'); 
 
    // These are important settings to experiment with
    // mySpeechRecognizer.continuous = true;      // Do continuous recognition
    mySpeechRecognizer.interimResults = true; // Allow partial recognition (faster, less accurate)
    mySpeechRecognizer.onResult = parseResult; // The speech recognition callback function
    mySpeechRecognizer.onEnd = restartSpeech; // The speech recognition callback function
    mySpeechRecognizer.start(); // Start the recognition engine. Requires an internet connection!
}
 
function restartSpeech() {
    mySpeechRecognizer.start();
}
 
function parseResult() {
    console.log (mySpeechRecognizer.resultString);
    mostRecentSpokenWord = mySpeechRecognizer.resultString.split(' ').pop();
    mostRecentConfidence = mySpeechRecognizer.resultConfidence;
 
    if     (mostRecentSpokenWord.indexOf("left" )!==-1) { console.log("left")  }
    else if(mostRecentSpokenWord.indexOf("right")!==-1) { console.log("right")  }
    else if(mostRecentSpokenWord.indexOf("up"   )!==-1) { console.log("up") }
    else if(mostRecentSpokenWord.indexOf("down" )!==-1) { console.log("down")  }
}
 
function keyPressed() {
    if (key === ' ') {
        mySpeechRecognizer.start();
    }
}
 
//--------------------------
let counter = 0;
function draw() {
  background(0);
  noStroke();
 
  push()
  var lightX = mouseX - width / 2;
  var lightY = mouseY - height / 2;
  pointLight(255,255,255,lightX,lightY,200);
  pointLight(255,255,255,200,200,300);
  pointLight(255 , 255 , 255 , 150 , 40 , 300);
  ambientLight(100);
  rotateY(Math.PI);
  rotateY(frameCount * 0.02);
  texture(skin);
  ellipsoid(100, 130, 90);
    //cone(100,70);
 
 
  push();
  //translate(100,30)
  translate(-10,40,-80);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  sphere(20);
  pop();
 
  push();
  //translate(100,30)
  translate(-22,50,-80);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  sphere(10);
  pop();
 
  push();
  //translate(100,30)
  translate(10,50,-80);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  sphere(10);
  pop();
 
    //eye
  push();
  //translate(100,30)
  translate(22,-10,-90);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(eye);
  sphere(10);
  //ellipsoid(20,10,10);
  pop();
 
  //skin around eye
  push();
  //translate(100,30)
  translate(-8,-10,-82);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  ellipsoid(44,23,8);
  //ellipsoid(20,10,10);
  pop();
 
  //forehead
  push();
  //translate(100,30)
  translate(-8,-40,-73);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  ellipsoid(55,40,10);
  //ellipsoid(20,10,10);
  pop();
 
    //other eye
  push();
  //translate(100,30)
  translate(-40,-10,-87);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(eye);
  sphere(10);
  //ellipsoid(20,10,10);
  pop();
 
  //ear r
  push();
  //translate(100,30)
  translate(-98,0,-10);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  ellipsoid(10,20,10);
  pop();
 
 
  //ear r
  push();
  //translate(100,30)
  translate(98,0,-10);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  ellipsoid(10,20,10);
  pop();
 
 
    //mouth
  push();
  //translate(100,30)
  translate(0,80,-40);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(mouth);
  ellipsoid(40,30,40);
  pop();
 
    //neck
  push();
  //translate(100,30)
  translate(0,130,0);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  cylinder(20,20);
  pop();
 
    //nosebridge
  push();
  //translate(100,30)
  translate(-10,13,-40);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  ellipsoid(24,40,59);
  pop();
 
    //eyebrow r
  push();
  //translate(100,30)
  translate(-35,-32,-70);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(hair);
  ellipsoid(23,10,20);
  pop();
 
    //eyebrow l
  push();
  //translate(100,30)
  translate(20,-30,-70);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(hair);
  ellipsoid(23,10,20);
  pop();
 
  //cheek l
  push();
  //translate(100,30)
  translate(36,28,-70);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  ellipsoid(30,30,20);
  pop();
 
  //cheek r
  push();
  //translate(100,30)
  translate(-55,29,-63);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  ellipsoid(30,30,20);
  pop();
 
 
 
  //body
  push();
  //translate(100,30)
  translate(0,228,0);
  push();
  rotateX(90 * 0.07);
  rotateY(frameCount * 0.02);
  pop();
  texture(skin);
  ellipsoid(80,90,50);
  pop();
 
  drawPimples();
  addPimples();
 
  for (var i = 0; i < swearWords.length; i++) {
      if (mostRecentSpokenWord.includes(swearWords[i])) {
          mostRecentSpokenWord = "";
          PIMPLE_NUM += 10;
      }
  }
 
  pop();
 
  //text
  frameCount+=0.10;
  o.background(0);
  o.fill(255);
  o.text("Insult Me With Swears", 67, 25);
  texture(o);
  plane(400);
}
 
function drawPimples() {
    for(let i = 0; i < pimpleArr.length; i++) {
        pimpleArr[i].draw();
    }
}
 
function addPimples() {
    if(counter < PIMPLE_NUM) {
        let xyz = getPimpleXYZ();
        pimpleArr.push(new Pimple(xyz[0], xyz[1], xyz[2], random(1, counter/10)));
        counter++;
    }
}
 
function noCollision(pimple) {
    for(let i = 0; i < pimpleArr.length; i++) { if(pimple.collidesWith(pimpleArr[i])) { return false; } } return true; } function getPimpleXYZ() { let xyz = new Array(3); let x = random(-100, 100); let yMax = Math.sqrt(130**2 * (1 - (x/100)**2)); let y = random(-yMax, yMax); let z = Math.sqrt(90**2 * (1 - (x/100)**2 - (y/130)**2)); let plusMinus = random(0, 2); z = (plusMinus > 1)? z : -z;
 
    xyz[0] = x;
    xyz[1] = y;
    xyz[2] = z;
 
    return xyz;
}
 
function getPimpleZ(x, y) {
    return -Math.sqrt(90**2 * (1 - (x/100)**2 - (y/130)**2));
}
 
class Pimple {
    constructor(x, y, z, fR) {
        this.x = x;
        this.y = y;
        this.z = z;
        this.fR = fR;
        this.r = 0;
    }
 
    draw() {
        push();
        translate(this.x, this.y, this.z);
        rotateY(atan(this.x/this.z));
        if(this.z > 0) {
            rotateY(-Math.PI / 2);
        } else {
            rotateY(Math.PI / 2);
        }
        rotateX(atan(this.y/this.z));
        texture(pimple);
        sphere(this.r);
        pop();
        this.incrementRadius();
    }
 
    incrementRadius() {
        if(this.r < this.fR)
            this.r += 0.5;
    }
 
    collidesWith(other) {
        return this.distanceTo(other) < this.fR + other.fR;
    }
 
    distanceTo(other) {
        return Math.sqrt((this.x - other.x)**2 + (this.y - other.y)**2 + (this.z - other.z)**2);
    }
}