Skip to content

Instantly share code, notes, and snippets.

@dribnet
Forked from AndrewMoffat/README.md
Last active November 2, 2016 02:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save dribnet/6ba0b1aa018a6db6a3c67d9560accf03 to your computer and use it in GitHub Desktop.
Save dribnet/6ba0b1aa018a6db6a3c67d9560accf03 to your computer and use it in GitHub Desktop.
MDDN 342 Final Project

Face Generator - Andrew Moffat This is the refined version of my face generator. To begin with, the original version of the project featured a monochromatic sketch style, using Bezier curves. I wanted to revisit this project as I felt that I had a really solid base of code and graphic design to build upon, where I had left the project it was almost as if I had drawn the outline, but had forgotten to colour it in. I identified that one part of the project, to produce unique faces was being held back by the stylistic similarity, the lack of distinct visual elements.

I initially began by changing each face element into its own object, and created the grid using an array of objects. My intent was to utilise this for animation, but unfortunately this did not work out. I then enlarged the faces to allow for quicker comparisons, and increased the saturation on the faces to a more natural skin tone. I also refined the mouth down to enhance the visibility of emotion, and enlarged the eyes, as well as adding in variation with the eyebrows as the eye position. I also added in variation around the ‘Gauntness’ of the lower half of the face.

With the next version I decided to focus my efforts on replicating a ‘male’ face, as this would reduce the complexity of the code and allow me to focus on refinement. I chose to work on facial hair next, beginning by adding in a simple shape representation, but decided that this didn’t look quite right. I wanted a bit more realism and uniqueness, so I chose to add in another layer of thicker but more transparent edge lines that were coloured blonde or brown to break up the contrast of the black edge lines and the beard, and to soften up the lower half of the faces to create more diversity.

The next iteration was focused on adding in hair. I initially began by approaching it in the same way as the beard, by using a block shape to shade in the area, and soften up the edges using softer transparent lines. This block shape did not work at all, and just made the faces look blocky and uniform, so I removed this and just left it with the soft edge lines. I didn’t like how flat everything was looking, so I experimented with layering the base shape with different opacities and brightness to push it into 3d space, but this didn’t really produce an effect I liked. I decided to stick with the sketch style, and utilizing my line function create shading similar to what you would get with a graphics marker. I really loved the effect this produced, but wanted it to pop a bit more, so made the hair some nice bright colours.

With my final iteration, I decided I loved the forms that I had come to, but didn’t like the aesthetic that was produced by the colour combinations. I decided to look back to last project, and pull the colour palette from that and use it for this version. That colour scheme tied it all together, with a primary colour scheme perfectly tying in and complementing the sketch/graphic marker style

// note: this file is poorly named - it can generally be ignored.
// helper functions below for supporting blocks/purview
var canvasWidth = 4000;
var canvasHeight = 3000;
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 = canvasWidth;
offscreenCanvas.height = canvasHeight;
var context = offscreenCanvas.getContext('2d');
// background is flat white
context.fillStyle="#FFFFFF";
context.fillRect(0, 0, canvasWidth, canvasHeight);
context.drawImage(this.canvas, 0, 0, canvasWidth, canvasHeight);
// save to browser
var downloadMime = 'image/octet-stream';
var imageData = offscreenCanvas.toDataURL('image/png');
imageData = imageData.replace('image/png', downloadMime);
p5.prototype.downloadFile(imageData, 'canvas.png', 'png');
/*
// 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');
*/
}
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)();
}
<head>
<script src="http://cdnjs.cloudflare.com/ajax/libs/p5.js/0.5.2/p5.js"></script>
<script src="http://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>
{
"commits": [
{
"sha": "0000000000000000000000000000000000000012",
"name": "final_version"
},
{
"sha": "0000000000000000000000000000000000000011",
"name": "interaction_2"
},
{
"sha": "0000000000000000000000000000000000000010",
"name": "interaction_1"
},
{
"sha": "0000000000000000000000000000000000000009",
"name": "distribution_2"
},
{
"sha": "0000000000000000000000000000000000000008",
"name": "distribution_1"
},
{
"sha": "0000000000000000000000000000000000000007",
"name": "randomizer_3"
},
{
"sha": "0000000000000000000000000000000000000006",
"name": "randomizer_2"
},
{
"sha": "0000000000000000000000000000000000000005",
"name": "randomizer_1"
},
{
"sha": "0000000000000000000000000000000000000004",
"name": "drawing_styles_3"
},
{
"sha": "0000000000000000000000000000000000000003",
"name": "drawing_styles_2"
},
{
"sha": "0000000000000000000000000000000000000002",
"name": "drawing_styles_1"
},
{
"sha": "6e6db89be3cb99f99d07171faee645e84379dd06",
"name": "self_portrait"
}
]
}
var main_canvas;
var colF=100;
var smilebool=[];
var smiletime=[];
var sec = 0;
var faces=[];
var faceGaunt;
var midW;
var beardcheck;
var haircheck;
var canvasWidth = 4000;
var canvasHeight = 3000;
function setup () {
// create the drawing canvas, save the canvas element
main_canvas = createCanvas(canvasWidth, canvasHeight);
background(227,225,216);
beardcheck=round(random(0,1));
haircheck=round(random(0,2));
faceGaunt=random(.4,.8)
for (var i=0; i<200; i++) {
faces.push(new drawface());
}
smilebool[i]=false;
smiletime[i]=round(random(10,40));
angleMode(DEGREES);
main_canvas.parent('canvasContainer');
}
function draw(){
sec = second();
var smilesize=7;
var countface=0;
background(227,225,216);
for(i=3.0;i<=25;i+=1.1) {
for(u=3.4;u<=15;u+=0.8) {
// for(i=.5;i<=(14*2) + 0.5;i++){
// for(u=.5;u<=(8*3) + 0.5;u++){
// for(i=.5;i<=(1) + 0.5;i++){
// for(u=.5;u<=(1) + 0.5;u++){
beardcheck=round(random(0,1));
haircheck=round(random(0,2));
faces[countface].x=1000/5*i
faces[countface].y=500/3*u
if(smiletime[countface]==sec){
faces[countface].smilesize=16
}
faces[countface].display()
countface++
println(countface)
}
}
noLoop();
}
function keyTyped() {
if (key == '!') {
saveBlocksImages();
}
}
function drawface() {
this.x
this.y
this.basegen=random(60,110);
this.smilesize=4;
this.display = function() {
basegen=this.basegen
x=this.x
y=this.y
smilesize=this.smilesize
top1 = basegen
bottom = basegen*random(1.04,1.17)
size=random(70,80)/100
side = basegen*random(size-.04,size+.04)
push()
rotate(random(-10,10))
translate(x, y);
push()
rotate(random(-40,40))
faceGaunt=random(.5,.8)
head(top1,bottom,side,smilesize)
eyes(top1,bottom,side)
mouth2(top1,bottom,side,smilesize)
hair(top1,bottom,side)
headlines(top1,bottom,side)
pop()
pop()
}
}
function keyTyped() {
if (key == '!') {
saveBlocksImages();
}
}
function head(top1,bottom,side,smilesize){
midW=random(.8,1.2)
top1 = top1
bottom = bottom
side2 = midW*side
colorMode(HSB,360)
colF=random(225,360)
fill(37,90,colF)
noStroke()
colorMode(RGB,255)
var linecolors = [ [222,86,74], [89,198,213], [238,236,166]]
fill(linecolors[(round(random(2)))])
colorMode(HSB,360)
beginShape();
vertex(0, bottom);//chin
vertex(faceGaunt*side,.85*bottom);//bottomRight
vertex(side2,0);//midRight
vertex(.9*side2,-.66*top1);//topRight
vertex(0,-top1);//top of head
vertex(-.9*side2,-.66*top1);//topLeft
vertex(-side2, 0);//midleft
vertex(-faceGaunt*side2,.85*bottom);//bottomleft
endShape();
shadeW=random(40,60)
facelines2(0, bottom,0,-top1,360,5,shadeW)
facelines2(faceGaunt*side,.85*bottom,.9*side2,-.66*top1,360,20,shadeW)
facelines2(side2,0,side2,0,360,30,shadeW)
facelines2(-faceGaunt*side,.85*bottom,-.9*side2,-.66*top1,0,10,shadeW)
facelines2(-side2,-15,-side2,15,0,10,shadeW)
colorMode(RGB,255)
linescol=color(0,150)
stroke(linescol)
facelines(0,bottom,faceGaunt*side2,.85*bottom,linescol)
facelines(faceGaunt*side2,.85*bottom,side2,0,linescol)
facelines(side2,0,.9*side2,-.66*top1,linescol)
facelines(.9*side2,-.66*top1,0,-top1,linescol)
facelines(0,bottom,-faceGaunt*side2,.85*bottom,linescol)
facelines(-faceGaunt*side2,.85*bottom,-side2,0,linescol)
facelines(-side2,0,-.9*side2,-.66*top1,linescol)
facelines(-.9*side2,-.66*top1,0,-top1,linescol)
}
function headlines(top1,bottom,side){
top1 = top1
bottom = bottom
side2 = midW*side
colorMode(HSB,360)
colF=random(225,360)
fill(37,90,colF)
noStroke()
colorMode(RGB,255)
linescol=color(0,150)
stroke(linescol)
facelines(0,bottom,faceGaunt*side2,.85*bottom,linescol)
facelines(faceGaunt*side2,.85*bottom,side2,0,linescol)
facelines(side2,0,.9*side2,-.66*top1,linescol)
facelines(.9*side2,-.66*top1,0,-top1,linescol)
facelines(0,bottom,-faceGaunt*side2,.85*bottom,linescol)
facelines(-faceGaunt*side2,.85*bottom,-side2,0,linescol)
facelines(-side2,0,-.9*side2,-.66*top1,linescol)
facelines(-.9*side2,-.66*top1,0,-top1,linescol)
}
function facelines (ax1,ay1,ax2,ay2,colorfacelines){
noFill()
//fill(29,130,colF)
//colorMode(HSB,360)
//stroke(0,200)
strokeWeight(random(2))
r1=-20
r2=20
i=0
for(var i=0;i<=5;i++){
controlx1=round(ax1+random(r1,r2)*cos(random(0,360)))
controly1=round(ay1+random(r1,r2)*sin(random(0,360)))
controlx2=round(ax2+random(r1,r2)*cos(random(0,360)))
controly2=round(ay2+random(r1,r2)*sin(random(0,360)))
strokeWeight(random(3))
bezier(ax1,ay1,controlx2,controly2,controlx1,controly1,ax2,ay2)
ellipse(ax1,ay1,5,5)
ellipse(ax2,ay2,5,5)
}
colorMode(HSB,360)
}
function facelines2 (ax1,ay1,ax2,ay2,colorfacelines,colorfacelines2,shade){
noFill()
r1=-20
r2=20
i=0
for(var i=0;i<=5;i++){
controlx1=round(ax1+random(r1,r2)*cos(random(0,360)))
controly1=round(ay1+random(r1,r2)*sin(random(0,360)))
controlx2=round(ax2+random(r1,r2)*cos(random(0,360)))
controly2=round(ay2+random(r1,r2)*sin(random(0,360)))
stroke(colorfacelines,colorfacelines2)
strokeWeight(shade)
bezier(ax1,ay1,controlx2,controly2,controlx1,controly1,ax2,ay2)
}
colorMode(HSB,360)
}
function beardlines (ax1,ay1,ax2,ay2,colorfacelines,neat){
noFill()
//fill(29,130,colF)
//colorMode(HSB,360)
//stroke(0,colorfacelines)
strokeWeight(random(2))
r1=-20
r2=20
i=0
for(var i=0;i<=5;i++){
controlx1=round(ax1+random(r1,r2)*cos(random(0,360)))
controly1=round(ay1+random(r1,r2)*sin(random(0,360)))
controlx2=round(ax2+random(r1,r2)*cos(random(0,360)))
controly2=round(ay2+random(r1,r2)*sin(random(0,360)))
strokeWeight(neat)
bezier(ax1,ay1,controlx2,controly2,controlx1,controly1,ax2,ay2)
//ellipse(ax1,ay1,5,5)
//ellipse(ax2,ay2,5,5)
}
}
function hairlines (ax1,ay1,ax2,ay2,colorfacelines,neat){
noFill()
//fill(29,130,colF)
strokeWeight(random(2))
r1=-20
r2=20
i=0
for(var i=0;i<=5;i++){
controlx1=round(ax1+random(r1,r2)*cos(random(0,360)))
controly1=round(ay1+random(r1,r2)*sin(random(0,360)))
controlx2=round(ax2+random(r1,r2)*cos(random(0,360)))
controly2=round(ay2+random(r1,r2)*sin(random(0,360)))
strokeWeight(neat)
bezier(ax1,ay1,controlx2,controly2,controlx1,controly1,ax2,ay2)
//ellipse(ax1,ay1,5,5)
//ellipse(ax2,ay2,5,5)
}
}
function eyes (top1,bottom,side){
top1=top1
bottom=bottom
side=side
xR1=random(.25,.55)
xR2=random(.25,.55)
yR1=random(0,.15)
r1=.1*20;
r2=random(6,14)
pupilcol=random(150,200)
pupilcolb=random(0,100)
noFill()
stroke(65,65,65,150)
strokeWeight(.2)
ellipse(xR1*side,yR1*bottom,20,20)
for(var i=0;i<6;i++){
stroke(20,random(20,100))
strokeWeight(random(1,2))
ellipse(xR1*side,yR1*bottom,random(10-r1,10+r1),random(10-r1,10+r1))
//rect(.4*side-random(10-r1,10+r1),.05*bottom-random(10-r1,10+r1),random(20-r1,20+r1),random(20-r1,20+r1))
}
fill(360)
pupil1x=round((xR1*side)+random(0,4-r2)*cos(random(0,360)))
pupil1y=round((yR1*bottom)+random(0,4-r2)*sin(random(0,360)))
ellipse(pupil1x,pupil1y,random((r2-1)*2,(r2+1)*2),random((r2-1)*2,(r2+1)*2))
fill(pupilcol,0,pupilcolb)
ellipse(pupil1x,pupil1y,(random((r2-1)*2,(r2+1)*2))/1.4,(random((r2-1)*2,(r2+1)*2))/1.4)
noFill()
stroke(65,65,65,150)
strokeWeight(.2)
ellipse(-xR2*side,yR1*bottom,20,20)
for(var i=0;i<6;i++){
stroke(20,random(20,100))
strokeWeight(random(1,2))
ellipse(-xR2*side,yR1*bottom,random(10-r1,10+r1),random(10-r1,10+r1))
//rect(-.4*side-random(10-r1,10+r1),.05*bottom-random(10-r1,10+r1),random(20-r1,20+r1),random(20-r1,20+r1))
}
fill(360)
pupil2x=round((-xR2*side)+random(0,4-r2)*cos(random(0,360)))
pupil2y=round((yR1*bottom)+random(0,4-r2)*sin(random(0,360)))
ellipse(pupil2x,pupil2y,random((r2-1)*2,(r2+1)*2),random((r2-1)*2,(r2+1)*2))
fill(pupilcol,0,pupilcolb)
ellipse(pupil2x,pupil2y,(random((r2-1)*2,(r2+1)*2))/1.4,(random((r2-1)*2,(r2+1)*2))/1.4)
eyebrows(top1,bottom,side,xR1,xR2,yR1)
}
function eyebrows (top1,bottom,side,xr1,xr2,yr1){
top1=top1
bottom=bottom
side=side
xr3=random((xr1-.05),(xr1+.05))
xr4=random((xr2-.05),(xr2+.05))
yr2=random((yr1-.05),(yr1+.05))
lift1=random(10,22)
col=round(random(0,1))*255
fill(65,65,65)
noStroke()
strokeWeight(3)
stroke(col)
line(xr3*side-random(3,15),yr1*bottom-lift1,xr3*side+random(3,15),yr1*bottom-random((lift1-5),lift1))
line((-xr3*side)-random(3,15),yr1*bottom-random((lift1-5),lift1),(-xr3*side)+random(3,15),yr1*bottom-lift1)
}
function mouth(){
mth=1
x1=35
y1=98
y2=88
y3=85
y4=95
fill(255)
beginShape();
vertex(x1, y1);
bezierVertex(-x1-mth, y2-mth, -x1+mth, y2-mth, -x1, y2);
bezierVertex(-x1, y3+mth, -x1, y3, -x1, y3);
bezierVertex(-x1, y4+mth, -x1, y4, x1, y4);
endShape();
}
function mouth2 (top1,bottom,side){
top1=top1
bottom=bottom
side=side
ax1=.3*side
ay1=.55*bottom
ax2=-.3*side
ay2=.55*bottom
noFill()
stroke(255,185)
strokeWeight(focusedRandom(0,3,.5))
beardL=random(0,.3)
if(beardcheck>0){
noStroke()
beardOpac=random(100,260)
fill(0,beardOpac)
xdif=(side-(faceGaunt*side))*beardL
beardOpac=beardOpac/1.5
beginShape();
vertex(0, bottom);//chin
vertex(faceGaunt*side,.85*bottom);//bottomRight
vertex(side-xdif,beardL*bottom);//midRight
vertex(ax1,ay1);//topRight
vertex(ax2,ay2);//topLeft
vertex(-side+xdif, beardL*bottom);//midleft
vertex(-faceGaunt*side,.85*bottom);//bottomleft
endShape();
noFill()
neat=random(1,15)
colorMode(RGB,255)
//var linecolors = [ [84,72,58,100], [238,236,166,100], [random(60,80),65,57,100]]
var linecolors = [ [222,86,74], [89,198,213], [238,236,166]]
stroke(linecolors[(round(random(2)))])
colorMode(HSB,360)
beardlines(0, bottom,faceGaunt*side,.85*bottom,beardOpac,neat)
beardlines(faceGaunt*side,.85*bottom,side-xdif,beardL*bottom,beardOpac,neat)
//beardlines(side-xdif,beardL*bottom,ax1,ay1,beardOpac)
//beardlines(ax2,ay2,-side+xdif, beardL*bottom,beardOpac)
beardlines(-side+xdif, beardL*bottom,-faceGaunt*side,.85*bottom,beardOpac,neat)
beardlines(-faceGaunt*side,.85*bottom,0, bottom,beardOpac,neat)
}
stroke(0,random(0,20),360,200)
rand1=random(90,180)
rand2=random(r1,r2)
for(var i=0;i<=4;i++){
controlx11=round(ax1+rand2*cos(rand1))
controly11=round(ay1+rand2*sin(rand1))
controlx21=round(ax2+rand2*cos(rand1))
controly21=round(ay2+rand2*sin(rand1))
strokeWeight(random(2,3))
bezier(ax1,ay1,controlx11,controly21,controlx21,controly21,ax2,ay2) }
}
function hair (top1,bottom,side){
top1=top1
bottom=bottom
side=side
ax1=.3*side
ay1=.55*bottom
ax2=-.3*side
ay2=.55*bottom
noFill()
stroke(255,185)
strokeWeight(focusedRandom(0,3,.5))
beardL=random(0,.3)
if(haircheck>0){
noStroke()
hairOpac=random(100,260)
fill(0,hairOpac)
xdif=(side-(faceGaunt*side))*beardL
hairOpac=hairOpac/1.5
noFill()
neat=random(1,15)
colorMode(RGB,255)
var linecolors = [ [222,86,74], [89,198,213], [238,236,166]]
stroke(linecolors[(round(random(2)))])
colorMode(HSB,360)
//stroke(random(0,360),100,300,100)
hairlines(side2,0,.9*side2,-.66*top1,hairOpac,neat)
hairlines(.9*side2,-.66*top1,0,-top1,hairOpac,neat)
hairlines(0,-top1,-.9*side2,-.66*top1,hairOpac,neat)
hairlines(-.9*side2,-.66*top1,-side2, 0,hairOpac,neat)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment