mirror of
https://github.com/photonstorm/phaser
synced 2024-11-26 22:52:14 +00:00
Testing out a 3D Camera
This commit is contained in:
parent
fb81fa514b
commit
83d985b4b2
17 changed files with 2809 additions and 12 deletions
172
v3/src/camera3d/Camera3D.js
Normal file
172
v3/src/camera3d/Camera3D.js
Normal file
|
@ -0,0 +1,172 @@
|
|||
var Class = require('../utils/Class');
|
||||
|
||||
var util = require('./vecutil');
|
||||
|
||||
var Vector2 = require('./vecmath/Vector2');
|
||||
var Vector3 = require('./vecmath/Vector3');
|
||||
var Vector4 = require('./vecmath/Vector4');
|
||||
var Matrix4 = require('./vecmath/Matrix4');
|
||||
|
||||
var tmpVec3 = new Vector3();
|
||||
var tmpVec4 = new Vector4();
|
||||
|
||||
/**
|
||||
* Abstract base class for cameras to implement.
|
||||
* @class Camera
|
||||
* @abstract
|
||||
*/
|
||||
var Camera3D = new Class({
|
||||
|
||||
initialize: function() {
|
||||
this.direction = new Vector3(0, 0, -1);
|
||||
this.up = new Vector3(0, 1, 0);
|
||||
this.position = new Vector3();
|
||||
|
||||
this.projection = new Matrix4();
|
||||
this.view = new Matrix4();
|
||||
this.combined = new Matrix4();
|
||||
this.invProjectionView = new Matrix4();
|
||||
|
||||
this.near = 1;
|
||||
this.far = 100;
|
||||
|
||||
this.ray = {
|
||||
origin: new Vector3(),
|
||||
direction: new Vector3()
|
||||
};
|
||||
|
||||
this.viewportWidth = 0;
|
||||
this.viewportHeight = 0;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets the width and height of the viewport. Does not
|
||||
* update any matrices.
|
||||
*
|
||||
* @method setViewport
|
||||
* @param {Number} width the viewport width
|
||||
* @param {Number} height the viewport height
|
||||
*/
|
||||
setViewport: function(width, height) {
|
||||
this.viewportWidth = width;
|
||||
this.viewportHeight = height;
|
||||
},
|
||||
|
||||
/**
|
||||
* Translates this camera by a specified Vector3 object
|
||||
* or x, y, z parameters. Any undefined x y z values will
|
||||
* default to zero, leaving that component unaffected.
|
||||
*
|
||||
* @param {[type]} vec [description]
|
||||
* @return {[type]} [description]
|
||||
*/
|
||||
translate: function(x, y, z) {
|
||||
if (typeof x === "object") {
|
||||
this.position.x += x.x || 0;
|
||||
this.position.y += x.y || 0;
|
||||
this.position.z += x.z || 0;
|
||||
} else {
|
||||
this.position.x += x || 0;
|
||||
this.position.y += y || 0;
|
||||
this.position.z += z || 0;
|
||||
}
|
||||
},
|
||||
|
||||
lookAt: function(x, y, z) {
|
||||
var dir = this.direction,
|
||||
up = this.up;
|
||||
|
||||
if (typeof x === "object") {
|
||||
dir.copy(x);
|
||||
} else {
|
||||
dir.set(x, y, z);
|
||||
}
|
||||
|
||||
dir.sub(this.position).normalize();
|
||||
|
||||
//calculate right vector
|
||||
tmpVec3.copy(dir).cross(up).normalize();
|
||||
|
||||
//calculate up vector
|
||||
up.copy(tmpVec3).cross(dir).normalize();
|
||||
},
|
||||
|
||||
rotate: function(radians, axis) {
|
||||
util.rotate(this.direction, axis, radians);
|
||||
util.rotate(this.up, axis, radians);
|
||||
},
|
||||
|
||||
rotateAround: function(point, radians, axis) {
|
||||
tmpVec.copy(point).sub(this.position);
|
||||
this.translate(tmpVec);
|
||||
this.rotate(radians, axis);
|
||||
this.translate(tmpVec.negate());
|
||||
},
|
||||
|
||||
project: function(vec, out) {
|
||||
if (!out)
|
||||
out = new Vector4();
|
||||
|
||||
//TODO: support viewport XY
|
||||
var viewportWidth = this.viewportWidth,
|
||||
viewportHeight = this.viewportHeight,
|
||||
n = Camera3D.NEAR_RANGE,
|
||||
f = Camera3D.FAR_RANGE;
|
||||
|
||||
// for useful Z and W values we should do the usual steps...
|
||||
// clip space -> NDC -> window coords
|
||||
|
||||
//implicit 1.0 for w component
|
||||
tmpVec4.set(vec.x, vec.y, vec.z, 1.0);
|
||||
|
||||
//transform into clip space
|
||||
tmpVec4.transformMat4(this.combined);
|
||||
|
||||
//now into NDC
|
||||
tmpVec4.x = tmpVec4.x / tmpVec4.w;
|
||||
tmpVec4.y = tmpVec4.y / tmpVec4.w;
|
||||
tmpVec4.z = tmpVec4.z / tmpVec4.w;
|
||||
|
||||
//and finally into window coordinates
|
||||
out.x = viewportWidth / 2 * tmpVec4.x + (0 + viewportWidth / 2);
|
||||
out.y = viewportHeight / 2 * tmpVec4.y + (0 + viewportHeight / 2);
|
||||
out.z = (f - n) / 2 * tmpVec4.z + (f + n) / 2;
|
||||
|
||||
//if the out vector has a fourth component, we also store (1/clip.w)
|
||||
//same idea as gl_FragCoord.w
|
||||
if (out.w === 0 || out.w)
|
||||
out.w = 1 / tmpVec4.w;
|
||||
|
||||
return out;
|
||||
},
|
||||
|
||||
unproject: function(vec, out) {
|
||||
if (!out)
|
||||
out = new Vector3();
|
||||
|
||||
var viewport = tmpVec4.set(0, 0, this.viewportWidth, this.viewportHeight);
|
||||
return out.copy(vec).unproject(viewport, this.invProjectionView);
|
||||
},
|
||||
|
||||
getPickRay: function(x, y) {
|
||||
var origin = this.ray.origin.set(x, y, 0),
|
||||
direction = this.ray.direction.set(x, y, 1),
|
||||
viewport = tmpVec4.set(0, 0, this.viewportWidth, this.viewportHeight),
|
||||
mtx = this.invProjectionView;
|
||||
|
||||
origin.unproject(viewport, mtx);
|
||||
direction.unproject(viewport, mtx);
|
||||
|
||||
direction.sub(origin).normalize();
|
||||
return this.ray;
|
||||
},
|
||||
|
||||
update: function() {
|
||||
//left empty for subclasses
|
||||
}
|
||||
});
|
||||
|
||||
Camera3D.FAR_RANGE = 1.0;
|
||||
Camera3D.NEAR_RANGE = 0.0;
|
||||
|
||||
module.exports = Camera3D;
|
82
v3/src/camera3d/OrthographicCamera.js
Normal file
82
v3/src/camera3d/OrthographicCamera.js
Normal file
|
@ -0,0 +1,82 @@
|
|||
var Class = require('../utils/Class');
|
||||
|
||||
var Vector3 = require('./vecmath/Vector3');
|
||||
var Vector4 = require('./vecmath/Vector4');
|
||||
var Matrix4 = require('./vecmath/Matrix4');
|
||||
|
||||
var Camera = require('./Camera3D');
|
||||
|
||||
var tmpVec3 = new Vector3();
|
||||
|
||||
var OrthographicCamera = new Class({
|
||||
|
||||
Extends: Camera,
|
||||
|
||||
zoom: {
|
||||
|
||||
set: function(v) {
|
||||
if (typeof v !== 'number')
|
||||
throw new Error("zoom must be a number");
|
||||
this._zoom = v;
|
||||
},
|
||||
|
||||
get: function() {
|
||||
return this._zoom;
|
||||
}
|
||||
},
|
||||
|
||||
initialize: function(viewportWidth, viewportHeight) {
|
||||
Camera.call(this);
|
||||
this.viewportWidth = viewportWidth||0;
|
||||
this.viewportHeight = viewportHeight||0;
|
||||
|
||||
this._zoom = 1.0;
|
||||
this.near = 0;
|
||||
this.update();
|
||||
},
|
||||
|
||||
setToOrtho: function(yDown, viewportWidth, viewportHeight) {
|
||||
var zoom = this.zoom;
|
||||
viewportWidth = typeof viewportWidth === "number" ? viewportWidth : this.viewportWidth;
|
||||
viewportHeight = typeof viewportHeight === "number" ? viewportHeight : this.viewportHeight;
|
||||
|
||||
this.up.set(0, yDown ? -1 : 1, 0);
|
||||
this.direction.set(0, 0, yDown ? 1 : -1);
|
||||
this.position.set(zoom * viewportWidth / 2, zoom * viewportHeight / 2, 0);
|
||||
|
||||
this.viewportWidth = viewportWidth;
|
||||
this.viewportHeight = viewportHeight;
|
||||
this.update();
|
||||
},
|
||||
|
||||
update: function() {
|
||||
//TODO: support x/y offset
|
||||
var w = this.viewportWidth,
|
||||
h = this.viewportHeight,
|
||||
near = Math.abs(this.near),
|
||||
far = Math.abs(this.far),
|
||||
zoom = this.zoom;
|
||||
|
||||
if (w===0||h===0) {
|
||||
//What to do here... hmm ?
|
||||
return;
|
||||
}
|
||||
|
||||
this.projection.ortho(
|
||||
zoom * -w / 2, zoom * w / 2,
|
||||
zoom * -h / 2, zoom * h / 2,
|
||||
near, far);
|
||||
|
||||
//build the view matrix
|
||||
tmpVec3.copy(this.position).add(this.direction);
|
||||
this.view.lookAt(this.position, tmpVec3, this.up);
|
||||
|
||||
//projection * view matrix
|
||||
this.combined.copy(this.projection).mul(this.view);
|
||||
|
||||
//invert combined matrix, used for unproject
|
||||
this.invProjectionView.copy(this.combined).invert();
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = OrthographicCamera;
|
136
v3/src/camera3d/PerspectiveCamera.js
Normal file
136
v3/src/camera3d/PerspectiveCamera.js
Normal file
|
@ -0,0 +1,136 @@
|
|||
var Class = require('../utils/Class');
|
||||
|
||||
var Matrix4 = require('./vecmath/Matrix4');
|
||||
var Vector2 = require('./vecmath/Vector2');
|
||||
var Vector3 = require('./vecmath/Vector3');
|
||||
var Camera = require('./Camera3D');
|
||||
|
||||
var tmpVec3 = new Vector3();
|
||||
|
||||
var PerspectiveCamera = new Class({
|
||||
|
||||
Extends: Camera,
|
||||
|
||||
//fov in RADIANS!
|
||||
initialize: function(fieldOfView, viewportWidth, viewportHeight) {
|
||||
Camera.call(this);
|
||||
this.viewportWidth = viewportWidth;
|
||||
this.viewportHeight = viewportHeight;
|
||||
|
||||
this.fieldOfView = fieldOfView;
|
||||
this.update();
|
||||
},
|
||||
|
||||
update: function() {
|
||||
var aspect = this.viewportWidth / this.viewportHeight;
|
||||
|
||||
//create a perspective matrix for our camera
|
||||
this.projection.perspective(this.fieldOfView, aspect,
|
||||
Math.abs(this.near), Math.abs(this.far));
|
||||
|
||||
//build the view matrix
|
||||
tmpVec3.copy(this.position).add(this.direction);
|
||||
this.view.lookAt(this.position, tmpVec3, this.up);
|
||||
|
||||
//projection * view matrix
|
||||
this.combined.copy(this.projection).mul(this.view);
|
||||
|
||||
//invert combined matrix, used for unproject
|
||||
this.invProjectionView.copy(this.combined).invert();
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = PerspectiveCamera;
|
||||
|
||||
|
||||
|
||||
/*
|
||||
TODO: Billboarding should be moved to a separate module.
|
||||
|
||||
updateBillboardMatrix: function() {
|
||||
if (!dirvec) {
|
||||
dirvec = new Vector3();
|
||||
rightvec = new Vector3();
|
||||
billboardMatrix = new Matrix4();
|
||||
}
|
||||
|
||||
|
||||
var dir = dirvec.set(this.direction).negate();
|
||||
|
||||
// Better view-aligned billboards might use this:
|
||||
// var dir = tmp.set(camera.position).sub(p).normalize();
|
||||
|
||||
var right = rightvec.set(this.up).cross(dir).normalize();
|
||||
var up = tmpVec3.set(dir).cross(right).normalize();
|
||||
|
||||
var out = billboardMatrix.val;
|
||||
out[0] = right.x;
|
||||
out[1] = right.y;
|
||||
out[2] = right.z;
|
||||
out[3] = 0;
|
||||
out[4] = up.x;
|
||||
out[5] = up.y;
|
||||
out[6] = up.z;
|
||||
out[7] = 0;
|
||||
out[8] = dir.x;
|
||||
out[9] = dir.y;
|
||||
out[10] = dir.z;
|
||||
out[11] = 0;
|
||||
out[12] = 0;
|
||||
out[13] = 0;
|
||||
out[14] = 0;
|
||||
out[15] = 1;
|
||||
|
||||
this.billboardMatrixDirty = false;
|
||||
},
|
||||
|
||||
|
||||
* This is a utility function for canvas 3D rendering,
|
||||
* which determines the "point size" of a camera-facing
|
||||
* sprite billboard given its 3D world position
|
||||
* (origin at center of sprite) and its world width
|
||||
* and height in x/y.
|
||||
*
|
||||
* We place into the output Vector2 the scaled width
|
||||
* and height. If no `out` is specified, a new Vector2
|
||||
* will be created for convenience (this should be avoided
|
||||
* in tight loops).
|
||||
*
|
||||
* @param {Vector3} vec the position of the 3D sprite
|
||||
* @param {Vector2} size the x and y dimensions of the sprite
|
||||
* @param {Vector2} out the result, scaled x and y dimensions in 3D space
|
||||
* @return {Vector2} returns the out parameter, or a new Vector2 if none was given
|
||||
|
||||
getPointSize: function(vec, size, out) {
|
||||
//TODO: optimize this with a simple distance calculation:
|
||||
//https://developer.valvesoftware.com/wiki/Field_of_View
|
||||
|
||||
if (!out)
|
||||
out = new Vector2();
|
||||
|
||||
if (this.billboardMatrixDirty)
|
||||
this.updateBillboardMatrix();
|
||||
|
||||
var tmp = tmpVec3;
|
||||
|
||||
var dx = size.x/2;
|
||||
var dy = size.y/2;
|
||||
|
||||
tmp.set(-dx, -dy, 0).transformMat4(billboardMatrix).add(vec);
|
||||
this.project(tmp, tmp);
|
||||
|
||||
var tlx = tmp.x;
|
||||
var tly = tmp.y;
|
||||
|
||||
tmp.set(dx, dy, 0).transformMat4(billboardMatrix).add(vec);
|
||||
this.project(tmp, tmp);
|
||||
|
||||
var brx = tmp.x;
|
||||
var bry = tmp.y;
|
||||
|
||||
var w = Math.abs(brx - tlx);
|
||||
var h = Math.abs(bry - tly);
|
||||
return out.set(w, h);
|
||||
},
|
||||
|
||||
*/
|
6
v3/src/camera3d/index.js
Normal file
6
v3/src/camera3d/index.js
Normal file
|
@ -0,0 +1,6 @@
|
|||
module.exports = {
|
||||
vecutil: require('./vecutil'),
|
||||
Camera3D: require('./Camera3D'),
|
||||
PerspectiveCamera: require('./PerspectiveCamera'),
|
||||
OrthographicCamera: require('./OrthographicCamera')
|
||||
};
|
312
v3/src/camera3d/vecmath/Matrix3.js
Normal file
312
v3/src/camera3d/vecmath/Matrix3.js
Normal file
|
@ -0,0 +1,312 @@
|
|||
var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array;
|
||||
|
||||
function Matrix3(m) {
|
||||
this.val = new ARRAY_TYPE(9);
|
||||
|
||||
if (m) { //assume Matrix3 with val
|
||||
this.copy(m);
|
||||
} else { //default to identity
|
||||
this.idt();
|
||||
}
|
||||
}
|
||||
|
||||
var mat3 = Matrix3.prototype;
|
||||
|
||||
mat3.clone = function() {
|
||||
return new Matrix3(this);
|
||||
};
|
||||
|
||||
mat3.set = function(otherMat) {
|
||||
return this.copy(otherMat);
|
||||
};
|
||||
|
||||
mat3.copy = function(otherMat) {
|
||||
var out = this.val,
|
||||
a = otherMat.val;
|
||||
out[0] = a[0];
|
||||
out[1] = a[1];
|
||||
out[2] = a[2];
|
||||
out[3] = a[3];
|
||||
out[4] = a[4];
|
||||
out[5] = a[5];
|
||||
out[6] = a[6];
|
||||
out[7] = a[7];
|
||||
out[8] = a[8];
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.fromMat4 = function(m) {
|
||||
var a = m.val,
|
||||
out = this.val;
|
||||
out[0] = a[0];
|
||||
out[1] = a[1];
|
||||
out[2] = a[2];
|
||||
out[3] = a[4];
|
||||
out[4] = a[5];
|
||||
out[5] = a[6];
|
||||
out[6] = a[8];
|
||||
out[7] = a[9];
|
||||
out[8] = a[10];
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.fromArray = function(a) {
|
||||
var out = this.val;
|
||||
out[0] = a[0];
|
||||
out[1] = a[1];
|
||||
out[2] = a[2];
|
||||
out[3] = a[3];
|
||||
out[4] = a[4];
|
||||
out[5] = a[5];
|
||||
out[6] = a[6];
|
||||
out[7] = a[7];
|
||||
out[8] = a[8];
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.identity = function() {
|
||||
var out = this.val;
|
||||
out[0] = 1;
|
||||
out[1] = 0;
|
||||
out[2] = 0;
|
||||
out[3] = 0;
|
||||
out[4] = 1;
|
||||
out[5] = 0;
|
||||
out[6] = 0;
|
||||
out[7] = 0;
|
||||
out[8] = 1;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.transpose = function() {
|
||||
var a = this.val,
|
||||
a01 = a[1],
|
||||
a02 = a[2],
|
||||
a12 = a[5];
|
||||
a[1] = a[3];
|
||||
a[2] = a[6];
|
||||
a[3] = a01;
|
||||
a[5] = a[7];
|
||||
a[6] = a02;
|
||||
a[7] = a12;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.invert = function() {
|
||||
var a = this.val,
|
||||
a00 = a[0], a01 = a[1], a02 = a[2],
|
||||
a10 = a[3], a11 = a[4], a12 = a[5],
|
||||
a20 = a[6], a21 = a[7], a22 = a[8],
|
||||
|
||||
b01 = a22 * a11 - a12 * a21,
|
||||
b11 = -a22 * a10 + a12 * a20,
|
||||
b21 = a21 * a10 - a11 * a20,
|
||||
|
||||
// Calculate the determinant
|
||||
det = a00 * b01 + a01 * b11 + a02 * b21;
|
||||
|
||||
if (!det) {
|
||||
return null;
|
||||
}
|
||||
det = 1.0 / det;
|
||||
|
||||
a[0] = b01 * det;
|
||||
a[1] = (-a22 * a01 + a02 * a21) * det;
|
||||
a[2] = (a12 * a01 - a02 * a11) * det;
|
||||
a[3] = b11 * det;
|
||||
a[4] = (a22 * a00 - a02 * a20) * det;
|
||||
a[5] = (-a12 * a00 + a02 * a10) * det;
|
||||
a[6] = b21 * det;
|
||||
a[7] = (-a21 * a00 + a01 * a20) * det;
|
||||
a[8] = (a11 * a00 - a01 * a10) * det;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.adjoint = function() {
|
||||
var a = this.val,
|
||||
a00 = a[0], a01 = a[1], a02 = a[2],
|
||||
a10 = a[3], a11 = a[4], a12 = a[5],
|
||||
a20 = a[6], a21 = a[7], a22 = a[8];
|
||||
|
||||
a[0] = (a11 * a22 - a12 * a21);
|
||||
a[1] = (a02 * a21 - a01 * a22);
|
||||
a[2] = (a01 * a12 - a02 * a11);
|
||||
a[3] = (a12 * a20 - a10 * a22);
|
||||
a[4] = (a00 * a22 - a02 * a20);
|
||||
a[5] = (a02 * a10 - a00 * a12);
|
||||
a[6] = (a10 * a21 - a11 * a20);
|
||||
a[7] = (a01 * a20 - a00 * a21);
|
||||
a[8] = (a00 * a11 - a01 * a10);
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.determinant = function() {
|
||||
var a = this.val,
|
||||
a00 = a[0], a01 = a[1], a02 = a[2],
|
||||
a10 = a[3], a11 = a[4], a12 = a[5],
|
||||
a20 = a[6], a21 = a[7], a22 = a[8];
|
||||
|
||||
return a00 * (a22 * a11 - a12 * a21) + a01 * (-a22 * a10 + a12 * a20) + a02 * (a21 * a10 - a11 * a20);
|
||||
};
|
||||
|
||||
mat3.multiply = function(otherMat) {
|
||||
var a = this.val,
|
||||
b = otherMat.val,
|
||||
a00 = a[0], a01 = a[1], a02 = a[2],
|
||||
a10 = a[3], a11 = a[4], a12 = a[5],
|
||||
a20 = a[6], a21 = a[7], a22 = a[8],
|
||||
|
||||
b00 = b[0], b01 = b[1], b02 = b[2],
|
||||
b10 = b[3], b11 = b[4], b12 = b[5],
|
||||
b20 = b[6], b21 = b[7], b22 = b[8];
|
||||
|
||||
a[0] = b00 * a00 + b01 * a10 + b02 * a20;
|
||||
a[1] = b00 * a01 + b01 * a11 + b02 * a21;
|
||||
a[2] = b00 * a02 + b01 * a12 + b02 * a22;
|
||||
|
||||
a[3] = b10 * a00 + b11 * a10 + b12 * a20;
|
||||
a[4] = b10 * a01 + b11 * a11 + b12 * a21;
|
||||
a[5] = b10 * a02 + b11 * a12 + b12 * a22;
|
||||
|
||||
a[6] = b20 * a00 + b21 * a10 + b22 * a20;
|
||||
a[7] = b20 * a01 + b21 * a11 + b22 * a21;
|
||||
a[8] = b20 * a02 + b21 * a12 + b22 * a22;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.translate = function(v) {
|
||||
var a = this.val,
|
||||
x = v.x, y = v.y;
|
||||
a[6] = x * a[0] + y * a[3] + a[6];
|
||||
a[7] = x * a[1] + y * a[4] + a[7];
|
||||
a[8] = x * a[2] + y * a[5] + a[8];
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.rotate = function(rad) {
|
||||
var a = this.val,
|
||||
a00 = a[0], a01 = a[1], a02 = a[2],
|
||||
a10 = a[3], a11 = a[4], a12 = a[5],
|
||||
|
||||
s = Math.sin(rad),
|
||||
c = Math.cos(rad);
|
||||
|
||||
a[0] = c * a00 + s * a10;
|
||||
a[1] = c * a01 + s * a11;
|
||||
a[2] = c * a02 + s * a12;
|
||||
|
||||
a[3] = c * a10 - s * a00;
|
||||
a[4] = c * a11 - s * a01;
|
||||
a[5] = c * a12 - s * a02;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.scale = function(v) {
|
||||
var a = this.val,
|
||||
x = v.x,
|
||||
y = v.y;
|
||||
|
||||
a[0] = x * a[0];
|
||||
a[1] = x * a[1];
|
||||
a[2] = x * a[2];
|
||||
|
||||
a[3] = y * a[3];
|
||||
a[4] = y * a[4];
|
||||
a[5] = y * a[5];
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.fromQuat = function(q) {
|
||||
var x = q.x, y = q.y, z = q.z, w = q.w,
|
||||
x2 = x + x,
|
||||
y2 = y + y,
|
||||
z2 = z + z,
|
||||
|
||||
xx = x * x2,
|
||||
xy = x * y2,
|
||||
xz = x * z2,
|
||||
yy = y * y2,
|
||||
yz = y * z2,
|
||||
zz = z * z2,
|
||||
wx = w * x2,
|
||||
wy = w * y2,
|
||||
wz = w * z2,
|
||||
|
||||
out = this.val;
|
||||
|
||||
out[0] = 1 - (yy + zz);
|
||||
out[3] = xy + wz;
|
||||
out[6] = xz - wy;
|
||||
|
||||
out[1] = xy - wz;
|
||||
out[4] = 1 - (xx + zz);
|
||||
out[7] = yz + wx;
|
||||
|
||||
out[2] = xz + wy;
|
||||
out[5] = yz - wx;
|
||||
out[8] = 1 - (xx + yy);
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.normalFromMat4 = function(m) {
|
||||
var a = m.val,
|
||||
out = this.val,
|
||||
|
||||
a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
|
||||
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
|
||||
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
|
||||
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
|
||||
|
||||
b00 = a00 * a11 - a01 * a10,
|
||||
b01 = a00 * a12 - a02 * a10,
|
||||
b02 = a00 * a13 - a03 * a10,
|
||||
b03 = a01 * a12 - a02 * a11,
|
||||
b04 = a01 * a13 - a03 * a11,
|
||||
b05 = a02 * a13 - a03 * a12,
|
||||
b06 = a20 * a31 - a21 * a30,
|
||||
b07 = a20 * a32 - a22 * a30,
|
||||
b08 = a20 * a33 - a23 * a30,
|
||||
b09 = a21 * a32 - a22 * a31,
|
||||
b10 = a21 * a33 - a23 * a31,
|
||||
b11 = a22 * a33 - a23 * a32,
|
||||
|
||||
// Calculate the determinant
|
||||
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
|
||||
|
||||
if (!det) {
|
||||
return null;
|
||||
}
|
||||
det = 1.0 / det;
|
||||
|
||||
out[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
|
||||
out[1] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
|
||||
out[2] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
|
||||
|
||||
out[3] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
|
||||
out[4] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
|
||||
out[5] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
|
||||
|
||||
out[6] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
|
||||
out[7] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
|
||||
out[8] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat3.mul = mat3.multiply;
|
||||
|
||||
mat3.idt = mat3.identity;
|
||||
|
||||
//This is handy for Pool utilities, to "reset" a
|
||||
//shared object to its default state
|
||||
mat3.reset = mat3.idt;
|
||||
|
||||
mat3.toString = function() {
|
||||
var a = this.val;
|
||||
return 'Matrix3(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' +
|
||||
a[3] + ', ' + a[4] + ', ' + a[5] + ', ' +
|
||||
a[6] + ', ' + a[7] + ', ' + a[8] + ')';
|
||||
};
|
||||
|
||||
mat3.str = mat3.toString;
|
||||
|
||||
module.exports = Matrix3;
|
690
v3/src/camera3d/vecmath/Matrix4.js
Normal file
690
v3/src/camera3d/vecmath/Matrix4.js
Normal file
|
@ -0,0 +1,690 @@
|
|||
var ARRAY_TYPE = typeof Float32Array !== "undefined" ? Float32Array : Array;
|
||||
var EPSILON = 0.000001;
|
||||
|
||||
function Matrix4(m) {
|
||||
this.val = new ARRAY_TYPE(16);
|
||||
|
||||
if (m) { //assume Matrix4 with val
|
||||
this.copy(m);
|
||||
} else { //default to identity
|
||||
this.idt();
|
||||
}
|
||||
}
|
||||
|
||||
var mat4 = Matrix4.prototype;
|
||||
|
||||
mat4.clone = function() {
|
||||
return new Matrix4(this);
|
||||
};
|
||||
|
||||
mat4.set = function(otherMat) {
|
||||
return this.copy(otherMat);
|
||||
};
|
||||
|
||||
mat4.copy = function(otherMat) {
|
||||
var out = this.val,
|
||||
a = otherMat.val;
|
||||
out[0] = a[0];
|
||||
out[1] = a[1];
|
||||
out[2] = a[2];
|
||||
out[3] = a[3];
|
||||
out[4] = a[4];
|
||||
out[5] = a[5];
|
||||
out[6] = a[6];
|
||||
out[7] = a[7];
|
||||
out[8] = a[8];
|
||||
out[9] = a[9];
|
||||
out[10] = a[10];
|
||||
out[11] = a[11];
|
||||
out[12] = a[12];
|
||||
out[13] = a[13];
|
||||
out[14] = a[14];
|
||||
out[15] = a[15];
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.fromArray = function(a) {
|
||||
var out = this.val;
|
||||
out[0] = a[0];
|
||||
out[1] = a[1];
|
||||
out[2] = a[2];
|
||||
out[3] = a[3];
|
||||
out[4] = a[4];
|
||||
out[5] = a[5];
|
||||
out[6] = a[6];
|
||||
out[7] = a[7];
|
||||
out[8] = a[8];
|
||||
out[9] = a[9];
|
||||
out[10] = a[10];
|
||||
out[11] = a[11];
|
||||
out[12] = a[12];
|
||||
out[13] = a[13];
|
||||
out[14] = a[14];
|
||||
out[15] = a[15];
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.identity = function() {
|
||||
var out = this.val;
|
||||
out[0] = 1;
|
||||
out[1] = 0;
|
||||
out[2] = 0;
|
||||
out[3] = 0;
|
||||
out[4] = 0;
|
||||
out[5] = 1;
|
||||
out[6] = 0;
|
||||
out[7] = 0;
|
||||
out[8] = 0;
|
||||
out[9] = 0;
|
||||
out[10] = 1;
|
||||
out[11] = 0;
|
||||
out[12] = 0;
|
||||
out[13] = 0;
|
||||
out[14] = 0;
|
||||
out[15] = 1;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.transpose = function() {
|
||||
var a = this.val,
|
||||
a01 = a[1], a02 = a[2], a03 = a[3],
|
||||
a12 = a[6], a13 = a[7],
|
||||
a23 = a[11];
|
||||
|
||||
a[1] = a[4];
|
||||
a[2] = a[8];
|
||||
a[3] = a[12];
|
||||
a[4] = a01;
|
||||
a[6] = a[9];
|
||||
a[7] = a[13];
|
||||
a[8] = a02;
|
||||
a[9] = a12;
|
||||
a[11] = a[14];
|
||||
a[12] = a03;
|
||||
a[13] = a13;
|
||||
a[14] = a23;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.invert = function() {
|
||||
var a = this.val,
|
||||
a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
|
||||
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
|
||||
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
|
||||
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
|
||||
|
||||
b00 = a00 * a11 - a01 * a10,
|
||||
b01 = a00 * a12 - a02 * a10,
|
||||
b02 = a00 * a13 - a03 * a10,
|
||||
b03 = a01 * a12 - a02 * a11,
|
||||
b04 = a01 * a13 - a03 * a11,
|
||||
b05 = a02 * a13 - a03 * a12,
|
||||
b06 = a20 * a31 - a21 * a30,
|
||||
b07 = a20 * a32 - a22 * a30,
|
||||
b08 = a20 * a33 - a23 * a30,
|
||||
b09 = a21 * a32 - a22 * a31,
|
||||
b10 = a21 * a33 - a23 * a31,
|
||||
b11 = a22 * a33 - a23 * a32,
|
||||
|
||||
// Calculate the determinant
|
||||
det = b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
|
||||
|
||||
if (!det) {
|
||||
return null;
|
||||
}
|
||||
det = 1.0 / det;
|
||||
|
||||
a[0] = (a11 * b11 - a12 * b10 + a13 * b09) * det;
|
||||
a[1] = (a02 * b10 - a01 * b11 - a03 * b09) * det;
|
||||
a[2] = (a31 * b05 - a32 * b04 + a33 * b03) * det;
|
||||
a[3] = (a22 * b04 - a21 * b05 - a23 * b03) * det;
|
||||
a[4] = (a12 * b08 - a10 * b11 - a13 * b07) * det;
|
||||
a[5] = (a00 * b11 - a02 * b08 + a03 * b07) * det;
|
||||
a[6] = (a32 * b02 - a30 * b05 - a33 * b01) * det;
|
||||
a[7] = (a20 * b05 - a22 * b02 + a23 * b01) * det;
|
||||
a[8] = (a10 * b10 - a11 * b08 + a13 * b06) * det;
|
||||
a[9] = (a01 * b08 - a00 * b10 - a03 * b06) * det;
|
||||
a[10] = (a30 * b04 - a31 * b02 + a33 * b00) * det;
|
||||
a[11] = (a21 * b02 - a20 * b04 - a23 * b00) * det;
|
||||
a[12] = (a11 * b07 - a10 * b09 - a12 * b06) * det;
|
||||
a[13] = (a00 * b09 - a01 * b07 + a02 * b06) * det;
|
||||
a[14] = (a31 * b01 - a30 * b03 - a32 * b00) * det;
|
||||
a[15] = (a20 * b03 - a21 * b01 + a22 * b00) * det;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.adjoint = function() {
|
||||
var a = this.val,
|
||||
a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
|
||||
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
|
||||
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
|
||||
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
|
||||
|
||||
a[0] = (a11 * (a22 * a33 - a23 * a32) - a21 * (a12 * a33 - a13 * a32) + a31 * (a12 * a23 - a13 * a22));
|
||||
a[1] = -(a01 * (a22 * a33 - a23 * a32) - a21 * (a02 * a33 - a03 * a32) + a31 * (a02 * a23 - a03 * a22));
|
||||
a[2] = (a01 * (a12 * a33 - a13 * a32) - a11 * (a02 * a33 - a03 * a32) + a31 * (a02 * a13 - a03 * a12));
|
||||
a[3] = -(a01 * (a12 * a23 - a13 * a22) - a11 * (a02 * a23 - a03 * a22) + a21 * (a02 * a13 - a03 * a12));
|
||||
a[4] = -(a10 * (a22 * a33 - a23 * a32) - a20 * (a12 * a33 - a13 * a32) + a30 * (a12 * a23 - a13 * a22));
|
||||
a[5] = (a00 * (a22 * a33 - a23 * a32) - a20 * (a02 * a33 - a03 * a32) + a30 * (a02 * a23 - a03 * a22));
|
||||
a[6] = -(a00 * (a12 * a33 - a13 * a32) - a10 * (a02 * a33 - a03 * a32) + a30 * (a02 * a13 - a03 * a12));
|
||||
a[7] = (a00 * (a12 * a23 - a13 * a22) - a10 * (a02 * a23 - a03 * a22) + a20 * (a02 * a13 - a03 * a12));
|
||||
a[8] = (a10 * (a21 * a33 - a23 * a31) - a20 * (a11 * a33 - a13 * a31) + a30 * (a11 * a23 - a13 * a21));
|
||||
a[9] = -(a00 * (a21 * a33 - a23 * a31) - a20 * (a01 * a33 - a03 * a31) + a30 * (a01 * a23 - a03 * a21));
|
||||
a[10] = (a00 * (a11 * a33 - a13 * a31) - a10 * (a01 * a33 - a03 * a31) + a30 * (a01 * a13 - a03 * a11));
|
||||
a[11] = -(a00 * (a11 * a23 - a13 * a21) - a10 * (a01 * a23 - a03 * a21) + a20 * (a01 * a13 - a03 * a11));
|
||||
a[12] = -(a10 * (a21 * a32 - a22 * a31) - a20 * (a11 * a32 - a12 * a31) + a30 * (a11 * a22 - a12 * a21));
|
||||
a[13] = (a00 * (a21 * a32 - a22 * a31) - a20 * (a01 * a32 - a02 * a31) + a30 * (a01 * a22 - a02 * a21));
|
||||
a[14] = -(a00 * (a11 * a32 - a12 * a31) - a10 * (a01 * a32 - a02 * a31) + a30 * (a01 * a12 - a02 * a11));
|
||||
a[15] = (a00 * (a11 * a22 - a12 * a21) - a10 * (a01 * a22 - a02 * a21) + a20 * (a01 * a12 - a02 * a11));
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.determinant = function () {
|
||||
var a = this.val,
|
||||
a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
|
||||
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
|
||||
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
|
||||
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15],
|
||||
|
||||
b00 = a00 * a11 - a01 * a10,
|
||||
b01 = a00 * a12 - a02 * a10,
|
||||
b02 = a00 * a13 - a03 * a10,
|
||||
b03 = a01 * a12 - a02 * a11,
|
||||
b04 = a01 * a13 - a03 * a11,
|
||||
b05 = a02 * a13 - a03 * a12,
|
||||
b06 = a20 * a31 - a21 * a30,
|
||||
b07 = a20 * a32 - a22 * a30,
|
||||
b08 = a20 * a33 - a23 * a30,
|
||||
b09 = a21 * a32 - a22 * a31,
|
||||
b10 = a21 * a33 - a23 * a31,
|
||||
b11 = a22 * a33 - a23 * a32;
|
||||
|
||||
// Calculate the determinant
|
||||
return b00 * b11 - b01 * b10 + b02 * b09 + b03 * b08 - b04 * b07 + b05 * b06;
|
||||
};
|
||||
|
||||
mat4.multiply = function(otherMat) {
|
||||
var a = this.val,
|
||||
b = otherMat.val,
|
||||
a00 = a[0], a01 = a[1], a02 = a[2], a03 = a[3],
|
||||
a10 = a[4], a11 = a[5], a12 = a[6], a13 = a[7],
|
||||
a20 = a[8], a21 = a[9], a22 = a[10], a23 = a[11],
|
||||
a30 = a[12], a31 = a[13], a32 = a[14], a33 = a[15];
|
||||
|
||||
// Cache only the current line of the second matrix
|
||||
var b0 = b[0], b1 = b[1], b2 = b[2], b3 = b[3];
|
||||
a[0] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
|
||||
a[1] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
|
||||
a[2] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
|
||||
a[3] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
|
||||
|
||||
b0 = b[4]; b1 = b[5]; b2 = b[6]; b3 = b[7];
|
||||
a[4] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
|
||||
a[5] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
|
||||
a[6] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
|
||||
a[7] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
|
||||
|
||||
b0 = b[8]; b1 = b[9]; b2 = b[10]; b3 = b[11];
|
||||
a[8] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
|
||||
a[9] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
|
||||
a[10] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
|
||||
a[11] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
|
||||
|
||||
b0 = b[12]; b1 = b[13]; b2 = b[14]; b3 = b[15];
|
||||
a[12] = b0*a00 + b1*a10 + b2*a20 + b3*a30;
|
||||
a[13] = b0*a01 + b1*a11 + b2*a21 + b3*a31;
|
||||
a[14] = b0*a02 + b1*a12 + b2*a22 + b3*a32;
|
||||
a[15] = b0*a03 + b1*a13 + b2*a23 + b3*a33;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.translate = function(v) {
|
||||
var x = v.x, y = v.y, z = v.z,
|
||||
a = this.val;
|
||||
a[12] = a[0] * x + a[4] * y + a[8] * z + a[12];
|
||||
a[13] = a[1] * x + a[5] * y + a[9] * z + a[13];
|
||||
a[14] = a[2] * x + a[6] * y + a[10] * z + a[14];
|
||||
a[15] = a[3] * x + a[7] * y + a[11] * z + a[15];
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.scale = function(v) {
|
||||
var x = v.x, y = v.y, z = v.z, a = this.val;
|
||||
|
||||
a[0] = a[0] * x;
|
||||
a[1] = a[1] * x;
|
||||
a[2] = a[2] * x;
|
||||
a[3] = a[3] * x;
|
||||
a[4] = a[4] * y;
|
||||
a[5] = a[5] * y;
|
||||
a[6] = a[6] * y;
|
||||
a[7] = a[7] * y;
|
||||
a[8] = a[8] * z;
|
||||
a[9] = a[9] * z;
|
||||
a[10] = a[10] * z;
|
||||
a[11] = a[11] * z;
|
||||
a[12] = a[12];
|
||||
a[13] = a[13];
|
||||
a[14] = a[14];
|
||||
a[15] = a[15];
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.rotate = function (rad, axis) {
|
||||
var a = this.val,
|
||||
x = axis.x, y = axis.y, z = axis.z,
|
||||
len = Math.sqrt(x * x + y * y + z * z),
|
||||
s, c, t,
|
||||
a00, a01, a02, a03,
|
||||
a10, a11, a12, a13,
|
||||
a20, a21, a22, a23,
|
||||
b00, b01, b02,
|
||||
b10, b11, b12,
|
||||
b20, b21, b22;
|
||||
|
||||
if (Math.abs(len) < EPSILON) { return null; }
|
||||
|
||||
len = 1 / len;
|
||||
x *= len;
|
||||
y *= len;
|
||||
z *= len;
|
||||
|
||||
s = Math.sin(rad);
|
||||
c = Math.cos(rad);
|
||||
t = 1 - c;
|
||||
|
||||
a00 = a[0]; a01 = a[1]; a02 = a[2]; a03 = a[3];
|
||||
a10 = a[4]; a11 = a[5]; a12 = a[6]; a13 = a[7];
|
||||
a20 = a[8]; a21 = a[9]; a22 = a[10]; a23 = a[11];
|
||||
|
||||
// Construct the elements of the rotation matrix
|
||||
b00 = x * x * t + c; b01 = y * x * t + z * s; b02 = z * x * t - y * s;
|
||||
b10 = x * y * t - z * s; b11 = y * y * t + c; b12 = z * y * t + x * s;
|
||||
b20 = x * z * t + y * s; b21 = y * z * t - x * s; b22 = z * z * t + c;
|
||||
|
||||
// Perform rotation-specific matrix multiplication
|
||||
a[0] = a00 * b00 + a10 * b01 + a20 * b02;
|
||||
a[1] = a01 * b00 + a11 * b01 + a21 * b02;
|
||||
a[2] = a02 * b00 + a12 * b01 + a22 * b02;
|
||||
a[3] = a03 * b00 + a13 * b01 + a23 * b02;
|
||||
a[4] = a00 * b10 + a10 * b11 + a20 * b12;
|
||||
a[5] = a01 * b10 + a11 * b11 + a21 * b12;
|
||||
a[6] = a02 * b10 + a12 * b11 + a22 * b12;
|
||||
a[7] = a03 * b10 + a13 * b11 + a23 * b12;
|
||||
a[8] = a00 * b20 + a10 * b21 + a20 * b22;
|
||||
a[9] = a01 * b20 + a11 * b21 + a21 * b22;
|
||||
a[10] = a02 * b20 + a12 * b21 + a22 * b22;
|
||||
a[11] = a03 * b20 + a13 * b21 + a23 * b22;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.rotateX = function(rad) {
|
||||
var a = this.val,
|
||||
s = Math.sin(rad),
|
||||
c = Math.cos(rad),
|
||||
a10 = a[4],
|
||||
a11 = a[5],
|
||||
a12 = a[6],
|
||||
a13 = a[7],
|
||||
a20 = a[8],
|
||||
a21 = a[9],
|
||||
a22 = a[10],
|
||||
a23 = a[11];
|
||||
|
||||
// Perform axis-specific matrix multiplication
|
||||
a[4] = a10 * c + a20 * s;
|
||||
a[5] = a11 * c + a21 * s;
|
||||
a[6] = a12 * c + a22 * s;
|
||||
a[7] = a13 * c + a23 * s;
|
||||
a[8] = a20 * c - a10 * s;
|
||||
a[9] = a21 * c - a11 * s;
|
||||
a[10] = a22 * c - a12 * s;
|
||||
a[11] = a23 * c - a13 * s;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.rotateY = function(rad) {
|
||||
var a = this.val,
|
||||
s = Math.sin(rad),
|
||||
c = Math.cos(rad),
|
||||
a00 = a[0],
|
||||
a01 = a[1],
|
||||
a02 = a[2],
|
||||
a03 = a[3],
|
||||
a20 = a[8],
|
||||
a21 = a[9],
|
||||
a22 = a[10],
|
||||
a23 = a[11];
|
||||
|
||||
// Perform axis-specific matrix multiplication
|
||||
a[0] = a00 * c - a20 * s;
|
||||
a[1] = a01 * c - a21 * s;
|
||||
a[2] = a02 * c - a22 * s;
|
||||
a[3] = a03 * c - a23 * s;
|
||||
a[8] = a00 * s + a20 * c;
|
||||
a[9] = a01 * s + a21 * c;
|
||||
a[10] = a02 * s + a22 * c;
|
||||
a[11] = a03 * s + a23 * c;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.rotateZ = function (rad) {
|
||||
var a = this.val,
|
||||
s = Math.sin(rad),
|
||||
c = Math.cos(rad),
|
||||
a00 = a[0],
|
||||
a01 = a[1],
|
||||
a02 = a[2],
|
||||
a03 = a[3],
|
||||
a10 = a[4],
|
||||
a11 = a[5],
|
||||
a12 = a[6],
|
||||
a13 = a[7];
|
||||
|
||||
// Perform axis-specific matrix multiplication
|
||||
a[0] = a00 * c + a10 * s;
|
||||
a[1] = a01 * c + a11 * s;
|
||||
a[2] = a02 * c + a12 * s;
|
||||
a[3] = a03 * c + a13 * s;
|
||||
a[4] = a10 * c - a00 * s;
|
||||
a[5] = a11 * c - a01 * s;
|
||||
a[6] = a12 * c - a02 * s;
|
||||
a[7] = a13 * c - a03 * s;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.fromRotationTranslation = function (q, v) {
|
||||
// Quaternion math
|
||||
var out = this.val,
|
||||
x = q.x, y = q.y, z = q.z, w = q.w,
|
||||
x2 = x + x,
|
||||
y2 = y + y,
|
||||
z2 = z + z,
|
||||
|
||||
xx = x * x2,
|
||||
xy = x * y2,
|
||||
xz = x * z2,
|
||||
yy = y * y2,
|
||||
yz = y * z2,
|
||||
zz = z * z2,
|
||||
wx = w * x2,
|
||||
wy = w * y2,
|
||||
wz = w * z2;
|
||||
|
||||
out[0] = 1 - (yy + zz);
|
||||
out[1] = xy + wz;
|
||||
out[2] = xz - wy;
|
||||
out[3] = 0;
|
||||
out[4] = xy - wz;
|
||||
out[5] = 1 - (xx + zz);
|
||||
out[6] = yz + wx;
|
||||
out[7] = 0;
|
||||
out[8] = xz + wy;
|
||||
out[9] = yz - wx;
|
||||
out[10] = 1 - (xx + yy);
|
||||
out[11] = 0;
|
||||
out[12] = v.x;
|
||||
out[13] = v.y;
|
||||
out[14] = v.z;
|
||||
out[15] = 1;
|
||||
return this;
|
||||
};
|
||||
|
||||
mat4.fromQuat = function (q) {
|
||||
var out = this.val,
|
||||
x = q.x, y = q.y, z = q.z, w = q.w,
|
||||
x2 = x + x,
|
||||
y2 = y + y,
|
||||
z2 = z + z,
|
||||
|
||||
xx = x * x2,
|
||||
xy = x * y2,
|
||||
xz = x * z2,
|
||||
yy = y * y2,
|
||||
yz = y * z2,
|
||||
zz = z * z2,
|
||||
wx = w * x2,
|
||||
wy = w * y2,
|
||||
wz = w * z2;
|
||||
|
||||
out[0] = 1 - (yy + zz);
|
||||
out[1] = xy + wz;
|
||||
out[2] = xz - wy;
|
||||
out[3] = 0;
|
||||
|
||||
out[4] = xy - wz;
|
||||
out[5] = 1 - (xx + zz);
|
||||
out[6] = yz + wx;
|
||||
out[7] = 0;
|
||||
|
||||
out[8] = xz + wy;
|
||||
out[9] = yz - wx;
|
||||
out[10] = 1 - (xx + yy);
|
||||
out[11] = 0;
|
||||
|
||||
out[12] = 0;
|
||||
out[13] = 0;
|
||||
out[14] = 0;
|
||||
out[15] = 1;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Generates a frustum matrix with the given bounds
|
||||
*
|
||||
* @param {Number} left Left bound of the frustum
|
||||
* @param {Number} right Right bound of the frustum
|
||||
* @param {Number} bottom Bottom bound of the frustum
|
||||
* @param {Number} top Top bound of the frustum
|
||||
* @param {Number} near Near bound of the frustum
|
||||
* @param {Number} far Far bound of the frustum
|
||||
* @returns {Matrix4} this for chaining
|
||||
*/
|
||||
mat4.frustum = function (left, right, bottom, top, near, far) {
|
||||
var out = this.val,
|
||||
rl = 1 / (right - left),
|
||||
tb = 1 / (top - bottom),
|
||||
nf = 1 / (near - far);
|
||||
out[0] = (near * 2) * rl;
|
||||
out[1] = 0;
|
||||
out[2] = 0;
|
||||
out[3] = 0;
|
||||
out[4] = 0;
|
||||
out[5] = (near * 2) * tb;
|
||||
out[6] = 0;
|
||||
out[7] = 0;
|
||||
out[8] = (right + left) * rl;
|
||||
out[9] = (top + bottom) * tb;
|
||||
out[10] = (far + near) * nf;
|
||||
out[11] = -1;
|
||||
out[12] = 0;
|
||||
out[13] = 0;
|
||||
out[14] = (far * near * 2) * nf;
|
||||
out[15] = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Generates a perspective projection matrix with the given bounds
|
||||
*
|
||||
* @param {number} fovy Vertical field of view in radians
|
||||
* @param {number} aspect Aspect ratio. typically viewport width/height
|
||||
* @param {number} near Near bound of the frustum
|
||||
* @param {number} far Far bound of the frustum
|
||||
* @returns {Matrix4} this for chaining
|
||||
*/
|
||||
mat4.perspective = function (fovy, aspect, near, far) {
|
||||
var out = this.val,
|
||||
f = 1.0 / Math.tan(fovy / 2),
|
||||
nf = 1 / (near - far);
|
||||
out[0] = f / aspect;
|
||||
out[1] = 0;
|
||||
out[2] = 0;
|
||||
out[3] = 0;
|
||||
out[4] = 0;
|
||||
out[5] = f;
|
||||
out[6] = 0;
|
||||
out[7] = 0;
|
||||
out[8] = 0;
|
||||
out[9] = 0;
|
||||
out[10] = (far + near) * nf;
|
||||
out[11] = -1;
|
||||
out[12] = 0;
|
||||
out[13] = 0;
|
||||
out[14] = (2 * far * near) * nf;
|
||||
out[15] = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a orthogonal projection matrix with the given bounds
|
||||
*
|
||||
* @param {number} left Left bound of the frustum
|
||||
* @param {number} right Right bound of the frustum
|
||||
* @param {number} bottom Bottom bound of the frustum
|
||||
* @param {number} top Top bound of the frustum
|
||||
* @param {number} near Near bound of the frustum
|
||||
* @param {number} far Far bound of the frustum
|
||||
* @returns {Matrix4} this for chaining
|
||||
*/
|
||||
mat4.ortho = function (left, right, bottom, top, near, far) {
|
||||
var out = this.val,
|
||||
lr = left-right,
|
||||
bt = bottom-top,
|
||||
nf = near-far;
|
||||
|
||||
//avoid division by zero
|
||||
lr = lr===0 ? lr : 1/lr;
|
||||
bt = bt===0 ? bt : 1/bt;
|
||||
nf = nf===0 ? nf : 1/nf;
|
||||
|
||||
out[0] = -2 * lr;
|
||||
out[1] = 0;
|
||||
out[2] = 0;
|
||||
out[3] = 0;
|
||||
out[4] = 0;
|
||||
out[5] = -2 * bt;
|
||||
out[6] = 0;
|
||||
out[7] = 0;
|
||||
out[8] = 0;
|
||||
out[9] = 0;
|
||||
out[10] = 2 * nf;
|
||||
out[11] = 0;
|
||||
out[12] = (left + right) * lr;
|
||||
out[13] = (top + bottom) * bt;
|
||||
out[14] = (far + near) * nf;
|
||||
out[15] = 1;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Generates a look-at matrix with the given eye position, focal point, and up axis
|
||||
*
|
||||
* @param {Vector3} eye Position of the viewer
|
||||
* @param {Vector3} center Point the viewer is looking at
|
||||
* @param {Vector3} up vec3 pointing up
|
||||
* @returns {Matrix4} this for chaining
|
||||
*/
|
||||
mat4.lookAt = function (eye, center, up) {
|
||||
var out = this.val,
|
||||
|
||||
x0, x1, x2, y0, y1, y2, z0, z1, z2, len,
|
||||
eyex = eye.x,
|
||||
eyey = eye.y,
|
||||
eyez = eye.z,
|
||||
upx = up.x,
|
||||
upy = up.y,
|
||||
upz = up.z,
|
||||
centerx = center.x,
|
||||
centery = center.y,
|
||||
centerz = center.z;
|
||||
|
||||
if (Math.abs(eyex - centerx) < EPSILON &&
|
||||
Math.abs(eyey - centery) < EPSILON &&
|
||||
Math.abs(eyez - centerz) < EPSILON) {
|
||||
return this.identity();
|
||||
}
|
||||
|
||||
z0 = eyex - centerx;
|
||||
z1 = eyey - centery;
|
||||
z2 = eyez - centerz;
|
||||
|
||||
len = 1 / Math.sqrt(z0 * z0 + z1 * z1 + z2 * z2);
|
||||
z0 *= len;
|
||||
z1 *= len;
|
||||
z2 *= len;
|
||||
|
||||
x0 = upy * z2 - upz * z1;
|
||||
x1 = upz * z0 - upx * z2;
|
||||
x2 = upx * z1 - upy * z0;
|
||||
len = Math.sqrt(x0 * x0 + x1 * x1 + x2 * x2);
|
||||
if (!len) {
|
||||
x0 = 0;
|
||||
x1 = 0;
|
||||
x2 = 0;
|
||||
} else {
|
||||
len = 1 / len;
|
||||
x0 *= len;
|
||||
x1 *= len;
|
||||
x2 *= len;
|
||||
}
|
||||
|
||||
y0 = z1 * x2 - z2 * x1;
|
||||
y1 = z2 * x0 - z0 * x2;
|
||||
y2 = z0 * x1 - z1 * x0;
|
||||
|
||||
len = Math.sqrt(y0 * y0 + y1 * y1 + y2 * y2);
|
||||
if (!len) {
|
||||
y0 = 0;
|
||||
y1 = 0;
|
||||
y2 = 0;
|
||||
} else {
|
||||
len = 1 / len;
|
||||
y0 *= len;
|
||||
y1 *= len;
|
||||
y2 *= len;
|
||||
}
|
||||
|
||||
out[0] = x0;
|
||||
out[1] = y0;
|
||||
out[2] = z0;
|
||||
out[3] = 0;
|
||||
out[4] = x1;
|
||||
out[5] = y1;
|
||||
out[6] = z1;
|
||||
out[7] = 0;
|
||||
out[8] = x2;
|
||||
out[9] = y2;
|
||||
out[10] = z2;
|
||||
out[11] = 0;
|
||||
out[12] = -(x0 * eyex + x1 * eyey + x2 * eyez);
|
||||
out[13] = -(y0 * eyex + y1 * eyey + y2 * eyez);
|
||||
out[14] = -(z0 * eyex + z1 * eyey + z2 * eyez);
|
||||
out[15] = 1;
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
mat4.mul = mat4.multiply;
|
||||
|
||||
mat4.idt = mat4.identity;
|
||||
|
||||
//This is handy for Pool utilities, to "reset" a
|
||||
//shared object to its default state
|
||||
mat4.reset = mat4.idt;
|
||||
|
||||
mat4.toString = function () {
|
||||
var a = this.val;
|
||||
return 'Matrix4(' + a[0] + ', ' + a[1] + ', ' + a[2] + ', ' + a[3] + ', ' +
|
||||
a[4] + ', ' + a[5] + ', ' + a[6] + ', ' + a[7] + ', ' +
|
||||
a[8] + ', ' + a[9] + ', ' + a[10] + ', ' + a[11] + ', ' +
|
||||
a[12] + ', ' + a[13] + ', ' + a[14] + ', ' + a[15] + ')';
|
||||
};
|
||||
|
||||
mat4.str = mat4.toString;
|
||||
|
||||
module.exports = Matrix4;
|
281
v3/src/camera3d/vecmath/Quaternion.js
Normal file
281
v3/src/camera3d/vecmath/Quaternion.js
Normal file
|
@ -0,0 +1,281 @@
|
|||
var Vector3 = require('./Vector3');
|
||||
var Matrix3 = require('./Matrix3');
|
||||
var common = require('./common');
|
||||
|
||||
//some shared 'private' arrays
|
||||
var s_iNext = (typeof Int8Array !== 'undefined' ? new Int8Array([1,2,0]) : [1,2,0]);
|
||||
var tmp = (typeof Float32Array !== 'undefined' ? new Float32Array([0,0,0]) : [0,0,0]);
|
||||
|
||||
var xUnitVec3 = new Vector3(1, 0, 0);
|
||||
var yUnitVec3 = new Vector3(0, 1, 0);
|
||||
var tmpvec = new Vector3();
|
||||
|
||||
var tmpMat3 = new Matrix3();
|
||||
|
||||
function Quaternion(x, y, z, w) {
|
||||
if (typeof x === "object") {
|
||||
this.x = x.x||0;
|
||||
this.y = x.y||0;
|
||||
this.z = x.z||0;
|
||||
this.w = x.w||0;
|
||||
} else {
|
||||
this.x = x||0;
|
||||
this.y = y||0;
|
||||
this.z = z||0;
|
||||
this.w = w||0;
|
||||
}
|
||||
}
|
||||
|
||||
var quat = Quaternion.prototype;
|
||||
|
||||
//mixin common functions
|
||||
for (var k in common) {
|
||||
quat[k] = common[k];
|
||||
}
|
||||
|
||||
quat.rotationTo = function(a, b) {
|
||||
var dot = a.x * b.x + a.y * b.y + a.z * b.z; //a.dot(b)
|
||||
if (dot < -0.999999) {
|
||||
if (tmpvec.copy(xUnitVec3).cross(a).len() < 0.000001)
|
||||
tmpvec.copy(yUnitVec3).cross(a);
|
||||
|
||||
tmpvec.normalize();
|
||||
return this.setAxisAngle(tmpvec, Math.PI);
|
||||
} else if (dot > 0.999999) {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
this.w = 1;
|
||||
return this;
|
||||
} else {
|
||||
tmpvec.copy(a).cross(b);
|
||||
this.x = tmpvec.x;
|
||||
this.y = tmpvec.y;
|
||||
this.z = tmpvec.z;
|
||||
this.w = 1 + dot;
|
||||
return this.normalize();
|
||||
}
|
||||
};
|
||||
|
||||
quat.setAxes = function(view, right, up) {
|
||||
var m = tmpMat3.val;
|
||||
m[0] = right.x;
|
||||
m[3] = right.y;
|
||||
m[6] = right.z;
|
||||
|
||||
m[1] = up.x;
|
||||
m[4] = up.y;
|
||||
m[7] = up.z;
|
||||
|
||||
m[2] = -view.x;
|
||||
m[5] = -view.y;
|
||||
m[8] = -view.z;
|
||||
|
||||
return this.fromMat3(tmpMat3).normalize();
|
||||
};
|
||||
|
||||
quat.identity = function() {
|
||||
this.x = this.y = this.z = 0;
|
||||
this.w = 1;
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.setAxisAngle = function(axis, rad) {
|
||||
rad = rad * 0.5;
|
||||
var s = Math.sin(rad);
|
||||
this.x = s * axis.x;
|
||||
this.y = s * axis.y;
|
||||
this.z = s * axis.z;
|
||||
this.w = Math.cos(rad);
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.multiply = function(b) {
|
||||
var ax = this.x, ay = this.y, az = this.z, aw = this.w,
|
||||
bx = b.x, by = b.y, bz = b.z, bw = b.w;
|
||||
|
||||
this.x = ax * bw + aw * bx + ay * bz - az * by;
|
||||
this.y = ay * bw + aw * by + az * bx - ax * bz;
|
||||
this.z = az * bw + aw * bz + ax * by - ay * bx;
|
||||
this.w = aw * bw - ax * bx - ay * by - az * bz;
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.slerp = function (b, t) {
|
||||
// benchmarks:
|
||||
// http://jsperf.com/quaternion-slerp-implementations
|
||||
|
||||
var ax = this.x, ay = this.y, az = this.y, aw = this.y,
|
||||
bx = b.x, by = b.y, bz = b.z, bw = b.w;
|
||||
|
||||
var omega, cosom, sinom, scale0, scale1;
|
||||
|
||||
// calc cosine
|
||||
cosom = ax * bx + ay * by + az * bz + aw * bw;
|
||||
// adjust signs (if necessary)
|
||||
if ( cosom < 0.0 ) {
|
||||
cosom = -cosom;
|
||||
bx = - bx;
|
||||
by = - by;
|
||||
bz = - bz;
|
||||
bw = - bw;
|
||||
}
|
||||
// calculate coefficients
|
||||
if ( (1.0 - cosom) > 0.000001 ) {
|
||||
// standard case (slerp)
|
||||
omega = Math.acos(cosom);
|
||||
sinom = Math.sin(omega);
|
||||
scale0 = Math.sin((1.0 - t) * omega) / sinom;
|
||||
scale1 = Math.sin(t * omega) / sinom;
|
||||
} else {
|
||||
// "from" and "to" quaternions are very close
|
||||
// ... so we can do a linear interpolation
|
||||
scale0 = 1.0 - t;
|
||||
scale1 = t;
|
||||
}
|
||||
// calculate final values
|
||||
this.x = scale0 * ax + scale1 * bx;
|
||||
this.y = scale0 * ay + scale1 * by;
|
||||
this.z = scale0 * az + scale1 * bz;
|
||||
this.w = scale0 * aw + scale1 * bw;
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.invert = function() {
|
||||
var a0 = this.x, a1 = this.y, a2 = this.z, a3 = this.w,
|
||||
dot = a0*a0 + a1*a1 + a2*a2 + a3*a3,
|
||||
invDot = dot ? 1.0/dot : 0;
|
||||
|
||||
// TODO: Would be faster to return [0,0,0,0] immediately if dot == 0
|
||||
|
||||
this.x = -a0*invDot;
|
||||
this.y = -a1*invDot;
|
||||
this.z = -a2*invDot;
|
||||
this.w = a3*invDot;
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.conjugate = function() {
|
||||
this.x = -this.x;
|
||||
this.y = -this.y;
|
||||
this.z = -this.z;
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.rotateX = function (rad) {
|
||||
rad *= 0.5;
|
||||
|
||||
var ax = this.x, ay = this.y, az = this.z, aw = this.w,
|
||||
bx = Math.sin(rad), bw = Math.cos(rad);
|
||||
|
||||
this.x = ax * bw + aw * bx;
|
||||
this.y = ay * bw + az * bx;
|
||||
this.z = az * bw - ay * bx;
|
||||
this.w = aw * bw - ax * bx;
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.rotateY = function (rad) {
|
||||
rad *= 0.5;
|
||||
|
||||
var ax = this.x, ay = this.y, az = this.z, aw = this.w,
|
||||
by = Math.sin(rad), bw = Math.cos(rad);
|
||||
|
||||
this.x = ax * bw - az * by;
|
||||
this.y = ay * bw + aw * by;
|
||||
this.z = az * bw + ax * by;
|
||||
this.w = aw * bw - ay * by;
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.rotateZ = function (rad) {
|
||||
rad *= 0.5;
|
||||
|
||||
var ax = this.x, ay = this.y, az = this.z, aw = this.w,
|
||||
bz = Math.sin(rad), bw = Math.cos(rad);
|
||||
|
||||
this.x = ax * bw + ay * bz;
|
||||
this.y = ay * bw - ax * bz;
|
||||
this.z = az * bw + aw * bz;
|
||||
this.w = aw * bw - az * bz;
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.calculateW = function () {
|
||||
var x = this.x, y = this.y, z = this.z;
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = -Math.sqrt(Math.abs(1.0 - x * x - y * y - z * z));
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.fromMat3 = function(mat) {
|
||||
// benchmarks:
|
||||
// http://jsperf.com/typed-array-access-speed
|
||||
// http://jsperf.com/conversion-of-3x3-matrix-to-quaternion
|
||||
|
||||
// Algorithm in Ken Shoemake's article in 1987 SIGGRAPH course notes
|
||||
// article "Quaternion Calculus and Fast Animation".
|
||||
var m = mat.val,
|
||||
fTrace = m[0] + m[4] + m[8];
|
||||
var fRoot;
|
||||
|
||||
if ( fTrace > 0.0 ) {
|
||||
// |w| > 1/2, may as well choose w > 1/2
|
||||
fRoot = Math.sqrt(fTrace + 1.0); // 2w
|
||||
this.w = 0.5 * fRoot;
|
||||
fRoot = 0.5/fRoot; // 1/(4w)
|
||||
this.x = (m[7]-m[5])*fRoot;
|
||||
this.y = (m[2]-m[6])*fRoot;
|
||||
this.z = (m[3]-m[1])*fRoot;
|
||||
} else {
|
||||
// |w| <= 1/2
|
||||
var i = 0;
|
||||
if ( m[4] > m[0] )
|
||||
i = 1;
|
||||
if ( m[8] > m[i*3+i] )
|
||||
i = 2;
|
||||
var j = s_iNext[i];
|
||||
var k = s_iNext[j];
|
||||
|
||||
//This isn't quite as clean without array access...
|
||||
fRoot = Math.sqrt(m[i*3+i]-m[j*3+j]-m[k*3+k] + 1.0);
|
||||
tmp[i] = 0.5 * fRoot;
|
||||
|
||||
fRoot = 0.5 / fRoot;
|
||||
tmp[j] = (m[j*3+i] + m[i*3+j]) * fRoot;
|
||||
tmp[k] = (m[k*3+i] + m[i*3+k]) * fRoot;
|
||||
|
||||
this.x = tmp[0];
|
||||
this.y = tmp[1];
|
||||
this.z = tmp[2];
|
||||
this.w = (m[k*3+j] - m[j*3+k]) * fRoot;
|
||||
}
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
quat.idt = quat.identity;
|
||||
|
||||
quat.sub = quat.subtract;
|
||||
|
||||
quat.mul = quat.multiply;
|
||||
|
||||
quat.len = quat.length;
|
||||
|
||||
quat.lenSq = quat.lengthSq;
|
||||
|
||||
//This is handy for Pool utilities, to "reset" a
|
||||
//shared object to its default state
|
||||
quat.reset = quat.idt;
|
||||
|
||||
|
||||
quat.toString = function() {
|
||||
return 'Quaternion(' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')';
|
||||
};
|
||||
|
||||
quat.str = quat.toString;
|
||||
|
||||
module.exports = Quaternion;
|
201
v3/src/camera3d/vecmath/Vector2.js
Normal file
201
v3/src/camera3d/vecmath/Vector2.js
Normal file
|
@ -0,0 +1,201 @@
|
|||
function Vector2(x, y) {
|
||||
if (typeof x === "object") {
|
||||
this.x = x.x||0;
|
||||
this.y = x.y||0;
|
||||
} else {
|
||||
this.x = x||0;
|
||||
this.y = y||0;
|
||||
}
|
||||
}
|
||||
|
||||
//shorthand it for better minification
|
||||
var vec2 = Vector2.prototype;
|
||||
|
||||
/**
|
||||
* Returns a new instance of Vector2 with
|
||||
* this vector's components.
|
||||
* @return {Vector2} a clone of this vector
|
||||
*/
|
||||
vec2.clone = function() {
|
||||
return new Vector2(this.x, this.y);
|
||||
};
|
||||
|
||||
/**
|
||||
* Copies the x, y components from the specified
|
||||
* Vector. Any undefined components from `otherVec`
|
||||
* will default to zero.
|
||||
*
|
||||
* @param {otherVec} the other Vector2 to copy
|
||||
* @return {Vector2} this, for chaining
|
||||
*/
|
||||
vec2.copy = function(otherVec) {
|
||||
this.x = otherVec.x||0;
|
||||
this.y = otherVec.y||0;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* A convenience function to set the components of
|
||||
* this vector as x and y. Falsy or undefined
|
||||
* parameters will default to zero.
|
||||
*
|
||||
* You can also pass a vector object instead of
|
||||
* individual components, to copy the object's components.
|
||||
*
|
||||
* @param {Number} x the x component
|
||||
* @param {Number} y the y component
|
||||
* @return {Vector2} this, for chaining
|
||||
*/
|
||||
vec2.set = function(x, y) {
|
||||
if (typeof x === "object") {
|
||||
this.x = x.x||0;
|
||||
this.y = x.y||0;
|
||||
} else {
|
||||
this.x = x||0;
|
||||
this.y = y||0;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.add = function(v) {
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.subtract = function(v) {
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.multiply = function(v) {
|
||||
this.x *= v.x;
|
||||
this.y *= v.y;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.scale = function(s) {
|
||||
this.x *= s;
|
||||
this.y *= s;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.divide = function(v) {
|
||||
this.x /= v.x;
|
||||
this.y /= v.y;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.negate = function() {
|
||||
this.x = -this.x;
|
||||
this.y = -this.y;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.distance = function(v) {
|
||||
var dx = v.x - this.x,
|
||||
dy = v.y - this.y;
|
||||
return Math.sqrt(dx*dx + dy*dy);
|
||||
};
|
||||
|
||||
vec2.distanceSq = function(v) {
|
||||
var dx = v.x - this.x,
|
||||
dy = v.y - this.y;
|
||||
return dx*dx + dy*dy;
|
||||
};
|
||||
|
||||
vec2.length = function() {
|
||||
var x = this.x,
|
||||
y = this.y;
|
||||
return Math.sqrt(x*x + y*y);
|
||||
};
|
||||
|
||||
vec2.lengthSq = function() {
|
||||
var x = this.x,
|
||||
y = this.y;
|
||||
return x*x + y*y;
|
||||
};
|
||||
|
||||
vec2.normalize = function() {
|
||||
var x = this.x,
|
||||
y = this.y;
|
||||
var len = x*x + y*y;
|
||||
if (len > 0) {
|
||||
len = 1 / Math.sqrt(len);
|
||||
this.x = x*len;
|
||||
this.y = y*len;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.dot = function(v) {
|
||||
return this.x * v.x + this.y * v.y;
|
||||
};
|
||||
|
||||
//Unlike Vector3, this returns a scalar
|
||||
//http://allenchou.net/2013/07/cross-product-of-2d-vectors/
|
||||
vec2.cross = function(v) {
|
||||
return this.x * v.y - this.y * v.x;
|
||||
};
|
||||
|
||||
vec2.lerp = function(v, t) {
|
||||
var ax = this.x,
|
||||
ay = this.y;
|
||||
t = t||0;
|
||||
this.x = ax + t * (v.x - ax);
|
||||
this.y = ay + t * (v.y - ay);
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.transformMat3 = function(mat) {
|
||||
var x = this.x, y = this.y, m = mat.val;
|
||||
this.x = m[0] * x + m[3] * y + m[6];
|
||||
this.y = m[1] * x + m[4] * y + m[7];
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.transformMat4 = function(mat) {
|
||||
var x = this.x,
|
||||
y = this.y,
|
||||
m = mat.val;
|
||||
this.x = m[0] * x + m[4] * y + m[12];
|
||||
this.y = m[1] * x + m[5] * y + m[13];
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.reset = function() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.sub = vec2.subtract;
|
||||
|
||||
vec2.mul = vec2.multiply;
|
||||
|
||||
vec2.div = vec2.divide;
|
||||
|
||||
vec2.dist = vec2.distance;
|
||||
|
||||
vec2.distSq = vec2.distanceSq;
|
||||
|
||||
vec2.len = vec2.length;
|
||||
|
||||
vec2.lenSq = vec2.lengthSq;
|
||||
|
||||
vec2.toString = function() {
|
||||
return 'Vector2(' + this.x + ', ' + this.y + ')';
|
||||
};
|
||||
|
||||
vec2.random = function(scale) {
|
||||
scale = scale || 1.0;
|
||||
var r = Math.random() * 2.0 * Math.PI;
|
||||
this.x = Math.cos(r) * scale;
|
||||
this.y = Math.sin(r) * scale;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec2.str = vec2.toString;
|
||||
|
||||
module.exports = Vector2;
|
286
v3/src/camera3d/vecmath/Vector3.js
Normal file
286
v3/src/camera3d/vecmath/Vector3.js
Normal file
|
@ -0,0 +1,286 @@
|
|||
function Vector3(x, y, z) {
|
||||
if (typeof x === "object") {
|
||||
this.x = x.x||0;
|
||||
this.y = x.y||0;
|
||||
this.z = x.z||0;
|
||||
} else {
|
||||
this.x = x||0;
|
||||
this.y = y||0;
|
||||
this.z = z||0;
|
||||
}
|
||||
}
|
||||
|
||||
//shorthand it for better minification
|
||||
var vec3 = Vector3.prototype;
|
||||
|
||||
vec3.clone = function() {
|
||||
return new Vector3(this.x, this.y, this.z);
|
||||
};
|
||||
|
||||
vec3.copy = function(otherVec) {
|
||||
this.x = otherVec.x;
|
||||
this.y = otherVec.y;
|
||||
this.z = otherVec.z;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.set = function(x, y, z) {
|
||||
if (typeof x === "object") {
|
||||
this.x = x.x||0;
|
||||
this.y = x.y||0;
|
||||
this.z = x.z||0;
|
||||
} else {
|
||||
this.x = x||0;
|
||||
this.y = y||0;
|
||||
this.z = z||0;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.add = function(v) {
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
this.z += v.z;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.subtract = function(v) {
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
this.z -= v.z;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.multiply = function(v) {
|
||||
this.x *= v.x;
|
||||
this.y *= v.y;
|
||||
this.z *= v.z;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.scale = function(s) {
|
||||
this.x *= s;
|
||||
this.y *= s;
|
||||
this.z *= s;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.divide = function(v) {
|
||||
this.x /= v.x;
|
||||
this.y /= v.y;
|
||||
this.z /= v.z;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.negate = function() {
|
||||
this.x = -this.x;
|
||||
this.y = -this.y;
|
||||
this.z = -this.z;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.distance = function(v) {
|
||||
var dx = v.x - this.x,
|
||||
dy = v.y - this.y,
|
||||
dz = v.z - this.z;
|
||||
return Math.sqrt(dx*dx + dy*dy + dz*dz);
|
||||
};
|
||||
|
||||
vec3.distanceSq = function(v) {
|
||||
var dx = v.x - this.x,
|
||||
dy = v.y - this.y,
|
||||
dz = v.z - this.z;
|
||||
return dx*dx + dy*dy + dz*dz;
|
||||
};
|
||||
|
||||
vec3.length = function() {
|
||||
var x = this.x,
|
||||
y = this.y,
|
||||
z = this.z;
|
||||
return Math.sqrt(x*x + y*y + z*z);
|
||||
};
|
||||
|
||||
vec3.lengthSq = function() {
|
||||
var x = this.x,
|
||||
y = this.y,
|
||||
z = this.z;
|
||||
return x*x + y*y + z*z;
|
||||
};
|
||||
|
||||
vec3.normalize = function() {
|
||||
var x = this.x,
|
||||
y = this.y,
|
||||
z = this.z;
|
||||
var len = x*x + y*y + z*z;
|
||||
if (len > 0) {
|
||||
len = 1 / Math.sqrt(len);
|
||||
this.x = x*len;
|
||||
this.y = y*len;
|
||||
this.z = z*len;
|
||||
}
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.dot = function(v) {
|
||||
return this.x * v.x + this.y * v.y + this.z * v.z;
|
||||
};
|
||||
|
||||
vec3.cross = function(v) {
|
||||
var ax = this.x, ay = this.y, az = this.z,
|
||||
bx = v.x, by = v.y, bz = v.z;
|
||||
|
||||
this.x = ay * bz - az * by;
|
||||
this.y = az * bx - ax * bz;
|
||||
this.z = ax * by - ay * bx;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.lerp = function(v, t) {
|
||||
var ax = this.x,
|
||||
ay = this.y,
|
||||
az = this.z;
|
||||
t = t||0;
|
||||
this.x = ax + t * (v.x - ax);
|
||||
this.y = ay + t * (v.y - ay);
|
||||
this.z = az + t * (v.z - az);
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.transformMat4 = function(mat) {
|
||||
var x = this.x, y = this.y, z = this.z, m = mat.val;
|
||||
this.x = m[0] * x + m[4] * y + m[8] * z + m[12];
|
||||
this.y = m[1] * x + m[5] * y + m[9] * z + m[13];
|
||||
this.z = m[2] * x + m[6] * y + m[10] * z + m[14];
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.transformMat3 = function(mat) {
|
||||
var x = this.x, y = this.y, z = this.z, m = mat.val;
|
||||
this.x = x * m[0] + y * m[3] + z * m[6];
|
||||
this.y = x * m[1] + y * m[4] + z * m[7];
|
||||
this.z = x * m[2] + y * m[5] + z * m[8];
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.transformQuat = function(q) {
|
||||
// benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
|
||||
var x = this.x, y = this.y, z = this.z,
|
||||
qx = q.x, qy = q.y, qz = q.z, qw = q.w,
|
||||
|
||||
// calculate quat * vec
|
||||
ix = qw * x + qy * z - qz * y,
|
||||
iy = qw * y + qz * x - qx * z,
|
||||
iz = qw * z + qx * y - qy * x,
|
||||
iw = -qx * x - qy * y - qz * z;
|
||||
|
||||
// calculate result * inverse quat
|
||||
this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
|
||||
this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
|
||||
this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Multiplies this Vector3 by the specified matrix,
|
||||
* applying a W divide. This is useful for projection,
|
||||
* e.g. unprojecting a 2D point into 3D space.
|
||||
*
|
||||
* @method prj
|
||||
* @param {Matrix4} the 4x4 matrix to multiply with
|
||||
* @return {Vector3} this object for chaining
|
||||
*/
|
||||
vec3.project = function(mat) {
|
||||
var x = this.x,
|
||||
y = this.y,
|
||||
z = this.z,
|
||||
m = mat.val,
|
||||
a00 = m[0], a01 = m[1], a02 = m[2], a03 = m[3],
|
||||
a10 = m[4], a11 = m[5], a12 = m[6], a13 = m[7],
|
||||
a20 = m[8], a21 = m[9], a22 = m[10], a23 = m[11],
|
||||
a30 = m[12], a31 = m[13], a32 = m[14], a33 = m[15];
|
||||
|
||||
var l_w = 1 / (x * a03 + y * a13 + z * a23 + a33);
|
||||
|
||||
this.x = (x * a00 + y * a10 + z * a20 + a30) * l_w;
|
||||
this.y = (x * a01 + y * a11 + z * a21 + a31) * l_w;
|
||||
this.z = (x * a02 + y * a12 + z * a22 + a32) * l_w;
|
||||
return this;
|
||||
};
|
||||
|
||||
/**
|
||||
* Unproject this point from 2D space to 3D space.
|
||||
* The point should have its x and y properties set to
|
||||
* 2D screen space, and the z either at 0 (near plane)
|
||||
* or 1 (far plane). The provided matrix is assumed to already
|
||||
* be combined, i.e. projection * view * model.
|
||||
*
|
||||
* After this operation, this vector's (x, y, z) components will
|
||||
* represent the unprojected 3D coordinate.
|
||||
*
|
||||
* @param {Vector4} viewport screen x, y, width and height in pixels
|
||||
* @param {Matrix4} invProjectionView combined projection and view matrix
|
||||
* @return {Vector3} this object, for chaining
|
||||
*/
|
||||
vec3.unproject = function(viewport, invProjectionView) {
|
||||
var viewX = viewport.x,
|
||||
viewY = viewport.y,
|
||||
viewWidth = viewport.z,
|
||||
viewHeight = viewport.w;
|
||||
|
||||
var x = this.x,
|
||||
y = this.y,
|
||||
z = this.z;
|
||||
|
||||
x = x - viewX;
|
||||
y = viewHeight - y - 1;
|
||||
y = y - viewY;
|
||||
|
||||
this.x = (2 * x) / viewWidth - 1;
|
||||
this.y = (2 * y) / viewHeight - 1;
|
||||
this.z = 2 * z - 1;
|
||||
|
||||
return this.project(invProjectionView);
|
||||
};
|
||||
|
||||
vec3.random = function(scale) {
|
||||
scale = scale || 1.0;
|
||||
|
||||
var r = Math.random() * 2.0 * Math.PI;
|
||||
var z = (Math.random() * 2.0) - 1.0;
|
||||
var zScale = Math.sqrt(1.0-z*z) * scale;
|
||||
|
||||
this.x = Math.cos(r) * zScale;
|
||||
this.y = Math.sin(r) * zScale;
|
||||
this.z = z * scale;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec3.reset = function() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
vec3.sub = vec3.subtract;
|
||||
|
||||
vec3.mul = vec3.multiply;
|
||||
|
||||
vec3.div = vec3.divide;
|
||||
|
||||
vec3.dist = vec3.distance;
|
||||
|
||||
vec3.distSq = vec3.distanceSq;
|
||||
|
||||
vec3.len = vec3.length;
|
||||
|
||||
vec3.lenSq = vec3.lengthSq;
|
||||
|
||||
vec3.toString = function() {
|
||||
return 'Vector3(' + this.x + ', ' + this.y + ', ' + this.z + ')';
|
||||
};
|
||||
|
||||
vec3.str = vec3.toString;
|
||||
|
||||
module.exports = Vector3;
|
138
v3/src/camera3d/vecmath/Vector4.js
Normal file
138
v3/src/camera3d/vecmath/Vector4.js
Normal file
|
@ -0,0 +1,138 @@
|
|||
var common = require('./common');
|
||||
|
||||
function Vector4(x, y, z, w) {
|
||||
if (typeof x === "object") {
|
||||
this.x = x.x||0;
|
||||
this.y = x.y||0;
|
||||
this.z = x.z||0;
|
||||
this.w = x.w||0;
|
||||
} else {
|
||||
this.x = x||0;
|
||||
this.y = y||0;
|
||||
this.z = z||0;
|
||||
this.w = w||0;
|
||||
}
|
||||
}
|
||||
|
||||
//shorthand it for better minification
|
||||
var vec4 = Vector4.prototype;
|
||||
|
||||
//mixin common functions
|
||||
for (var k in common) {
|
||||
vec4[k] = common[k];
|
||||
}
|
||||
|
||||
vec4.clone = function() {
|
||||
return new Vector4(this.x, this.y, this.z, this.w);
|
||||
};
|
||||
|
||||
vec4.multiply = function(v) {
|
||||
this.x *= v.x;
|
||||
this.y *= v.y;
|
||||
this.z *= v.z;
|
||||
this.w *= v.w;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec4.divide = function(v) {
|
||||
this.x /= v.x;
|
||||
this.y /= v.y;
|
||||
this.z /= v.z;
|
||||
this.w /= v.w;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec4.distance = function(v) {
|
||||
var dx = v.x - this.x,
|
||||
dy = v.y - this.y,
|
||||
dz = v.z - this.z,
|
||||
dw = v.w - this.w;
|
||||
return Math.sqrt(dx*dx + dy*dy + dz*dz + dw*dw);
|
||||
};
|
||||
|
||||
vec4.distanceSq = function(v) {
|
||||
var dx = v.x - this.x,
|
||||
dy = v.y - this.y,
|
||||
dz = v.z - this.z,
|
||||
dw = v.w - this.w;
|
||||
return dx*dx + dy*dy + dz*dz + dw*dw;
|
||||
};
|
||||
|
||||
vec4.negate = function() {
|
||||
this.x = -this.x;
|
||||
this.y = -this.y;
|
||||
this.z = -this.z;
|
||||
this.w = -this.w;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec4.transformMat4 = function(mat) {
|
||||
var m = mat.val, x = this.x, y = this.y, z = this.z, w = this.w;
|
||||
this.x = m[0] * x + m[4] * y + m[8] * z + m[12] * w;
|
||||
this.y = m[1] * x + m[5] * y + m[9] * z + m[13] * w;
|
||||
this.z = m[2] * x + m[6] * y + m[10] * z + m[14] * w;
|
||||
this.w = m[3] * x + m[7] * y + m[11] * z + m[15] * w;
|
||||
return this;
|
||||
};
|
||||
|
||||
//// TODO: is this really the same as Vector3 ??
|
||||
/// Also, what about this:
|
||||
/// http://molecularmusings.wordpress.com/2013/05/24/a-faster-quaternion-vector-multiplication/
|
||||
vec4.transformQuat = function(q) {
|
||||
// benchmarks: http://jsperf.com/quaternion-transform-vec3-implementations
|
||||
var x = this.x, y = this.y, z = this.z,
|
||||
qx = q.x, qy = q.y, qz = q.z, qw = q.w,
|
||||
|
||||
// calculate quat * vec
|
||||
ix = qw * x + qy * z - qz * y,
|
||||
iy = qw * y + qz * x - qx * z,
|
||||
iz = qw * z + qx * y - qy * x,
|
||||
iw = -qx * x - qy * y - qz * z;
|
||||
|
||||
// calculate result * inverse quat
|
||||
this.x = ix * qw + iw * -qx + iy * -qz - iz * -qy;
|
||||
this.y = iy * qw + iw * -qy + iz * -qx - ix * -qz;
|
||||
this.z = iz * qw + iw * -qz + ix * -qy - iy * -qx;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec4.random = function(scale) {
|
||||
scale = scale || 1.0;
|
||||
|
||||
//Not spherical; should fix this for more uniform distribution
|
||||
this.x = (Math.random() * 2 - 1) * scale;
|
||||
this.y = (Math.random() * 2 - 1) * scale;
|
||||
this.z = (Math.random() * 2 - 1) * scale;
|
||||
this.w = (Math.random() * 2 - 1) * scale;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec4.reset = function() {
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
this.z = 0;
|
||||
this.w = 0;
|
||||
return this;
|
||||
};
|
||||
|
||||
vec4.sub = vec4.subtract;
|
||||
|
||||
vec4.mul = vec4.multiply;
|
||||
|
||||
vec4.div = vec4.divide;
|
||||
|
||||
vec4.dist = vec4.distance;
|
||||
|
||||
vec4.distSq = vec4.distanceSq;
|
||||
|
||||
vec4.len = vec4.length;
|
||||
|
||||
vec4.lenSq = vec4.lengthSq;
|
||||
|
||||
vec4.toString = function() {
|
||||
return 'Vector4(' + this.x + ', ' + this.y + ', ' + this.z + ', ' + this.w + ')';
|
||||
};
|
||||
|
||||
vec4.str = vec4.toString;
|
||||
|
||||
module.exports = Vector4;
|
186
v3/src/camera3d/vecmath/common.js
Normal file
186
v3/src/camera3d/vecmath/common.js
Normal file
|
@ -0,0 +1,186 @@
|
|||
//common vec4 functions
|
||||
module.exports = {
|
||||
|
||||
/**
|
||||
* Copies the x, y, z, w components from the specified
|
||||
* Vector. Unlike most other operations, this function
|
||||
* will default undefined components on `otherVec` to zero.
|
||||
*
|
||||
* @method copy
|
||||
* @param {otherVec} the other Vector4 to copy
|
||||
* @return {Vector} this, for chaining
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* A convenience function to set the components of
|
||||
* this vector as x, y, z, w. Falsy or undefined
|
||||
* parameters will default to zero.
|
||||
*
|
||||
* You can also pass a vector object instead of
|
||||
* individual components, to copy the object's components.
|
||||
*
|
||||
* @method set
|
||||
* @param {Number} x the x component
|
||||
* @param {Number} y the y component
|
||||
* @param {Number} z the z component
|
||||
* @param {Number} w the w component
|
||||
* @return {Vector2} this, for chaining
|
||||
*/
|
||||
|
||||
/**
|
||||
* Adds the components of the other Vector4 to
|
||||
* this vector.
|
||||
*
|
||||
* @method add
|
||||
* @param {Vector4} otherVec other vector, right operand
|
||||
* @return {Vector2} this, for chaining
|
||||
*/
|
||||
|
||||
/**
|
||||
* Subtracts the components of the other Vector4
|
||||
* from this vector. Aliased as `sub()`
|
||||
*
|
||||
* @method subtract
|
||||
* @param {Vector4} otherVec other vector, right operand
|
||||
* @return {Vector2} this, for chaining
|
||||
*/
|
||||
|
||||
/**
|
||||
* Multiplies the components of this Vector4
|
||||
* by a scalar amount.
|
||||
*
|
||||
* @method scale
|
||||
* @param {Number} s the scale to multiply by
|
||||
* @return {Vector4} this, for chaining
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the magnitude (length) of this vector.
|
||||
*
|
||||
* Aliased as `len()`
|
||||
*
|
||||
* @method length
|
||||
* @return {Number} the length of this vector
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the squared magnitude (length) of this vector.
|
||||
*
|
||||
* Aliased as `lenSq()`
|
||||
*
|
||||
* @method lengthSq
|
||||
* @return {Number} the squared length of this vector
|
||||
*/
|
||||
|
||||
/**
|
||||
* Normalizes this vector to a unit vector.
|
||||
* @method normalize
|
||||
* @return {Vector4} this, for chaining
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the dot product of this vector
|
||||
* and the specified Vector4.
|
||||
*
|
||||
* @method dot
|
||||
* @return {Number} the dot product
|
||||
*/
|
||||
copy: function(otherVec) {
|
||||
this.x = otherVec.x||0;
|
||||
this.y = otherVec.y||0;
|
||||
this.z = otherVec.z||0;
|
||||
this.w = otherVec.w||0;
|
||||
return this;
|
||||
},
|
||||
|
||||
set: function(x, y, z, w) {
|
||||
if (typeof x === "object") {
|
||||
this.x = x.x||0;
|
||||
this.y = x.y||0;
|
||||
this.z = x.z||0;
|
||||
this.w = x.w||0;
|
||||
} else {
|
||||
this.x = x||0;
|
||||
this.y = y||0;
|
||||
this.z = z||0;
|
||||
this.w = w||0;
|
||||
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
add: function(v) {
|
||||
this.x += v.x;
|
||||
this.y += v.y;
|
||||
this.z += v.z;
|
||||
this.w += v.w;
|
||||
return this;
|
||||
},
|
||||
|
||||
subtract: function(v) {
|
||||
this.x -= v.x;
|
||||
this.y -= v.y;
|
||||
this.z -= v.z;
|
||||
this.w -= v.w;
|
||||
return this;
|
||||
},
|
||||
|
||||
scale: function(s) {
|
||||
this.x *= s;
|
||||
this.y *= s;
|
||||
this.z *= s;
|
||||
this.w *= s;
|
||||
return this;
|
||||
},
|
||||
|
||||
|
||||
length: function() {
|
||||
var x = this.x,
|
||||
y = this.y,
|
||||
z = this.z,
|
||||
w = this.w;
|
||||
return Math.sqrt(x*x + y*y + z*z + w*w);
|
||||
},
|
||||
|
||||
lengthSq: function() {
|
||||
var x = this.x,
|
||||
y = this.y,
|
||||
z = this.z,
|
||||
w = this.w;
|
||||
return x*x + y*y + z*z + w*w;
|
||||
},
|
||||
|
||||
normalize: function() {
|
||||
var x = this.x,
|
||||
y = this.y,
|
||||
z = this.z,
|
||||
w = this.w;
|
||||
var len = x*x + y*y + z*z + w*w;
|
||||
if (len > 0) {
|
||||
len = 1 / Math.sqrt(len);
|
||||
this.x = x*len;
|
||||
this.y = y*len;
|
||||
this.z = z*len;
|
||||
this.w = w*len;
|
||||
}
|
||||
return this;
|
||||
},
|
||||
|
||||
dot: function(v) {
|
||||
return this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;
|
||||
},
|
||||
|
||||
lerp: function(v, t) {
|
||||
var ax = this.x,
|
||||
ay = this.y,
|
||||
az = this.z,
|
||||
aw = this.w;
|
||||
t = t||0;
|
||||
this.x = ax + t * (v.x - ax);
|
||||
this.y = ay + t * (v.y - ay);
|
||||
this.z = az + t * (v.z - az);
|
||||
this.w = aw + t * (v.w - aw);
|
||||
return this;
|
||||
}
|
||||
};
|
8
v3/src/camera3d/vecmath/index.js
Normal file
8
v3/src/camera3d/vecmath/index.js
Normal file
|
@ -0,0 +1,8 @@
|
|||
module.exports = {
|
||||
Vector2: require('./Vector2'),
|
||||
Vector3: require('./Vector3'),
|
||||
Vector4: require('./Vector4'),
|
||||
Matrix3: require('./Matrix3'),
|
||||
Matrix4: require('./Matrix4'),
|
||||
Quaternion: require('./Quaternion')
|
||||
};
|
34
v3/src/camera3d/vecutil.js
Normal file
34
v3/src/camera3d/vecutil.js
Normal file
|
@ -0,0 +1,34 @@
|
|||
|
||||
var Vector3 = require('./vecmath/Vector3');
|
||||
var Matrix4 = require('./vecmath/Matrix4');
|
||||
var Quaternion = require('./vecmath/Quaternion');
|
||||
|
||||
var tmpMat4 = new Matrix4();
|
||||
var tmpQuat = new Quaternion();
|
||||
var tmpVec3 = new Vector3();
|
||||
|
||||
var util = {};
|
||||
|
||||
/**
|
||||
* Rotates a vector in place by axis angle.
|
||||
*
|
||||
* This is the same as transforming a point by an
|
||||
* axis-angle quaternion, but it has higher precision.
|
||||
*
|
||||
* @param {Vector3} vec [description]
|
||||
* @param {Vector3} axis [description]
|
||||
* @param {float} radians [description]
|
||||
* @return {Vector3} [description]
|
||||
*/
|
||||
util.rotate = function(vec, axis, radians) {
|
||||
//set the quaternion to our axis angle
|
||||
tmpQuat.setAxisAngle(axis, radians);
|
||||
|
||||
//create a rotation matrix from the axis angle
|
||||
tmpMat4.fromRotationTranslation( tmpQuat, tmpVec3.set(0, 0, 0) );
|
||||
|
||||
//multiply our vector by the rotation matrix
|
||||
return vec.transformMat4( tmpMat4 );
|
||||
};
|
||||
|
||||
module.exports = util;
|
|
@ -19,6 +19,8 @@ var Transform = {
|
|||
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0,
|
||||
w: 0,
|
||||
|
||||
depth: {
|
||||
|
||||
|
@ -109,13 +111,17 @@ var Transform = {
|
|||
}
|
||||
},
|
||||
|
||||
setPosition: function (x, y)
|
||||
setPosition: function (x, y, z, w)
|
||||
{
|
||||
if (x === undefined) { x = 0; }
|
||||
if (y === undefined) { y = x; }
|
||||
if (z === undefined) { z = 0; }
|
||||
if (w === undefined) { w = 0; }
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
this.w = w;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
@ -149,6 +155,24 @@ var Transform = {
|
|||
return this;
|
||||
},
|
||||
|
||||
setZ: function (value)
|
||||
{
|
||||
if (value === undefined) { value = 0; }
|
||||
|
||||
this.z = value;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setW: function (value)
|
||||
{
|
||||
if (value === undefined) { value = 0; }
|
||||
|
||||
this.w = value;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
setDepth: function (value)
|
||||
{
|
||||
if (value === undefined) { value = 0; }
|
||||
|
|
|
@ -1,19 +1,36 @@
|
|||
var Percent = function (a, b, base)
|
||||
{
|
||||
if (base === undefined) { base = 0; }
|
||||
// Work out what % value is of the range between min and max.
|
||||
// If max isn't given then you get the % of value to min.
|
||||
// You can optionally specify an upperMax, which is a mid-way point in the range
|
||||
// that represents 100%, after which the % starts to go down to zero again.
|
||||
|
||||
if (a > b || base > b)
|
||||
var Percent = function (value, min, max, upperMax)
|
||||
{
|
||||
if (max === undefined) { max = min + 1; }
|
||||
|
||||
var percentage = (value - min) / (max - min);
|
||||
|
||||
if (percentage > 1)
|
||||
{
|
||||
return 1;
|
||||
if (upperMax !== undefined)
|
||||
{
|
||||
percentage = ((upperMax - value)) / (upperMax - max);
|
||||
|
||||
if (percentage < 0)
|
||||
{
|
||||
percentage = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
percentage = 1;
|
||||
}
|
||||
}
|
||||
else if (a < base || base > a)
|
||||
else if (percentage < 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return (a - base) / b;
|
||||
percentage = 0;
|
||||
}
|
||||
|
||||
return percentage;
|
||||
};
|
||||
|
||||
module.exports = Percent;
|
||||
|
|
221
v3/src/math/Vector2.js
Normal file
221
v3/src/math/Vector2.js
Normal file
|
@ -0,0 +1,221 @@
|
|||
// Based on vecmath lib by mattdesl https://github.com/mattdesl/vecmath and gl-matrix
|
||||
|
||||
var Class = require('../utils/Class');
|
||||
|
||||
var Vector2 = new Class({
|
||||
|
||||
initialize:
|
||||
|
||||
function Vector2 (x, y)
|
||||
{
|
||||
if (x === undefined) { x = 0; }
|
||||
if (y === undefined) { y = 0; }
|
||||
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
},
|
||||
|
||||
clone: function ()
|
||||
{
|
||||
return new Vector2(this.x, this.y);
|
||||
},
|
||||
|
||||
|
||||
copy: function (src)
|
||||
{
|
||||
this.x = src.x || 0;
|
||||
this.y = src.y || 0;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
set: function (x, y)
|
||||
{
|
||||
if (typeof x === 'object')
|
||||
{
|
||||
this.x = x.x || 0;
|
||||
this.y = x.y || 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
add: function (src)
|
||||
{
|
||||
this.x += src.x;
|
||||
this.y += src.y;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
subtract: function (src)
|
||||
{
|
||||
this.x -= src.x;
|
||||
this.y -= src.y;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
multiply: function (src)
|
||||
{
|
||||
this.x *= src.x;
|
||||
this.y *= src.y;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
scale: function (value)
|
||||
{
|
||||
this.x *= value;
|
||||
this.y *= value;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
divide: function (src)
|
||||
{
|
||||
this.x /= src.x;
|
||||
this.y /= src.y;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
negate: function ()
|
||||
{
|
||||
this.x = -this.x;
|
||||
this.y = -this.y;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
distance: function (src)
|
||||
{
|
||||
var dx = src.x - this.x;
|
||||
var dy = src.y - this.y;
|
||||
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
},
|
||||
|
||||
distanceSq: function (src)
|
||||
{
|
||||
var dx = src.x - this.x;
|
||||
var dy = src.y - this.y;
|
||||
|
||||
return dx * dx + dy * dy;
|
||||
},
|
||||
|
||||
length: function ()
|
||||
{
|
||||
var x = this.x;
|
||||
var y = this.y;
|
||||
|
||||
return Math.sqrt(x * x + y * y);
|
||||
},
|
||||
|
||||
lengthSq: function ()
|
||||
{
|
||||
var x = this.x;
|
||||
var y = this.y;
|
||||
|
||||
return x * x + y * y;
|
||||
},
|
||||
|
||||
normalize: function ()
|
||||
{
|
||||
var x = this.x;
|
||||
var y = this.y;
|
||||
var len = x * x + y * y;
|
||||
|
||||
if (len > 0)
|
||||
{
|
||||
len = 1 / Math.sqrt(len);
|
||||
this.x = x * len;
|
||||
this.y = y * len;
|
||||
}
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
dot: function (src)
|
||||
{
|
||||
return this.x * src.x + this.y * src.y;
|
||||
},
|
||||
|
||||
cross: function (src)
|
||||
{
|
||||
return this.x * src.y - this.y * src.x;
|
||||
},
|
||||
|
||||
lerp: function (src, t)
|
||||
{
|
||||
if (t === undefined) { t = 0; }
|
||||
|
||||
var ax = this.x;
|
||||
var ay = this.y;
|
||||
|
||||
this.x = ax + t * (src.x - ax);
|
||||
this.y = ay + t * (src.y - ay);
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
transformMat3: function (mat)
|
||||
{
|
||||
var x = this.x;
|
||||
var y = this.y;
|
||||
var m = mat.val;
|
||||
|
||||
this.x = m[0] * x + m[3] * y + m[6];
|
||||
this.y = m[1] * x + m[4] * y + m[7];
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
transformMat4: function (mat)
|
||||
{
|
||||
var x = this.x;
|
||||
var y = this.y;
|
||||
var m = mat.val;
|
||||
|
||||
this.x = m[0] * x + m[4] * y + m[12];
|
||||
this.y = m[1] * x + m[5] * y + m[13];
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
reset: function ()
|
||||
{
|
||||
this.x = 0;
|
||||
this.y = 0;
|
||||
|
||||
return this;
|
||||
},
|
||||
|
||||
random: function (scale)
|
||||
{
|
||||
if (scale === undefined) { scale = 1; }
|
||||
|
||||
var r = Math.random() * 2 * Math.PI;
|
||||
|
||||
this.x = Math.cos(r) * scale;
|
||||
this.y = Math.sin(r) * scale;
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
Vector2.sub = Vector2.subtract;
|
||||
Vector2.mul = Vector2.multiply;
|
||||
Vector2.div = Vector2.divide;
|
||||
Vector2.dist = Vector2.distance;
|
||||
Vector2.distSq = Vector2.distanceSq;
|
||||
Vector2.len = Vector2.length;
|
||||
Vector2.lenSq = Vector2.lengthSq;
|
||||
|
||||
module.exports = Vector2;
|
|
@ -19,6 +19,9 @@ var Phaser = {
|
|||
|
||||
Create: require('./create/'),
|
||||
|
||||
Cameras3D: require('./camera3d/'),
|
||||
VecMath: require('./camera3d/vecmath/'),
|
||||
|
||||
DOM: require('./dom/'),
|
||||
|
||||
Game: require('./boot/Game'),
|
||||
|
|
Loading…
Reference in a new issue