block by dribnet e8f7f19f503af19d7591a9723e67db8a

Parametric Faces

Full Screen

PS1 MDDN 342 2016

This is my final solution to PS1. I chose to make faces that reminded me vaguely of my avatar. After some experimenting, I chose to allow only slight variations in tilt. The mouth generally is closed and never opens too far. I decided to allow mutant version of my face with either one or three eyes, but these are very rare.

When viewed as a group, they seem to be a crowd all staring up the sky in disbelief.

index.html

<head>
    <script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/addons/p5.dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/seedrandom/2.4.0/seedrandom.min.js"></script>
    <script src="https://d3js.org/d3-random.v1.min.js"></script>
    <script language="javascript" type="text/javascript" src="focusedRandom.js"></script>
    <script language="javascript" type="text/javascript" src="readme.purview_helper.js"></script>
    <script language="javascript" type="text/javascript" src="sketch.js"></script>
    <style> body {padding: 0; margin: 0;} </style>
</head>
<body style="background-color:white">
<div id="canvasContainer"></div>
</body>

focusedRandom.js

function resetFocusedRandom() {
  return Math.seedrandom(arguments);
}

function focusedRandom(min, max, focus, mean) {
  // console.log("hello")
  if(max === undefined) {
    max = min;
    min = 0;
  }
  if(focus === undefined) {
    focus = 1.0;
  }
  if(mean === undefined) {
    mean = (min + max) / 2.0;
  }
  if(focus == 0) {
    return d3.randomUniform(min, max)();
  }
  else if(focus < 0) {
    focus = -1 / focus;
  }
  sigma = (max - mean) / focus;
  val = d3.randomNormal(mean, sigma)();
  if (val > min && val < max) {
    return val;
  }
  return d3.randomUniform(min, max)();
}

readme.purview_helper.js

// note: this file is poorly named - it can generally be ignored.

// helper functions below for supporting blocks/purview

function saveBlocksImages(doZoom) {
  if(doZoom == null) {
    doZoom = false;
  }

  // generate 960x500 preview.jpg of entire canvas
  // TODO: should this be recycled?
  var offscreenCanvas = document.createElement('canvas');
  offscreenCanvas.width = 960;
  offscreenCanvas.height = 500;
  var context = offscreenCanvas.getContext('2d');
  // background is flat white
  context.fillStyle="#FFFFFF";
  context.fillRect(0, 0, 960, 500);
  context.drawImage(this.canvas, 0, 0, 960, 500);
  // save to browser
  var downloadMime = 'image/octet-stream';
  var imageData = offscreenCanvas.toDataURL('image/jpeg');
  imageData = imageData.replace('image/jpeg', downloadMime);
  p5.prototype.downloadFile(imageData, 'preview.jpg', 'jpg');

  // generate 230x120 thumbnail.png centered on mouse
  offscreenCanvas.width = 230;
  offscreenCanvas.height = 120;

  // background is flat white  
  context = offscreenCanvas.getContext('2d');
  context.fillStyle="#FFFFFF";
  context.fillRect(0, 0, 230, 120);

  if(doZoom) {
    // pixelDensity does the right thing on retina displays
    var pd = this._pixelDensity;
    var sx = pd * mouseX - pd * 230/2;
    var sy = pd * mouseY - pd * 120/2;
    var sw = pd * 230;
    var sh = pd * 120;
    // bounds checking - just displace if necessary
    if (sx < 0) {
      sx = 0;
    }
    if (sx > this.canvas.width - sw) {
      sx = this.canvas.width - sw;
    }
    if (sy < 0) {
      sy = 0;
    }
    if (sy > this.canvas.height - sh) {
      sy = this.canvas.height - sh;
    }
    // save to browser
    context.drawImage(this.canvas, sx, sy, sw, sh, 0, 0, 230, 120);
  }
  else {
    // now scaledown
    var full_width = this.canvas.width;
    var full_height = this.canvas.height;
    context.drawImage(this.canvas, 0, 0, full_width, full_height, 0, 0, 230, 120);
  }
  imageData = offscreenCanvas.toDataURL('image/png');
  imageData = imageData.replace('image/png', downloadMime);
  p5.prototype.downloadFile(imageData, 'thumbnail.png', 'png');
}

sketch.js

var main_canvas;

var canvasWidth = 960;
var canvasHeight = 500;

var canvasWidth = 960;
var canvasHeight = 500;

function setup () {
  // create the drawing canvas, save the canvas element
  main_canvas = createCanvas(canvasWidth, canvasHeight);

  // rotation in degrees (more slider friendly)
  angleMode(DEGREES);

  curRandomSeed = int(focusedRandom(0, 1000));

  // position each element on the page
  main_canvas.parent('canvasContainer');
}

function changeRandomSeed() {
  curRandomSeed = curRandomSeed + 1;
}

var colorFront = [151, 102, 52];
var colorBack = [225, 206, 187];

function drawFace(x, y, w, h, tilt_value, eye_value, mouth_value) {
  resetMatrix();
  translate(x, y);
  rotate(tilt_value);

  var extent = 0;
  if(h < w) {
    extent = h / 2;
  }
  else {
    extent = w / 2;
  }
  var scale = extent / 220.0;

  fill(colorFront);
  ellipse(0, 0, 300 * scale, 400 * scale);

  // eyes
  if (eye_value === 1 || eye_value == 3) {
    fill(colorBack);
    ellipse( 0, -80 * scale, 50 * scale, 30 * scale);
    fill(colorFront);
    ellipse(-10 * scale, -80 * scale, 20 * scale, 20 * scale);
  }

  if (eye_value >= 2) {
    fill(colorBack);
    ellipse(-50 * scale, -80 * scale, 50 * scale, 30 * scale);
    ellipse( 50 * scale, -80 * scale, 50 * scale, 30 * scale);

    fill(colorFront);
    ellipse(-60 * scale, -80 * scale, 20 * scale, 20 * scale);
    ellipse( 40 * scale, -80 * scale, 20 * scale, 20 * scale);
  }

  // mouth
  fill(colorBack);
  ellipse(0 * scale, 70 * scale, 150 * scale, mouth_value * scale);
}

function getRandomNumberOfEyes() {
  random_result = focusedRandom(0, 100);
  if(random_result < 8) {
    return 1;
  }
  else if(random_result > 96) {
    return 3;
  }
  else {
    return 2;
  }
}

var lastSwapTime = 0;
var millisPerSwap = 2000;

function draw () {
  var millisNow = millis();
  if(millisNow > lastSwapTime + millisPerSwap) {
    changeRandomSeed();
    lastSwapTime = millisNow;
  }

  background(colorBack);
  fill(colorFront);
  stroke(95, 52, 8)

  resetFocusedRandom(curRandomSeed);

  var w = canvasWidth / 5;
  var h = canvasHeight / 3;
  for(var i=0; i<3; i++) {
    for(var j=0; j<5; j++) {
      var y = h/2 + h*i;
      var x = w/2 + w*j;
      tilt_value = focusedRandom(-70, 90, 12);
      eye_value = getRandomNumberOfEyes();
      mouth_value = focusedRandom(0, 50, 4, 1);
      drawFace(x, y, w, h, tilt_value, eye_value, mouth_value);
    }
  }
}

function keyTyped() {
  if (key == '!') {
    saveBlocksImages();
  }
  else if (key == '@') {
    saveBlocksImages(true);
  }
}