850 lines
14 KiB
JavaScript
850 lines
14 KiB
JavaScript
/**
|
|
* @author mrdoob / http://mrdoob.com/
|
|
* @author *kile / http://kile.stravaganza.org/
|
|
* @author philogb / http://blog.thejit.org/
|
|
* @author mikael emtinger / http://gomo.se/
|
|
* @author egraether / http://egraether.com/
|
|
* @author WestLangley / http://github.com/WestLangley
|
|
*/
|
|
|
|
THREE.Vector3 = function ( x, y, z ) {
|
|
|
|
this.x = x || 0;
|
|
this.y = y || 0;
|
|
this.z = z || 0;
|
|
|
|
};
|
|
|
|
THREE.Vector3.prototype = {
|
|
|
|
constructor: THREE.Vector3,
|
|
/*
|
|
set: function ( x, y, z ) {
|
|
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z;
|
|
|
|
return this;
|
|
|
|
},
|
|
*/
|
|
setX: function ( x ) {
|
|
|
|
this.x = x;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
setY: function ( y ) {
|
|
|
|
this.y = y;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
setZ: function ( z ) {
|
|
|
|
this.z = z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
setComponent: function ( index, value ) {
|
|
|
|
switch ( index ) {
|
|
|
|
case 0: this.x = value; break;
|
|
case 1: this.y = value; break;
|
|
case 2: this.z = value; break;
|
|
default: throw new Error( 'index is out of range: ' + index );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
getComponent: function ( index ) {
|
|
|
|
switch ( index ) {
|
|
|
|
case 0: return this.x;
|
|
case 1: return this.y;
|
|
case 2: return this.z;
|
|
default: throw new Error( 'index is out of range: ' + index );
|
|
|
|
}
|
|
|
|
},
|
|
|
|
copy: function ( v ) {
|
|
|
|
this.x = v.x;
|
|
this.y = v.y;
|
|
this.z = v.z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
add: function ( v, w ) {
|
|
|
|
if ( w !== undefined ) {
|
|
|
|
THREE.warn( 'THREE.Vector3: .add() now only accepts one argument. Use .addVectors( a, b ) instead.' );
|
|
return this.addVectors( v, w );
|
|
|
|
}
|
|
|
|
this.x += v.x;
|
|
this.y += v.y;
|
|
this.z += v.z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
addScalar: function ( s ) {
|
|
|
|
this.x += s;
|
|
this.y += s;
|
|
this.z += s;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
addVectors: function ( a, b ) {
|
|
|
|
this.x = a.x + b.x;
|
|
this.y = a.y + b.y;
|
|
this.z = a.z + b.z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
sub: function ( v, w ) {
|
|
|
|
if ( w !== undefined ) {
|
|
|
|
THREE.warn( 'THREE.Vector3: .sub() now only accepts one argument. Use .subVectors( a, b ) instead.' );
|
|
return this.subVectors( v, w );
|
|
|
|
}
|
|
|
|
this.x -= v.x;
|
|
this.y -= v.y;
|
|
this.z -= v.z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
subScalar: function ( s ) {
|
|
|
|
this.x -= s;
|
|
this.y -= s;
|
|
this.z -= s;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
subVectors: function ( a, b ) {
|
|
|
|
this.x = a.x - b.x;
|
|
this.y = a.y - b.y;
|
|
this.z = a.z - b.z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
multiply: function ( v, w ) {
|
|
|
|
if ( w !== undefined ) {
|
|
|
|
THREE.warn( 'THREE.Vector3: .multiply() now only accepts one argument. Use .multiplyVectors( a, b ) instead.' );
|
|
return this.multiplyVectors( v, w );
|
|
|
|
}
|
|
|
|
this.x *= v.x;
|
|
this.y *= v.y;
|
|
this.z *= v.z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
multiplyScalar: function ( scalar ) {
|
|
|
|
this.x *= scalar;
|
|
this.y *= scalar;
|
|
this.z *= scalar;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
multiplyVectors: function ( a, b ) {
|
|
|
|
this.x = a.x * b.x;
|
|
this.y = a.y * b.y;
|
|
this.z = a.z * b.z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
applyEuler: function () {
|
|
|
|
var quaternion;
|
|
|
|
return function ( euler ) {
|
|
|
|
if ( euler instanceof THREE.Euler === false ) {
|
|
|
|
THREE.error( 'THREE.Vector3: .applyEuler() now expects a Euler rotation rather than a Vector3 and order.' );
|
|
|
|
}
|
|
|
|
if ( quaternion === undefined ) quaternion = new THREE.Quaternion();
|
|
|
|
this.applyQuaternion( quaternion.setFromEuler( euler ) );
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
}(),
|
|
|
|
applyAxisAngle: function () {
|
|
|
|
var quaternion;
|
|
|
|
return function ( axis, angle ) {
|
|
|
|
if ( quaternion === undefined ) quaternion = new THREE.Quaternion();
|
|
|
|
this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
|
|
|
|
return this;
|
|
|
|
};
|
|
|
|
}(),
|
|
|
|
applyMatrix3: function ( m ) {
|
|
|
|
var x = this.x;
|
|
var y = this.y;
|
|
var z = this.z;
|
|
|
|
var e = m.elements;
|
|
|
|
this.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;
|
|
this.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;
|
|
this.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
applyMatrix4: function ( m ) {
|
|
|
|
// input: THREE.Matrix4 affine matrix
|
|
|
|
var x = this.x, y = this.y, z = this.z;
|
|
|
|
var e = m.elements;
|
|
|
|
this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ];
|
|
this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ];
|
|
this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ];
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
applyProjection: function ( m ) {
|
|
|
|
// input: THREE.Matrix4 projection matrix
|
|
|
|
var x = this.x, y = this.y, z = this.z;
|
|
|
|
var e = m.elements;
|
|
var d = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] ); // perspective divide
|
|
|
|
this.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * d;
|
|
this.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * d;
|
|
this.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * d;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
applyQuaternion: function ( q ) {
|
|
|
|
var x = this.x;
|
|
var y = this.y;
|
|
var z = this.z;
|
|
|
|
var qx = q.x;
|
|
var qy = q.y;
|
|
var qz = q.z;
|
|
var qw = q.w;
|
|
|
|
// calculate quat * vector
|
|
|
|
var ix = qw * x + qy * z - qz * y;
|
|
var iy = qw * y + qz * x - qx * z;
|
|
var iz = qw * z + qx * y - qy * x;
|
|
var 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;
|
|
|
|
},
|
|
|
|
project: function () {
|
|
|
|
var matrix;
|
|
|
|
return function ( camera ) {
|
|
|
|
if ( matrix === undefined ) matrix = new THREE.Matrix4();
|
|
|
|
matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
|
|
return this.applyProjection( matrix );
|
|
|
|
};
|
|
|
|
}(),
|
|
|
|
unproject: function () {
|
|
|
|
var matrix;
|
|
|
|
return function ( camera ) {
|
|
|
|
if ( matrix === undefined ) matrix = new THREE.Matrix4();
|
|
|
|
matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
|
|
return this.applyProjection( matrix );
|
|
|
|
};
|
|
|
|
}(),
|
|
|
|
transformDirection: function ( m ) {
|
|
|
|
// input: THREE.Matrix4 affine matrix
|
|
// vector interpreted as a direction
|
|
|
|
var x = this.x, y = this.y, z = this.z;
|
|
|
|
var e = m.elements;
|
|
|
|
this.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;
|
|
this.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;
|
|
this.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;
|
|
|
|
this.normalize();
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
divide: function ( v ) {
|
|
|
|
this.x /= v.x;
|
|
this.y /= v.y;
|
|
this.z /= v.z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
divideScalar: function ( scalar ) {
|
|
|
|
if ( scalar !== 0 ) {
|
|
|
|
var invScalar = 1 / scalar;
|
|
|
|
this.x *= invScalar;
|
|
this.y *= invScalar;
|
|
this.z *= invScalar;
|
|
|
|
} else {
|
|
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.z = 0;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
min: function ( v ) {
|
|
|
|
if ( this.x > v.x ) {
|
|
|
|
this.x = v.x;
|
|
|
|
}
|
|
|
|
if ( this.y > v.y ) {
|
|
|
|
this.y = v.y;
|
|
|
|
}
|
|
|
|
if ( this.z > v.z ) {
|
|
|
|
this.z = v.z;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
max: function ( v ) {
|
|
|
|
if ( this.x < v.x ) {
|
|
|
|
this.x = v.x;
|
|
|
|
}
|
|
|
|
if ( this.y < v.y ) {
|
|
|
|
this.y = v.y;
|
|
|
|
}
|
|
|
|
if ( this.z < v.z ) {
|
|
|
|
this.z = v.z;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
clamp: function ( min, max ) {
|
|
|
|
// This function assumes min < max, if this assumption isn't true it will not operate correctly
|
|
|
|
if ( this.x < min.x ) {
|
|
|
|
this.x = min.x;
|
|
|
|
} else if ( this.x > max.x ) {
|
|
|
|
this.x = max.x;
|
|
|
|
}
|
|
|
|
if ( this.y < min.y ) {
|
|
|
|
this.y = min.y;
|
|
|
|
} else if ( this.y > max.y ) {
|
|
|
|
this.y = max.y;
|
|
|
|
}
|
|
|
|
if ( this.z < min.z ) {
|
|
|
|
this.z = min.z;
|
|
|
|
} else if ( this.z > max.z ) {
|
|
|
|
this.z = max.z;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
clampScalar: ( function () {
|
|
|
|
var min, max;
|
|
|
|
return function ( minVal, maxVal ) {
|
|
|
|
if ( min === undefined ) {
|
|
|
|
min = new THREE.Vector3();
|
|
max = new THREE.Vector3();
|
|
|
|
}
|
|
|
|
min.set( minVal, minVal, minVal );
|
|
max.set( maxVal, maxVal, maxVal );
|
|
|
|
return this.clamp( min, max );
|
|
|
|
};
|
|
|
|
} )(),
|
|
|
|
floor: function () {
|
|
|
|
this.x = Math.floor( this.x );
|
|
this.y = Math.floor( this.y );
|
|
this.z = Math.floor( this.z );
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
ceil: function () {
|
|
|
|
this.x = Math.ceil( this.x );
|
|
this.y = Math.ceil( this.y );
|
|
this.z = Math.ceil( this.z );
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
round: function () {
|
|
|
|
this.x = Math.round( this.x );
|
|
this.y = Math.round( this.y );
|
|
this.z = Math.round( this.z );
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
roundToZero: function () {
|
|
|
|
this.x = ( this.x < 0 ) ? Math.ceil( this.x ) : Math.floor( this.x );
|
|
this.y = ( this.y < 0 ) ? Math.ceil( this.y ) : Math.floor( this.y );
|
|
this.z = ( this.z < 0 ) ? Math.ceil( this.z ) : Math.floor( this.z );
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
negate: function () {
|
|
|
|
this.x = - this.x;
|
|
this.y = - this.y;
|
|
this.z = - this.z;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
dot: function ( v ) {
|
|
|
|
return this.x * v.x + this.y * v.y + this.z * v.z;
|
|
|
|
},
|
|
|
|
lengthSq: function () {
|
|
|
|
return this.x * this.x + this.y * this.y + this.z * this.z;
|
|
|
|
},
|
|
|
|
length: function () {
|
|
|
|
return Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );
|
|
|
|
},
|
|
|
|
lengthManhattan: function () {
|
|
|
|
return Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );
|
|
|
|
},
|
|
|
|
normalize: function () {
|
|
|
|
return this.divideScalar( this.length() );
|
|
|
|
},
|
|
|
|
setLength: function ( l ) {
|
|
|
|
var oldLength = this.length();
|
|
|
|
if ( oldLength !== 0 && l !== oldLength ) {
|
|
|
|
this.multiplyScalar( l / oldLength );
|
|
}
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
lerp: function ( v, alpha ) {
|
|
|
|
this.x += ( v.x - this.x ) * alpha;
|
|
this.y += ( v.y - this.y ) * alpha;
|
|
this.z += ( v.z - this.z ) * alpha;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
lerpVectors: function ( v1, v2, alpha ) {
|
|
|
|
this.subVectors( v2, v1 ).multiplyScalar( alpha ).add( v1 );
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
cross: function ( v, w ) {
|
|
|
|
if ( w !== undefined ) {
|
|
|
|
THREE.warn( 'THREE.Vector3: .cross() now only accepts one argument. Use .crossVectors( a, b ) instead.' );
|
|
return this.crossVectors( v, w );
|
|
|
|
}
|
|
|
|
var x = this.x, y = this.y, z = this.z;
|
|
|
|
this.x = y * v.z - z * v.y;
|
|
this.y = z * v.x - x * v.z;
|
|
this.z = x * v.y - y * v.x;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
crossVectors: function ( a, b ) {
|
|
|
|
var ax = a.x, ay = a.y, az = a.z;
|
|
var bx = b.x, by = b.y, bz = b.z;
|
|
|
|
this.x = ay * bz - az * by;
|
|
this.y = az * bx - ax * bz;
|
|
this.z = ax * by - ay * bx;
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
projectOnVector: function () {
|
|
|
|
var v1, dot;
|
|
|
|
return function ( vector ) {
|
|
|
|
if ( v1 === undefined ) v1 = new THREE.Vector3();
|
|
|
|
v1.copy( vector ).normalize();
|
|
|
|
dot = this.dot( v1 );
|
|
|
|
return this.copy( v1 ).multiplyScalar( dot );
|
|
|
|
};
|
|
|
|
}(),
|
|
|
|
projectOnPlane: function () {
|
|
|
|
var v1;
|
|
|
|
return function ( planeNormal ) {
|
|
|
|
if ( v1 === undefined ) v1 = new THREE.Vector3();
|
|
|
|
v1.copy( this ).projectOnVector( planeNormal );
|
|
|
|
return this.sub( v1 );
|
|
|
|
}
|
|
|
|
}(),
|
|
|
|
reflect: function () {
|
|
|
|
// reflect incident vector off plane orthogonal to normal
|
|
// normal is assumed to have unit length
|
|
|
|
var v1;
|
|
|
|
return function ( normal ) {
|
|
|
|
if ( v1 === undefined ) v1 = new THREE.Vector3();
|
|
|
|
return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
|
|
|
|
}
|
|
|
|
}(),
|
|
|
|
angleTo: function ( v ) {
|
|
|
|
var theta = this.dot( v ) / ( this.length() * v.length() );
|
|
|
|
// clamp, to handle numerical problems
|
|
|
|
return Math.acos( THREE.Math.clamp( theta, - 1, 1 ) );
|
|
|
|
},
|
|
|
|
distanceTo: function ( v ) {
|
|
|
|
return Math.sqrt( this.distanceToSquared( v ) );
|
|
|
|
},
|
|
|
|
distanceToSquared: function ( v ) {
|
|
|
|
var dx = this.x - v.x;
|
|
var dy = this.y - v.y;
|
|
var dz = this.z - v.z;
|
|
|
|
return dx * dx + dy * dy + dz * dz;
|
|
|
|
},
|
|
|
|
setEulerFromRotationMatrix: function ( m, order ) {
|
|
|
|
THREE.error( 'THREE.Vector3: .setEulerFromRotationMatrix() has been removed. Use Euler.setFromRotationMatrix() instead.' );
|
|
|
|
},
|
|
|
|
setEulerFromQuaternion: function ( q, order ) {
|
|
|
|
THREE.error( 'THREE.Vector3: .setEulerFromQuaternion() has been removed. Use Euler.setFromQuaternion() instead.' );
|
|
|
|
},
|
|
|
|
getPositionFromMatrix: function ( m ) {
|
|
|
|
THREE.warn( 'THREE.Vector3: .getPositionFromMatrix() has been renamed to .setFromMatrixPosition().' );
|
|
|
|
return this.setFromMatrixPosition( m );
|
|
|
|
},
|
|
|
|
getScaleFromMatrix: function ( m ) {
|
|
|
|
THREE.warn( 'THREE.Vector3: .getScaleFromMatrix() has been renamed to .setFromMatrixScale().' );
|
|
|
|
return this.setFromMatrixScale( m );
|
|
},
|
|
|
|
getColumnFromMatrix: function ( index, matrix ) {
|
|
|
|
THREE.warn( 'THREE.Vector3: .getColumnFromMatrix() has been renamed to .setFromMatrixColumn().' );
|
|
|
|
return this.setFromMatrixColumn( index, matrix );
|
|
|
|
},
|
|
|
|
setFromMatrixPosition: function ( m ) {
|
|
|
|
this.x = m.elements[ 12 ];
|
|
this.y = m.elements[ 13 ];
|
|
this.z = m.elements[ 14 ];
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
setFromMatrixScale: function ( m ) {
|
|
|
|
var sx = this.set( m.elements[ 0 ], m.elements[ 1 ], m.elements[ 2 ] ).length();
|
|
var sy = this.set( m.elements[ 4 ], m.elements[ 5 ], m.elements[ 6 ] ).length();
|
|
var sz = this.set( m.elements[ 8 ], m.elements[ 9 ], m.elements[ 10 ] ).length();
|
|
|
|
this.x = sx;
|
|
this.y = sy;
|
|
this.z = sz;
|
|
|
|
return this;
|
|
},
|
|
|
|
setFromMatrixColumn: function ( index, matrix ) {
|
|
|
|
var offset = index * 4;
|
|
|
|
var me = matrix.elements;
|
|
|
|
this.x = me[ offset ];
|
|
this.y = me[ offset + 1 ];
|
|
this.z = me[ offset + 2 ];
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
equals: function ( v ) {
|
|
|
|
return ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );
|
|
|
|
},
|
|
|
|
fromArray: function ( array, offset ) {
|
|
|
|
if ( offset === undefined ) offset = 0;
|
|
|
|
this.x = array[ offset ];
|
|
this.y = array[ offset + 1 ];
|
|
this.z = array[ offset + 2 ];
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
toArray: function ( array, offset ) {
|
|
|
|
if ( array === undefined ) array = [];
|
|
if ( offset === undefined ) offset = 0;
|
|
|
|
array[ offset ] = this.x;
|
|
array[ offset + 1 ] = this.y;
|
|
array[ offset + 2 ] = this.z;
|
|
|
|
return array;
|
|
|
|
},
|
|
|
|
fromAttribute: function ( attribute, index, offset ) {
|
|
|
|
if ( offset === undefined ) offset = 0;
|
|
|
|
index = index * attribute.itemSize + offset;
|
|
|
|
this.x = attribute.array[ index ];
|
|
this.y = attribute.array[ index + 1 ];
|
|
this.z = attribute.array[ index + 2 ];
|
|
|
|
return this;
|
|
|
|
},
|
|
|
|
clone: function () {
|
|
|
|
return new THREE.Vector3( this.x, this.y, this.z );
|
|
|
|
}
|
|
|
|
};
|