forked from protonphoton/LJ
294 lines
8.9 KiB
JavaScript
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;
|
|
}
|
|
}
|