Homework
Your homework this week will be to modify
the simple animated scene below by one
that does more general
translation, rotation and scale
transformations.
Details on how to do this follow below, after the figure.
Next week we will start to tie things back
into WebGL,
but for now I'd like you everything in JavaScript,
by drawing lines on the HTML5 canvas
to represent the edges of 3D shapes.
If you select View Source in your browser, you will
be able to see the simple canvas declaration for the above figure:
<canvas id=exampleCanvas width=400 height=400 tabindex="1"></canvas>
This is followed by a JavaScript script,
which I have also listed below.
Your job is to replace the simple translation
matrix in that script by
more general software that implements
and demonstrates all the types of
matrix transformation primitives.
In the script listing below,
I have highlighted in red the part that you will need to replace.
NOTE: To make your code work, you will also need to
implement a 4×4 matrix multiply function.
If you are feeling ambitious,
you can create multiple cubes or other shapes,
such as your own version of a sphere or a cylinder or a torus.
As I mentioned in class, a torus can be described as a parametric
surface, by sweeping two angles θ and φ between
0 and 2π. Specifically:
x = (R + r cos φ) cos θ
y = (R + r cos φ) sin θ
z = r sin φ
where R is the radius of the large ring,
and r is the radius of the tube that circles that ring.
The JavaScript script that is animating the above figure for this document:
<script>
// GET THE CANVAS ELEMENT AND ITS DRAWING CONTEXT FROM THE DOCUMENT
var canvas = document.getElementById('exampleCanvas');
var context = canvas.getContext('2d');
// THE VERTICES OF A UNIT CUBE
var pts = [[-1,-1,-1],[ 1,-1,-1],[-1, 1,-1],[ 1, 1,-1],
[-1,-1, 1],[ 1,-1, 1],[-1, 1, 1],[ 1, 1, 1]];
// THE EDGES OF A UNIT CUBE (INDEXING INTO THE VERTICES)
var edges = [[0,1],[2,3],[4,5],[6,7],
[0,2],[1,3],[4,6],[5,7],
[0,4],[1,5],[2,6],[3,7]];
// YOUR FUNCTION THAT GETS CALLED EACH ANIMATION FRAME
function animate() {
// GET THE DIMENSIONS OF THE CANVAS
var w = canvas.width, h = canvas.height;
// CLEAR THE ENTIRE CANVAS
context.fillStyle = '#ffffff';
context.beginPath();
context.moveTo(0,0);
context.lineTo(w,0);
context.lineTo(w,h);
context.lineTo(0,h);
context.fill();
// CREATE THE MATRIX TRANSFORM FOR THIS ANIMATION FRAME.
////////////////////////////////////////////////////////////
// NOTE: THIS IS THE PART THAT YOU WILL BE REPLACING WITH
// MORE GENERAL KINDS OF TRANSFORMATIONS.
var x = Math.cos(time) / 2;
var y = Math.sin(time) / 2;
var matrix = [ 1,0,0,0, 0,1,0,0, 0,0,1,0, x,y,0,1 ];
////////////////////////////////////////////////////////////
// SET THE DRAWING COLOR TO BLACK
context.strokeStyle = '#000000';
// LOOP THROUGH THE EDGES OF THE CUBE
for (var i = 0 ; i < edges.length ; i++) {
// TRANSFORM THE EDGE'S TWO ENDPOINTS BY THE MATRIX
var p0 = transform(pts[edges[i][0]], matrix);
var p1 = transform(pts[edges[i][1]], matrix);
// ADD DEPTH PERSPECTIVE
var a = depthPerspective(p0);
var b = depthPerspective(p1);
// DRAW THE EDGE AS A 2D LINE ON THE CANVAS
context.beginPath();
context.moveTo(w/2 + w/4 * a[0], h/2 - w/4 * a[1]);
context.lineTo(w/2 + w/4 * b[0], h/2 - w/4 * b[1]);
context.stroke();
}
}
// TRANSFORM A POINT BY A MATRIX
function transform(p, m) {
return [ m[0] * p[0] + m[4] * p[1] + m[ 8] * p[2] + m[12],
m[1] * p[0] + m[5] * p[1] + m[ 9] * p[2] + m[13],
m[2] * p[0] + m[6] * p[1] + m[10] * p[2] + m[14]];
}
// APPLY A SIMPLE DEPTH PERSPECTIVE TRANSFORM
var focalLength = 8.0;
function depthPerspective(p) {
var pz = focalLength / (focalLength - p[2]);
return [p[0] * pz, p[1] * pz, pz];
}
//--- BOILERPLATE CODE TO SUPPORT ANIMATED DRAWING ON AN HTML CANVAS ---
var startTime = (new Date()).getTime(), time = startTime;
window.requestAnimFrame = (function(callback) {
return window.requestAnimationFrame ||
window.webkitRequestAnimationFrame ||
window.mozRequestAnimationFrame ||
window.oRequestAnimationFrame ||
window.msRequestAnimationFrame ||
function(callback) { window.setTimeout(callback, 1000/60); };
})();
function tick() {
time = ((new Date()).getTime() - startTime) / 1000;
animate();
requestAnimFrame(function() { tick(); });
}
tick();
//----------------------------------------------------------------------
</script>