JavaScript
function Matrix() {
this.m = Array.prototype.concat.apply([], arguments);
}
function frustum(l, r, b, t, n, f) {
var m = new Matrix(
2 * n / (r - l),
0,
(r + l) / (r - l),
0,
0,
2 * n / (t - b),
(t + b) / (t - b),
0,
0,
0,
-(f + n) / (f - n),
-2 * f * n / (f - n),
0,
0,
-1,
0
);
return m;
}
function perspective(fovy, aspect, near, far) {
var y = Math.tan(fovy * Math.PI / 360) * near;
var x = y * aspect;
return frustum(-x, x, -y, y, near, far);
}
//from NDC to Screen space
function viewport(w, h) {
var depthRangeMin = 0;
var depthRangeMax = 1;
var depthRange = depthRangeMax - depthRangeMin;
var m = new Matrix(
w / 2, // scaling
0,
0,
0, // translation
0,
h / 2, // scaling
0,
0, // translation
0,
0,
depthRange / 2, // depthRange scaling to utilize depth buffer.
depthRangeMin + depthRange / 2, // translation
0,
0,
0,
1
);
return m;
}
function Vector3D(x, y, z, w) {
this.x = x || 0;
this.y = y || 0;
this.z = z || 0;
this.w = w || 1;
}
Vector3D.prototype.transform = function(matrix) {
var vector = new Vector3D(
matrix.m[0] *this.x + matrix.m[1] *this.y + matrix.m[2] *this.z + matrix.m[3] *this.w,
matrix.m[4] *this.x + matrix.m[5] *this.y + matrix.m[6] *this.z + matrix.m[7] *this.w,
matrix.m[8] *this.x + matrix.m[9] *this.y + matrix.m[10]*this.z + matrix.m[11]*this.w,
matrix.m[12]*this.x + matrix.m[13]*this.y + matrix.m[14]*this.z + matrix.m[15]*this.w
);
return vector;
};
//"perspective divide" to create 3D effect
Vector3D.prototype.normalize = function() {
var vector = new Vector3D(this.x / this.w,
this.y / this.w,
this.z / this.w,
1);
return vector;
};
Vector3D.prototype.toString = function() {
return "x=" + this.x.toFixed(4) + ", y=" + this.y.toFixed(4) + ", z=" +...