LJ/www/trckr/js/face_deformer.js

294 lines
8.9 KiB
JavaScript

"use strict";
var faceDeformer = function() {
var gl, verticeMap;
var numTriangles;
var maxx, minx, maxy, miny;
var width, height;
var first = true;
var texCoordBuffer, gridCoordbuffer;
var texCoordLocation;
var pdmModel;
var usegrid = false;
var drawProgram, gridProgram;
this.init = function(canvas) {
// ready a webgl element
gl = getWebGLContext(canvas);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
}
this.load = function(element, points, pModel, vertices) {
pdmModel = pModel;
if (vertices) {
verticeMap = vertices;
} else {
verticeMap = pdmModel.path.vertices;
}
numTriangles = verticeMap.length;
// get cropping
maxx = 0;
minx = element.width;
maxy = 0;
miny = element.height;
for (var i = 0;i < points.length;i++) {
if (points[i][0] > maxx) maxx = points[i][0];
if (points[i][0] < minx) minx = points[i][0];
if (points[i][1] > maxy) maxy = points[i][1];
if (points[i][1] < miny) miny = points[i][1];
}
minx = Math.floor(minx);
maxx = Math.ceil(maxx);
miny = Math.floor(miny);
maxy = Math.ceil(maxy);
width = maxx-minx;
height = maxy-miny;
if (element.tagName == 'VIDEO' || element.tagName == 'IMG') {
var ca = document.createElement('canvas');
ca.width = element.width;
ca.height = element.height;
var cc = ca.getContext('2d');
cc.drawImage(element, 0, 0, element.width, element.height);
} else if (element.tagName == 'CANVAS') {
var cc = element.getContext('2d');
}
var image = cc.getImageData(minx, miny, width, height);
// correct points
var nupoints = [];
for (var i = 0;i < points.length;i++) {
nupoints[i] = [];
nupoints[i][0] = points[i][0] - minx;
nupoints[i][1] = points[i][1] - miny;
}
// create vertices based on points
var textureVertices = [];
for (var i = 0;i < verticeMap.length;i++) {
textureVertices.push(nupoints[verticeMap[i][0]][0]/width);
textureVertices.push(nupoints[verticeMap[i][0]][1]/height);
textureVertices.push(nupoints[verticeMap[i][1]][0]/width);
textureVertices.push(nupoints[verticeMap[i][1]][1]/height);
textureVertices.push(nupoints[verticeMap[i][2]][0]/width);
textureVertices.push(nupoints[verticeMap[i][2]][1]/height);
}
if (first) {
// create program for drawing grid
var gridVertexShaderProg = [
"attribute vec2 a_position;",
"",
"uniform vec2 u_resolution;",
"",
"void main() {",
" vec2 zeroToOne = a_position / u_resolution;",
" vec2 zeroToTwo = zeroToOne * 2.0;",
" vec2 clipSpace = zeroToTwo - 1.0;",
" gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);",
"}"
].join('\n');
var gridFragmentShaderProg = [
"void main() {",
" gl_FragColor = vec4(0.2, 0.2, 0.2, 1.0);",
"}"
].join('\n');
var gridVertexShader = loadShader(gl, gridVertexShaderProg, gl.VERTEX_SHADER);
var gridFragmentShader = loadShader(gl, gridFragmentShaderProg, gl.FRAGMENT_SHADER);
try {
gridProgram = createProgram(gl, [gridVertexShader, gridFragmentShader]);
} catch(err) {
alert("There was a problem setting up the webGL programs. Maybe you should try it in another browser. :(");
}
gridCoordbuffer = gl.createBuffer();
// create program for drawing deformed face
var vertexShaderProg = [
"attribute vec2 a_texCoord;",
"attribute vec2 a_position;",
"",
"varying vec2 v_texCoord;",
"",
"uniform vec2 u_resolution;",
"",
"void main() {",
" vec2 zeroToOne = a_position / u_resolution;",
" vec2 zeroToTwo = zeroToOne * 2.0;",
" vec2 clipSpace = zeroToTwo - 1.0;",
" gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);",
" ",
" v_texCoord = a_texCoord;",
"}"
].join('\n');
var fragmentShaderProg = [
"precision mediump float;",
"",
"uniform sampler2D u_image;",
"",
"varying vec2 v_texCoord;",
"",
"void main() {",
" gl_FragColor = texture2D(u_image, v_texCoord);",
"}"
].join('\n');
var vertexShader = loadShader(gl, vertexShaderProg, gl.VERTEX_SHADER);
var fragmentShader = loadShader(gl, fragmentShaderProg, gl.FRAGMENT_SHADER);
drawProgram = createProgram(gl, [vertexShader, fragmentShader]);
texCoordBuffer = gl.createBuffer();
first = false;
}
// load program for drawing grid
gl.useProgram(gridProgram);
// set the resolution for grid program
var resolutionLocation = gl.getUniformLocation(gridProgram, "u_resolution");
gl.uniform2f(resolutionLocation, gl.drawingBufferWidth, gl.drawingBufferHeight);
// load program for drawing deformed face
gl.useProgram(drawProgram);
// look up where the vertex data needs to go.
texCoordLocation = gl.getAttribLocation(drawProgram, "a_texCoord");
// provide texture coordinates for face vertices (i.e. where we're going to copy face vertices from).
gl.enableVertexAttribArray(texCoordLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureVertices), gl.STATIC_DRAW);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
// Create the texture.
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
// Upload the image into the texture.
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
// set the resolution for draw program
resolutionLocation = gl.getUniformLocation(drawProgram, "u_resolution");
gl.uniform2f(resolutionLocation, gl.drawingBufferWidth, gl.drawingBufferHeight);
}
this.draw = function(points) {
if (usegrid) {
// switch program if needed
gl.useProgram(drawProgram);
//texCoordLocation = gl.getAttribLocation(drawProgram, "a_texCoord");
gl.enableVertexAttribArray(texCoordLocation);
gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer);
gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0);
usegrid = false;
}
// create drawvertices based on points
var vertices = [];
for (var i = 0;i < verticeMap.length;i++) {
vertices.push(points[verticeMap[i][0]][0]);
vertices.push(points[verticeMap[i][0]][1]);
vertices.push(points[verticeMap[i][1]][0]);
vertices.push(points[verticeMap[i][1]][1]);
vertices.push(points[verticeMap[i][2]][0]);
vertices.push(points[verticeMap[i][2]][1]);
}
var positionLocation = gl.getAttribLocation(drawProgram, "a_position");
// Create a buffer for the position of the vertices.
var drawPosBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, drawPosBuffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Draw the face vertices
gl.drawArrays(gl.TRIANGLES, 0, numTriangles*3);
}
this.drawGrid = function(points) {
if (!usegrid) {
gl.useProgram(gridProgram);
usegrid = true;
}
// create drawvertices based on points
var vertices = [];
// create new texturegrid
for (var i = 0;i < verticeMap.length;i++) {
vertices.push(points[verticeMap[i][0]][0]);
vertices.push(points[verticeMap[i][0]][1]);
vertices.push(points[verticeMap[i][1]][0]);
vertices.push(points[verticeMap[i][1]][1]);
vertices.push(points[verticeMap[i][1]][0]);
vertices.push(points[verticeMap[i][1]][1]);
vertices.push(points[verticeMap[i][2]][0]);
vertices.push(points[verticeMap[i][2]][1]);
vertices.push(points[verticeMap[i][2]][0]);
vertices.push(points[verticeMap[i][2]][1]);
vertices.push(points[verticeMap[i][0]][0]);
vertices.push(points[verticeMap[i][0]][1]);
}
var positionLocation = gl.getAttribLocation(gridProgram, "a_position");
// Create a buffer for position of the vertices (lines)
gl.bindBuffer(gl.ARRAY_BUFFER, gridCoordbuffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
// Draw the lines
gl.drawArrays(gl.LINES, 0, numTriangles*6);
}
this.clear = function() {
gl.clear(gl.COLOR_BUFFER_BIT);
}
this.calculatePositions = function(parameters, useTransforms) {
var x, y, a, b;
var numParameters = parameters.length;
var positions = [];
for (var i = 0;i < pdmModel.patchModel.numPatches;i++) {
x = pdmModel.shapeModel.meanShape[i][0];
y = pdmModel.shapeModel.meanShape[i][1];
for (var j = 0;j < numParameters-4;j++) {
x += pdmModel.shapeModel.eigenVectors[(i*2)][j]*parameters[j+4];
y += pdmModel.shapeModel.eigenVectors[(i*2)+1][j]*parameters[j+4];
}
if (useTransforms) {
a = parameters[0]*x - parameters[1]*y + parameters[2];
b = parameters[0]*y + parameters[1]*x + parameters[3];
x += a;
y += b;
}
positions[i] = [x,y];
}
return positions;
}
}