/****************************************************************/ /* cs4496/7496: Computer Animation, Instructor: Jarek Rossignac */ /* Project P4: Morph */ /* */ /* Solution by */ /* Florian Hecht */ /* */ /* November 2006 */ /****************************************************************/ import processing.opengl.*; // comment out if not using OpenGL PImage image1; PImage image2; // mouse pt Mouse = new pt(0,0,0); // display boolean drawGrid = false; boolean drawPins = false; boolean drawLaplacians = false; boolean drawTwists = false; //int influenceMethod = 0; float gt = 0.0; boolean twistSecond = true; boolean drawSecond = true; boolean doTheAnimation = true; boolean playAnimation = false; int animationPhase = 0; // the mesh int WIDTH = 50; int HEIGHT = 50; pt[] mesh = new pt[WIDTH*HEIGHT]; vec[] displacement = new vec[WIDTH*HEIGHT]; boolean[] pinned = new boolean[WIDTH*HEIGHT]; vec[] laplacian = new vec[WIDTH*HEIGHT]; // calc laplacian vector at each vertex of the mesh // uses bi-cubic smoothing void calcLaplacian(int x, int y) { float t = 1; int i = y*WIDTH + x; if (pinned[i]) { laplacian[i].setTo(0, 0, 0); return; } float dw = width / WIDTH; float dh = height / HEIGHT; pt p = getFinalPoint(x , y , t); pt p1 = getFinalPoint(x-2, y , t); pt p2 = getFinalPoint(x-1, y , t); pt p3 = getFinalPoint(x+1, y , t); pt p4 = getFinalPoint(x+2, y , t); pt p5 = getFinalPoint(x , y-2, t); pt p6 = getFinalPoint(x , y-1, t); pt p7 = getFinalPoint(x , y+1, t); pt p8 = getFinalPoint(x , y+2, t); float ratio = (float)4 / (float)3; pt tmp1 = linear_ipol(linear_ipol(p1, p2, ratio), linear_ipol(p4, p3, ratio), (float)0.5); pt tmp2 = linear_ipol(linear_ipol(p5, p6, ratio), linear_ipol(p8, p7, ratio), (float)0.5); pt avg = linear_ipol(tmp1, tmp2, (float)0.5); vec tmp = p.vecTo(avg); laplacian[i].setTo(tmp.x / (float)width, tmp.y / (float)height, 0); } void tuck(int x, int y, float s) { int i = y*WIDTH + x; if (pinned[i]) return; displacement[i].addScaled(s, laplacian[i]); } void relaxMesh(boolean doTuck) { for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { calcLaplacian(x, y); } } if (doTuck) { for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { tuck(x, y, 0.5); } } } } pt getPoint(int x, int y) { return mesh[y*WIDTH + x]; } vec getDisplacement(int x, int y) { return displacement[y*WIDTH + x]; } pt getFinalPoint(int x, int y, float t) { if (x < 0) x = 0; if (x > WIDTH-1) x = WIDTH-1; if (y < 0) y = 0; if (y > HEIGHT-1) y = HEIGHT-1; pt p = mesh[y*WIDTH + x].make(); p.addScaledVec(t, displacement[y*WIDTH + x]); p.x = p.x*width; p.y = p.y*height; return p; } void drawPins(float t) { noStroke(); fill(255, 0, 0); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { if (pinned[y*WIDTH + x]) { pt p = getFinalPoint(x, y, t); p.show(5); } } } } void drawLaplacians(float t) { stroke(255, 0, 255); noFill(); beginShape(LINES); for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { if (!pinned[y*WIDTH + x]) { pt p = getFinalPoint(x, y, t); p.vert(); vec v = laplacian[y*WIDTH + x].make(); v.x *= width; v.y *= height; p.addScaledVec(10, v); p.vert(); } } } endShape(); } /* setup */ void setup() { size(600, 600, OPENGL); //for OpenGL use: void setup() { size(800, 800, OPENGL); //PFont font = loadFont("Courier-14.vlw"); //textFont(font, 12); // font for writing labels on screen // enable backface culling //((PGraphicsGL)g).triangle.setCulling(true); reset(); image1 = loadImage("flo_morph_bw.jpg"); // load image for texture image2 = loadImage("drstrangelove_morph_bw.jpg"); } void reset() { for (int y = 0; y < HEIGHT; y++) { for (int x = 0; x < WIDTH; x++) { mesh[y*HEIGHT + x] = new pt((float)x / (float)(WIDTH-1), (float)y / (float)(HEIGHT-1), 0); displacement[y*HEIGHT + x] = new vec(0, 0, 0); laplacian[y*HEIGHT + x] = new vec(0, 0, 0); if (y == 0 || y == 1 || y == HEIGHT-2 || y == HEIGHT-1) { pinned[y*HEIGHT + x] = true; } else { if (x == 0 || x == 1 || x == WIDTH-2 || x == WIDTH-1) { pinned[y*HEIGHT + x] = true; } } } } resetTwists(); } /* rendering loop */ void draw() { float t; background(0); sphereDetail(4); // this does the 3 phase morph sequence if (doTheAnimation) { float deltaT = 0.01; if (animationPhase != 1 && gt < 0.33) { loadTwists("tw1.tw"); image1 = loadImage("flo_morph_bw.jpg"); image2 = loadImage("drstrangelove_morph_bw.jpg"); drawSecond = false; animationPhase = 1; println("phase 1"); } if (animationPhase != 2 && gt >= 0.33 && gt < 0.66) { loadTwists("tw2.tw"); if (animationPhase != 1) { image1 = loadImage("flo_morph_bw.jpg"); image2 = loadImage("drstrangelove_morph_bw.jpg"); } drawSecond = true; animationPhase = 2; println("phase 2"); } if (animationPhase != 3 && gt >= 0.66) { loadTwists("tw3.tw"); if (animationPhase != 2) { image2 = loadImage("flo_morph_bw.jpg"); image1 = loadImage("drstrangelove_morph_bw.jpg"); } else { PImage tmp = image1; image1 = image2; image2 = tmp; } drawSecond = false; animationPhase = 3; println("phase 3"); } if (gt < 0.33) { t = 1.0 - (gt / 0.33); } else if (gt < 0.66) { t = (gt - 0.33) / 0.33; deltaT *= 2; // speed up because we have double the work & blending } else { t = (gt - 0.66) / 0.33; } if (playAnimation) gt = min(1.0, gt + deltaT); } else { t = gt; } if (drawSecond) drawReverseTwistedMesh(t, twistSecond); drawTwistedMesh(t, !twistSecond); if (drawGrid) drawTwistedGrid(t); if (drawPins) drawPins(t); if (drawLaplacians) drawLaplacians(gt); if (drawTwists) drawTwists(); } /* mouse control */ void mouseDragged() { dragTwist(); } void mousePressed() { Mouse.setToMouse(); checkTwistSelection(); } void mouseReleased() { releaseTwistSelection(); } /* keyboard control */ void keyPressed() { switch (key) { case ' ': reset(); break; case 'l': drawLaplacians = !drawLaplacians; break; case 't': drawTwists = !drawTwists; break; case 'g': drawGrid = !drawGrid; break; case 'p': drawPins = !drawPins; break; case 'a': gt = 0; break; case 's': gt = max(0, gt - 0.01); break; case 'd': gt = min(1, gt + 0.01); break; case 'f': gt = 1.0; break; case 'y': twistSecond = ! twistSecond; break; case 'x': drawSecond = !drawSecond; break; case 'c': doTheAnimation = !doTheAnimation; gt = 0; animationPhase = 0; break; case 'b': playAnimation = !playAnimation; break; case 'v': PImage tmp = image1; image1 = image2; image2 = tmp; break; case '1': loadTwists("tw1.tw"); break; case '4': saveTwists("tw1.tw"); break; case '2': loadTwists("tw2.tw"); break; case '5': saveTwists("tw2.tw"); break; case '3': loadTwists("tw3.tw"); break; case '6': saveTwists("tw3.tw"); break; } }