2
0
Эх сурвалжийг харах

Merge pull request #17159 from Mugen87/dev31

Math: Remove closures part III.
Michael Herzog 6 жил өмнө
parent
commit
f708cb468f
5 өөрчлөгдсөн 633 нэмэгдсэн , 665 устгасан
  1. 177 182
      src/math/Box3.js
  2. 20 24
      src/math/Math.js
  3. 114 118
      src/math/Matrix4.js
  4. 171 182
      src/math/Ray.js
  5. 151 159
      src/math/Triangle.js

+ 177 - 182
src/math/Box3.js

@@ -5,6 +5,15 @@ import { Vector3 } from './Vector3.js';
  * @author WestLangley / http://github.com/WestLangley
  * @author WestLangley / http://github.com/WestLangley
  */
  */
 
 
+var _points;
+var _vector;
+
+var _v0, _v1, _v2;
+var _f0, _f1, _f2;
+var _center;
+var _extents;
+var _triangleNormal;
+
 function Box3( min, max ) {
 function Box3( min, max ) {
 
 
 	this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
 	this.min = ( min !== undefined ) ? min : new Vector3( + Infinity, + Infinity, + Infinity );
@@ -105,22 +114,18 @@ Object.assign( Box3.prototype, {
 
 
 	},
 	},
 
 
-	setFromCenterAndSize: function () {
-
-		var v1 = new Vector3();
+	setFromCenterAndSize: function ( center, size ) {
 
 
-		return function setFromCenterAndSize( center, size ) {
+		if ( _vector === undefined ) _vector = new Vector3();
 
 
-			var halfSize = v1.copy( size ).multiplyScalar( 0.5 );
+		var halfSize = _vector.copy( size ).multiplyScalar( 0.5 );
 
 
-			this.min.copy( center ).sub( halfSize );
-			this.max.copy( center ).add( halfSize );
+		this.min.copy( center ).sub( halfSize );
+		this.max.copy( center ).add( halfSize );
 
 
-			return this;
-
-		};
+		return this;
 
 
-	}(),
+	},
 
 
 	setFromObject: function ( object ) {
 	setFromObject: function ( object ) {
 
 
@@ -215,47 +220,45 @@ Object.assign( Box3.prototype, {
 
 
 	},
 	},
 
 
-	expandByObject: function () {
-
-		// Computes the world-axis-aligned bounding box of an object (including its children),
-		// accounting for both the object's, and children's, world transforms
+	expandByObject: function ( object ) {
 
 
-		var scope, i, l;
+		if ( _vector === undefined ) _vector = new Vector3();
 
 
-		var v1 = new Vector3();
+		var i, l;
 
 
-		function traverse( node ) {
+		// Computes the world-axis-aligned bounding box of an object (including its children),
+		// accounting for both the object's, and children's, world transforms
 
 
-			var geometry = node.geometry;
+		object.updateWorldMatrix( false, false );
 
 
-			if ( geometry !== undefined ) {
+		var geometry = object.geometry;
 
 
-				if ( geometry.isGeometry ) {
+		if ( geometry !== undefined ) {
 
 
-					var vertices = geometry.vertices;
+			if ( geometry.isGeometry ) {
 
 
-					for ( i = 0, l = vertices.length; i < l; i ++ ) {
+				var vertices = geometry.vertices;
 
 
-						v1.copy( vertices[ i ] );
-						v1.applyMatrix4( node.matrixWorld );
+				for ( i = 0, l = vertices.length; i < l; i ++ ) {
 
 
-						scope.expandByPoint( v1 );
+					_vector.copy( vertices[ i ] );
+					_vector.applyMatrix4( object.matrixWorld );
 
 
-					}
+					this.expandByPoint( _vector );
 
 
-				} else if ( geometry.isBufferGeometry ) {
+				}
 
 
-					var attribute = geometry.attributes.position;
+			} else if ( geometry.isBufferGeometry ) {
 
 
-					if ( attribute !== undefined ) {
+				var attribute = geometry.attributes.position;
 
 
-						for ( i = 0, l = attribute.count; i < l; i ++ ) {
+				if ( attribute !== undefined ) {
 
 
-							v1.fromBufferAttribute( attribute, i ).applyMatrix4( node.matrixWorld );
+					for ( i = 0, l = attribute.count; i < l; i ++ ) {
 
 
-							scope.expandByPoint( v1 );
+						_vector.fromBufferAttribute( attribute, i ).applyMatrix4( object.matrixWorld );
 
 
-						}
+						this.expandByPoint( _vector );
 
 
 					}
 					}
 
 
@@ -265,19 +268,19 @@ Object.assign( Box3.prototype, {
 
 
 		}
 		}
 
 
-		return function expandByObject( object ) {
+		//
 
 
-			scope = this;
+		var children = object.children;
 
 
-			object.updateMatrixWorld( true );
+		for ( i = 0, l = children.length; i < l; i ++ ) {
 
 
-			object.traverse( traverse );
+			this.expandByObject( children[ i ] );
 
 
-			return this;
+		}
 
 
-		};
+		return this;
 
 
-	}(),
+	},
 
 
 	containsPoint: function ( point ) {
 	containsPoint: function ( point ) {
 
 
@@ -324,21 +327,17 @@ Object.assign( Box3.prototype, {
 
 
 	},
 	},
 
 
-	intersectsSphere: ( function () {
-
-		var closestPoint = new Vector3();
+	intersectsSphere: function ( sphere ) {
 
 
-		return function intersectsSphere( sphere ) {
+		if ( _vector === undefined ) _vector = new Vector3();
 
 
-			// Find the point on the AABB closest to the sphere center.
-			this.clampPoint( sphere.center, closestPoint );
+		// Find the point on the AABB closest to the sphere center.
+		this.clampPoint( sphere.center, _vector );
 
 
-			// If that point is inside the sphere, the AABB and sphere intersect.
-			return closestPoint.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
+		// If that point is inside the sphere, the AABB and sphere intersect.
+		return _vector.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );
 
 
-		};
-
-	} )(),
+	},
 
 
 	intersectsPlane: function ( plane ) {
 	intersectsPlane: function ( plane ) {
 
 
@@ -387,106 +386,78 @@ Object.assign( Box3.prototype, {
 
 
 	},
 	},
 
 
-	intersectsTriangle: ( function () {
-
-		// triangle centered vertices
-		var v0 = new Vector3();
-		var v1 = new Vector3();
-		var v2 = new Vector3();
-
-		// triangle edge vectors
-		var f0 = new Vector3();
-		var f1 = new Vector3();
-		var f2 = new Vector3();
-
-		var testAxis = new Vector3();
-
-		var center = new Vector3();
-		var extents = new Vector3();
-
-		var triangleNormal = new Vector3();
-
-		function satForAxes( axes ) {
+	intersectsTriangle: function ( triangle ) {
 
 
-			var i, j;
+		if ( _v0 === undefined ) {
 
 
-			for ( i = 0, j = axes.length - 3; i <= j; i += 3 ) {
+			// triangle centered vertices
 
 
-				testAxis.fromArray( axes, i );
-				// project the aabb onto the seperating axis
-				var r = extents.x * Math.abs( testAxis.x ) + extents.y * Math.abs( testAxis.y ) + extents.z * Math.abs( testAxis.z );
-				// project all 3 vertices of the triangle onto the seperating axis
-				var p0 = v0.dot( testAxis );
-				var p1 = v1.dot( testAxis );
-				var p2 = v2.dot( testAxis );
-				// actual test, basically see if either of the most extreme of the triangle points intersects r
-				if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
+			_v0 = new Vector3();
+			_v1 = new Vector3();
+			_v2 = new Vector3();
 
 
-					// points of the projected triangle are outside the projected half-length of the aabb
-					// the axis is seperating and we can exit
-					return false;
+			// triangle edge vectors
 
 
-				}
-
-			}
+			_f0 = new Vector3();
+			_f1 = new Vector3();
+			_f2 = new Vector3();
 
 
-			return true;
+			_center = new Vector3();
+			_extents = new Vector3();
+			_triangleNormal = new Vector3();
 
 
 		}
 		}
 
 
-		return function intersectsTriangle( triangle ) {
-
-			if ( this.isEmpty() ) {
+		if ( this.isEmpty() ) {
 
 
-				return false;
+			return false;
 
 
-			}
+		}
 
 
-			// compute box center and extents
-			this.getCenter( center );
-			extents.subVectors( this.max, center );
-
-			// translate triangle to aabb origin
-			v0.subVectors( triangle.a, center );
-			v1.subVectors( triangle.b, center );
-			v2.subVectors( triangle.c, center );
-
-			// compute edge vectors for triangle
-			f0.subVectors( v1, v0 );
-			f1.subVectors( v2, v1 );
-			f2.subVectors( v0, v2 );
-
-			// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
-			// make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
-			// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
-			var axes = [
-				0, - f0.z, f0.y, 0, - f1.z, f1.y, 0, - f2.z, f2.y,
-				f0.z, 0, - f0.x, f1.z, 0, - f1.x, f2.z, 0, - f2.x,
-				- f0.y, f0.x, 0, - f1.y, f1.x, 0, - f2.y, f2.x, 0
-			];
-			if ( ! satForAxes( axes ) ) {
+		// compute box center and extents
+		this.getCenter( _center );
+		_extents.subVectors( this.max, _center );
+
+		// translate triangle to aabb origin
+		_v0.subVectors( triangle.a, _center );
+		_v1.subVectors( triangle.b, _center );
+		_v2.subVectors( triangle.c, _center );
+
+		// compute edge vectors for triangle
+		_f0.subVectors( _v1, _v0 );
+		_f1.subVectors( _v2, _v1 );
+		_f2.subVectors( _v0, _v2 );
+
+		// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb
+		// make an axis testing of each of the 3 sides of the aabb against each of the 3 sides of the triangle = 9 axis of separation
+		// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)
+		var axes = [
+			0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,
+			_f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,
+			- _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0
+		];
+		if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {
 
 
-				return false;
+			return false;
 
 
-			}
+		}
 
 
-			// test 3 face normals from the aabb
-			axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
-			if ( ! satForAxes( axes ) ) {
+		// test 3 face normals from the aabb
+		axes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];
+		if ( ! satForAxes( axes, _v0, _v1, _v2, _extents ) ) {
 
 
-				return false;
+			return false;
 
 
-			}
+		}
 
 
-			// finally testing the face normal of the triangle
-			// use already existing triangle edge vectors here
-			triangleNormal.crossVectors( f0, f1 );
-			axes = [ triangleNormal.x, triangleNormal.y, triangleNormal.z ];
-			return satForAxes( axes );
+		// finally testing the face normal of the triangle
+		// use already existing triangle edge vectors here
+		_triangleNormal.crossVectors( _f0, _f1 );
+		axes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];
 
 
-		};
+		return satForAxes( axes, _v0, _v1, _v2, _extents );
 
 
-	} )(),
+	},
 
 
 	clampPoint: function ( point, target ) {
 	clampPoint: function ( point, target ) {
 
 
@@ -501,41 +472,34 @@ Object.assign( Box3.prototype, {
 
 
 	},
 	},
 
 
-	distanceToPoint: function () {
-
-		var v1 = new Vector3();
-
-		return function distanceToPoint( point ) {
-
-			var clampedPoint = v1.copy( point ).clamp( this.min, this.max );
-			return clampedPoint.sub( point ).length();
+	distanceToPoint: function ( point ) {
 
 
-		};
+		if ( _vector === undefined ) _vector = new Vector3();
 
 
-	}(),
+		var clampedPoint = _vector.copy( point ).clamp( this.min, this.max );
 
 
-	getBoundingSphere: function () {
+		return clampedPoint.sub( point ).length();
 
 
-		var v1 = new Vector3();
+	},
 
 
-		return function getBoundingSphere( target ) {
+	getBoundingSphere: function ( target ) {
 
 
-			if ( target === undefined ) {
+		if ( _vector === undefined ) _vector = new Vector3();
 
 
-				console.error( 'THREE.Box3: .getBoundingSphere() target is now required' );
-				//target = new Sphere(); // removed to avoid cyclic dependency
+		if ( target === undefined ) {
 
 
-			}
+			console.error( 'THREE.Box3: .getBoundingSphere() target is now required' );
+			//target = new Sphere(); // removed to avoid cyclic dependency
 
 
-			this.getCenter( target.center );
+		}
 
 
-			target.radius = this.getSize( v1 ).length() * 0.5;
+		this.getCenter( target.center );
 
 
-			return target;
+		target.radius = this.getSize( _vector ).length() * 0.5;
 
 
-		};
+		return target;
 
 
-	}(),
+	},
 
 
 	intersect: function ( box ) {
 	intersect: function ( box ) {
 
 
@@ -558,41 +522,41 @@ Object.assign( Box3.prototype, {
 
 
 	},
 	},
 
 
-	applyMatrix4: function () {
-
-		var points = [
-			new Vector3(),
-			new Vector3(),
-			new Vector3(),
-			new Vector3(),
-			new Vector3(),
-			new Vector3(),
-			new Vector3(),
-			new Vector3()
-		];
+	applyMatrix4: function ( matrix ) {
 
 
-		return function applyMatrix4( matrix ) {
+		if ( _points === undefined ) {
+
+			_points = [
+				new Vector3(),
+				new Vector3(),
+				new Vector3(),
+				new Vector3(),
+				new Vector3(),
+				new Vector3(),
+				new Vector3(),
+				new Vector3()
+			];
 
 
-			// transform of empty box is an empty box.
-			if ( this.isEmpty() ) return this;
+		}
 
 
-			// NOTE: I am using a binary pattern to specify all 2^3 combinations below
-			points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
-			points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
-			points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
-			points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
-			points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
-			points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
-			points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
-			points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
+		// transform of empty box is an empty box.
+		if ( this.isEmpty() ) return this;
 
 
-			this.setFromPoints( points );
+		// NOTE: I am using a binary pattern to specify all 2^3 combinations below
+		_points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000
+		_points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001
+		_points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010
+		_points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011
+		_points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100
+		_points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101
+		_points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110
+		_points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111
 
 
-			return this;
+		this.setFromPoints( _points );
 
 
-		};
+		return this;
 
 
-	}(),
+	},
 
 
 	translate: function ( offset ) {
 	translate: function ( offset ) {
 
 
@@ -611,5 +575,36 @@ Object.assign( Box3.prototype, {
 
 
 } );
 } );
 
 
+var _testAxis;
+
+function satForAxes( axes, v0, v1, v2, extents ) {
+
+	if ( _testAxis === undefined ) _testAxis = new Vector3();
+
+	var i, j;
+
+	for ( i = 0, j = axes.length - 3; i <= j; i += 3 ) {
+
+		_testAxis.fromArray( axes, i );
+		// project the aabb onto the seperating axis
+		var r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );
+		// project all 3 vertices of the triangle onto the seperating axis
+		var p0 = v0.dot( _testAxis );
+		var p1 = v1.dot( _testAxis );
+		var p2 = v2.dot( _testAxis );
+		// actual test, basically see if either of the most extreme of the triangle points intersects r
+		if ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {
+
+			// points of the projected triangle are outside the projected half-length of the aabb
+			// the axis is seperating and we can exit
+			return false;
+
+		}
+
+	}
+
+	return true;
+
+}
 
 
 export { Box3 };
 export { Box3 };

+ 20 - 24
src/math/Math.js

@@ -3,40 +3,36 @@
  * @author mrdoob / http://mrdoob.com/
  * @author mrdoob / http://mrdoob.com/
  */
  */
 
 
-var _Math = {
-
-	DEG2RAD: Math.PI / 180,
-	RAD2DEG: 180 / Math.PI,
-
-	generateUUID: ( function () {
+var _lut = [];
 
 
-		// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
+for ( var i = 0; i < 256; i ++ ) {
 
 
-		var lut = [];
+	_lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 );
 
 
-		for ( var i = 0; i < 256; i ++ ) {
+}
 
 
-			lut[ i ] = ( i < 16 ? '0' : '' ) + ( i ).toString( 16 );
+var _Math = {
 
 
-		}
+	DEG2RAD: Math.PI / 180,
+	RAD2DEG: 180 / Math.PI,
 
 
-		return function generateUUID() {
+	generateUUID: function () {
 
 
-			var d0 = Math.random() * 0xffffffff | 0;
-			var d1 = Math.random() * 0xffffffff | 0;
-			var d2 = Math.random() * 0xffffffff | 0;
-			var d3 = Math.random() * 0xffffffff | 0;
-			var uuid = lut[ d0 & 0xff ] + lut[ d0 >> 8 & 0xff ] + lut[ d0 >> 16 & 0xff ] + lut[ d0 >> 24 & 0xff ] + '-' +
-				lut[ d1 & 0xff ] + lut[ d1 >> 8 & 0xff ] + '-' + lut[ d1 >> 16 & 0x0f | 0x40 ] + lut[ d1 >> 24 & 0xff ] + '-' +
-				lut[ d2 & 0x3f | 0x80 ] + lut[ d2 >> 8 & 0xff ] + '-' + lut[ d2 >> 16 & 0xff ] + lut[ d2 >> 24 & 0xff ] +
-				lut[ d3 & 0xff ] + lut[ d3 >> 8 & 0xff ] + lut[ d3 >> 16 & 0xff ] + lut[ d3 >> 24 & 0xff ];
+		// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136
 
 
-			// .toUpperCase() here flattens concatenated strings to save heap memory space.
-			return uuid.toUpperCase();
+		var d0 = Math.random() * 0xffffffff | 0;
+		var d1 = Math.random() * 0xffffffff | 0;
+		var d2 = Math.random() * 0xffffffff | 0;
+		var d3 = Math.random() * 0xffffffff | 0;
+		var uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +
+			_lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +
+			_lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +
+			_lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];
 
 
-		};
+		// .toUpperCase() here flattens concatenated strings to save heap memory space.
+		return uuid.toUpperCase();
 
 
-	} )(),
+	},
 
 
 	clamp: function ( value, min, max ) {
 	clamp: function ( value, min, max ) {
 
 

+ 114 - 118
src/math/Matrix4.js

@@ -13,6 +13,10 @@ import { Vector3 } from './Vector3.js';
  * @author WestLangley / http://github.com/WestLangley
  * @author WestLangley / http://github.com/WestLangley
  */
  */
 
 
+var _v1, _m1;
+var _zero, _one;
+var _x, _y, _z;
+
 function Matrix4() {
 function Matrix4() {
 
 
 	this.elements = [
 	this.elements = [
@@ -119,46 +123,42 @@ Object.assign( Matrix4.prototype, {
 
 
 	},
 	},
 
 
-	extractRotation: function () {
-
-		var v1 = new Vector3();
-
-		return function extractRotation( m ) {
+	extractRotation: function ( m ) {
 
 
-			// this method does not support reflection matrices
+		if ( _v1 === undefined ) _v1 = new Vector3();
 
 
-			var te = this.elements;
-			var me = m.elements;
+		// this method does not support reflection matrices
 
 
-			var scaleX = 1 / v1.setFromMatrixColumn( m, 0 ).length();
-			var scaleY = 1 / v1.setFromMatrixColumn( m, 1 ).length();
-			var scaleZ = 1 / v1.setFromMatrixColumn( m, 2 ).length();
+		var te = this.elements;
+		var me = m.elements;
 
 
-			te[ 0 ] = me[ 0 ] * scaleX;
-			te[ 1 ] = me[ 1 ] * scaleX;
-			te[ 2 ] = me[ 2 ] * scaleX;
-			te[ 3 ] = 0;
+		var scaleX = 1 / _v1.setFromMatrixColumn( m, 0 ).length();
+		var scaleY = 1 / _v1.setFromMatrixColumn( m, 1 ).length();
+		var scaleZ = 1 / _v1.setFromMatrixColumn( m, 2 ).length();
 
 
-			te[ 4 ] = me[ 4 ] * scaleY;
-			te[ 5 ] = me[ 5 ] * scaleY;
-			te[ 6 ] = me[ 6 ] * scaleY;
-			te[ 7 ] = 0;
+		te[ 0 ] = me[ 0 ] * scaleX;
+		te[ 1 ] = me[ 1 ] * scaleX;
+		te[ 2 ] = me[ 2 ] * scaleX;
+		te[ 3 ] = 0;
 
 
-			te[ 8 ] = me[ 8 ] * scaleZ;
-			te[ 9 ] = me[ 9 ] * scaleZ;
-			te[ 10 ] = me[ 10 ] * scaleZ;
-			te[ 11 ] = 0;
+		te[ 4 ] = me[ 4 ] * scaleY;
+		te[ 5 ] = me[ 5 ] * scaleY;
+		te[ 6 ] = me[ 6 ] * scaleY;
+		te[ 7 ] = 0;
 
 
-			te[ 12 ] = 0;
-			te[ 13 ] = 0;
-			te[ 14 ] = 0;
-			te[ 15 ] = 1;
+		te[ 8 ] = me[ 8 ] * scaleZ;
+		te[ 9 ] = me[ 9 ] * scaleZ;
+		te[ 10 ] = me[ 10 ] * scaleZ;
+		te[ 11 ] = 0;
 
 
-			return this;
+		te[ 12 ] = 0;
+		te[ 13 ] = 0;
+		te[ 14 ] = 0;
+		te[ 15 ] = 1;
 
 
-		};
+		return this;
 
 
-	}(),
+	},
 
 
 	makeRotationFromEuler: function ( euler ) {
 	makeRotationFromEuler: function ( euler ) {
 
 
@@ -288,73 +288,73 @@ Object.assign( Matrix4.prototype, {
 
 
 	},
 	},
 
 
-	makeRotationFromQuaternion: function () {
+	makeRotationFromQuaternion: function ( q ) {
 
 
-		var zero = new Vector3( 0, 0, 0 );
-		var one = new Vector3( 1, 1, 1 );
+		if ( _zero === undefined ) {
 
 
-		return function makeRotationFromQuaternion( q ) {
+			_zero = new Vector3( 0, 0, 0 );
+			_one = new Vector3( 1, 1, 1 );
 
 
-			return this.compose( zero, q, one );
-
-		};
+		}
 
 
-	}(),
+		return this.compose( _zero, q, _one );
 
 
-	lookAt: function () {
+	},
 
 
-		var x = new Vector3();
-		var y = new Vector3();
-		var z = new Vector3();
+	lookAt: function ( eye, target, up ) {
 
 
-		return function lookAt( eye, target, up ) {
+		if ( _x === undefined ) {
 
 
-			var te = this.elements;
+			_x = new Vector3();
+			_y = new Vector3();
+			_z = new Vector3();
 
 
-			z.subVectors( eye, target );
+		}
 
 
-			if ( z.lengthSq() === 0 ) {
+		var te = this.elements;
 
 
-				// eye and target are in the same position
+		_z.subVectors( eye, target );
 
 
-				z.z = 1;
+		if ( _z.lengthSq() === 0 ) {
 
 
-			}
+			// eye and target are in the same position
 
 
-			z.normalize();
-			x.crossVectors( up, z );
+			_z.z = 1;
 
 
-			if ( x.lengthSq() === 0 ) {
+		}
 
 
-				// up and z are parallel
+		_z.normalize();
+		_x.crossVectors( up, _z );
 
 
-				if ( Math.abs( up.z ) === 1 ) {
+		if ( _x.lengthSq() === 0 ) {
 
 
-					z.x += 0.0001;
+			// up and z are parallel
 
 
-				} else {
+			if ( Math.abs( up.z ) === 1 ) {
 
 
-					z.z += 0.0001;
+				_z.x += 0.0001;
 
 
-				}
+			} else {
 
 
-				z.normalize();
-				x.crossVectors( up, z );
+				_z.z += 0.0001;
 
 
 			}
 			}
 
 
-			x.normalize();
-			y.crossVectors( z, x );
+			_z.normalize();
+			_x.crossVectors( up, _z );
 
 
-			te[ 0 ] = x.x; te[ 4 ] = y.x; te[ 8 ] = z.x;
-			te[ 1 ] = x.y; te[ 5 ] = y.y; te[ 9 ] = z.y;
-			te[ 2 ] = x.z; te[ 6 ] = y.z; te[ 10 ] = z.z;
+		}
 
 
-			return this;
+		_x.normalize();
+		_y.crossVectors( _z, _x );
 
 
-		};
+		te[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;
+		te[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;
+		te[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;
 
 
-	}(),
+		return this;
+
+	},
 
 
 	multiply: function ( m, n ) {
 	multiply: function ( m, n ) {
 
 
@@ -428,29 +428,25 @@ Object.assign( Matrix4.prototype, {
 
 
 	},
 	},
 
 
-	applyToBufferAttribute: function () {
-
-		var v1 = new Vector3();
+	applyToBufferAttribute: function ( attribute ) {
 
 
-		return function applyToBufferAttribute( attribute ) {
+		if ( _v1 === undefined ) _v1 = new Vector3();
 
 
-			for ( var i = 0, l = attribute.count; i < l; i ++ ) {
+		for ( var i = 0, l = attribute.count; i < l; i ++ ) {
 
 
-				v1.x = attribute.getX( i );
-				v1.y = attribute.getY( i );
-				v1.z = attribute.getZ( i );
+			_v1.x = attribute.getX( i );
+			_v1.y = attribute.getY( i );
+			_v1.z = attribute.getZ( i );
 
 
-				v1.applyMatrix4( this );
+			_v1.applyMatrix4( this );
 
 
-				attribute.setXYZ( i, v1.x, v1.y, v1.z );
+			attribute.setXYZ( i, _v1.x, _v1.y, _v1.z );
 
 
-			}
-
-			return attribute;
+		}
 
 
-		};
+		return attribute;
 
 
-	}(),
+	},
 
 
 	determinant: function () {
 	determinant: function () {
 
 
@@ -784,57 +780,57 @@ Object.assign( Matrix4.prototype, {
 
 
 	},
 	},
 
 
-	decompose: function () {
+	decompose: function ( position, quaternion, scale ) {
 
 
-		var vector = new Vector3();
-		var matrix = new Matrix4();
+		if ( _m1 === undefined ) {
 
 
-		return function decompose( position, quaternion, scale ) {
+			_m1 = new Matrix4();
+			_v1 = new Vector3();
 
 
-			var te = this.elements;
+		}
 
 
-			var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
-			var sy = vector.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
-			var sz = vector.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
+		var te = this.elements;
 
 
-			// if determine is negative, we need to invert one scale
-			var det = this.determinant();
-			if ( det < 0 ) sx = - sx;
+		var sx = _v1.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
+		var sy = _v1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
+		var sz = _v1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
 
 
-			position.x = te[ 12 ];
-			position.y = te[ 13 ];
-			position.z = te[ 14 ];
+		// if determine is negative, we need to invert one scale
+		var det = this.determinant();
+		if ( det < 0 ) sx = - sx;
 
 
-			// scale the rotation part
-			matrix.copy( this );
+		position.x = te[ 12 ];
+		position.y = te[ 13 ];
+		position.z = te[ 14 ];
 
 
-			var invSX = 1 / sx;
-			var invSY = 1 / sy;
-			var invSZ = 1 / sz;
+		// scale the rotation part
+		_m1.copy( this );
 
 
-			matrix.elements[ 0 ] *= invSX;
-			matrix.elements[ 1 ] *= invSX;
-			matrix.elements[ 2 ] *= invSX;
+		var invSX = 1 / sx;
+		var invSY = 1 / sy;
+		var invSZ = 1 / sz;
 
 
-			matrix.elements[ 4 ] *= invSY;
-			matrix.elements[ 5 ] *= invSY;
-			matrix.elements[ 6 ] *= invSY;
+		_m1.elements[ 0 ] *= invSX;
+		_m1.elements[ 1 ] *= invSX;
+		_m1.elements[ 2 ] *= invSX;
 
 
-			matrix.elements[ 8 ] *= invSZ;
-			matrix.elements[ 9 ] *= invSZ;
-			matrix.elements[ 10 ] *= invSZ;
+		_m1.elements[ 4 ] *= invSY;
+		_m1.elements[ 5 ] *= invSY;
+		_m1.elements[ 6 ] *= invSY;
 
 
-			quaternion.setFromRotationMatrix( matrix );
+		_m1.elements[ 8 ] *= invSZ;
+		_m1.elements[ 9 ] *= invSZ;
+		_m1.elements[ 10 ] *= invSZ;
 
 
-			scale.x = sx;
-			scale.y = sy;
-			scale.z = sz;
+		quaternion.setFromRotationMatrix( _m1 );
 
 
-			return this;
+		scale.x = sx;
+		scale.y = sy;
+		scale.z = sz;
 
 
-		};
+		return this;
 
 
-	}(),
+	},
 
 
 	makePerspective: function ( left, right, top, bottom, near, far ) {
 	makePerspective: function ( left, right, top, bottom, near, far ) {
 
 

+ 171 - 182
src/math/Ray.js

@@ -4,6 +4,10 @@ import { Vector3 } from './Vector3.js';
  * @author bhouston / http://clara.io
  * @author bhouston / http://clara.io
  */
  */
 
 
+var _vector;
+var _segCenter, _segDir, _diff;
+var _diff, _edge1, _edge2, _normal;
+
 function Ray( origin, direction ) {
 function Ray( origin, direction ) {
 
 
 	this.origin = ( origin !== undefined ) ? origin : new Vector3();
 	this.origin = ( origin !== undefined ) ? origin : new Vector3();
@@ -58,19 +62,15 @@ Object.assign( Ray.prototype, {
 
 
 	},
 	},
 
 
-	recast: function () {
-
-		var v1 = new Vector3();
+	recast: function ( t ) {
 
 
-		return function recast( t ) {
+		if ( _vector === undefined ) _vector = new Vector3();
 
 
-			this.origin.copy( this.at( t, v1 ) );
+		this.origin.copy( this.at( t, _vector ) );
 
 
-			return this;
-
-		};
+		return this;
 
 
-	}(),
+	},
 
 
 	closestPointToPoint: function ( point, target ) {
 	closestPointToPoint: function ( point, target ) {
 
 
@@ -101,94 +101,82 @@ Object.assign( Ray.prototype, {
 
 
 	},
 	},
 
 
-	distanceSqToPoint: function () {
-
-		var v1 = new Vector3();
-
-		return function distanceSqToPoint( point ) {
-
-			var directionDistance = v1.subVectors( point, this.origin ).dot( this.direction );
+	distanceSqToPoint: function ( point ) {
 
 
-			// point behind the ray
+		if ( _vector === undefined ) _vector = new Vector3();
 
 
-			if ( directionDistance < 0 ) {
+		var directionDistance = _vector.subVectors( point, this.origin ).dot( this.direction );
 
 
-				return this.origin.distanceToSquared( point );
+		// point behind the ray
 
 
-			}
-
-			v1.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
-
-			return v1.distanceToSquared( point );
+		if ( directionDistance < 0 ) {
 
 
-		};
+			return this.origin.distanceToSquared( point );
 
 
-	}(),
+		}
 
 
-	distanceSqToSegment: function () {
+		_vector.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
 
 
-		var segCenter = new Vector3();
-		var segDir = new Vector3();
-		var diff = new Vector3();
+		return _vector.distanceToSquared( point );
 
 
-		return function distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
+	},
 
 
-			// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
-			// It returns the min distance between the ray and the segment
-			// defined by v0 and v1
-			// It can also set two optional targets :
-			// - The closest point on the ray
-			// - The closest point on the segment
+	distanceSqToSegment: function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
 
 
-			segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
-			segDir.copy( v1 ).sub( v0 ).normalize();
-			diff.copy( this.origin ).sub( segCenter );
+		if ( _segCenter === undefined ) {
 
 
-			var segExtent = v0.distanceTo( v1 ) * 0.5;
-			var a01 = - this.direction.dot( segDir );
-			var b0 = diff.dot( this.direction );
-			var b1 = - diff.dot( segDir );
-			var c = diff.lengthSq();
-			var det = Math.abs( 1 - a01 * a01 );
-			var s0, s1, sqrDist, extDet;
+			_segCenter = new Vector3();
+			_segDir = new Vector3();
+			_diff = new Vector3();
 
 
-			if ( det > 0 ) {
+		}
 
 
-				// The ray and segment are not parallel.
+		// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
+		// It returns the min distance between the ray and the segment
+		// defined by v0 and v1
+		// It can also set two optional targets :
+		// - The closest point on the ray
+		// - The closest point on the segment
 
 
-				s0 = a01 * b1 - b0;
-				s1 = a01 * b0 - b1;
-				extDet = segExtent * det;
+		_segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );
+		_segDir.copy( v1 ).sub( v0 ).normalize();
+		_diff.copy( this.origin ).sub( _segCenter );
 
 
-				if ( s0 >= 0 ) {
+		var segExtent = v0.distanceTo( v1 ) * 0.5;
+		var a01 = - this.direction.dot( _segDir );
+		var b0 = _diff.dot( this.direction );
+		var b1 = - _diff.dot( _segDir );
+		var c = _diff.lengthSq();
+		var det = Math.abs( 1 - a01 * a01 );
+		var s0, s1, sqrDist, extDet;
 
 
-					if ( s1 >= - extDet ) {
+		if ( det > 0 ) {
 
 
-						if ( s1 <= extDet ) {
+			// The ray and segment are not parallel.
 
 
-							// region 0
-							// Minimum at interior points of ray and segment.
+			s0 = a01 * b1 - b0;
+			s1 = a01 * b0 - b1;
+			extDet = segExtent * det;
 
 
-							var invDet = 1 / det;
-							s0 *= invDet;
-							s1 *= invDet;
-							sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
+			if ( s0 >= 0 ) {
 
 
-						} else {
+				if ( s1 >= - extDet ) {
 
 
-							// region 1
+					if ( s1 <= extDet ) {
 
 
-							s1 = segExtent;
-							s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
-							sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
+						// region 0
+						// Minimum at interior points of ray and segment.
 
 
-						}
+						var invDet = 1 / det;
+						s0 *= invDet;
+						s1 *= invDet;
+						sqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;
 
 
 					} else {
 					} else {
 
 
-						// region 5
+						// region 1
 
 
-						s1 = - segExtent;
+						s1 = segExtent;
 						s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
 						s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
 						sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
 						sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
 
 
@@ -196,97 +184,101 @@ Object.assign( Ray.prototype, {
 
 
 				} else {
 				} else {
 
 
-					if ( s1 <= - extDet ) {
+					// region 5
 
 
-						// region 4
+					s1 = - segExtent;
+					s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
+					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
 
 
-						s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
-						s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
-						sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
+				}
 
 
-					} else if ( s1 <= extDet ) {
+			} else {
 
 
-						// region 3
+				if ( s1 <= - extDet ) {
 
 
-						s0 = 0;
-						s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
-						sqrDist = s1 * ( s1 + 2 * b1 ) + c;
+					// region 4
 
 
-					} else {
+					s0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );
+					s1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
+					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
 
 
-						// region 2
+				} else if ( s1 <= extDet ) {
 
 
-						s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
-						s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
-						sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
+					// region 3
 
 
-					}
+					s0 = 0;
+					s1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );
+					sqrDist = s1 * ( s1 + 2 * b1 ) + c;
 
 
-				}
+				} else {
 
 
-			} else {
+					// region 2
 
 
-				// Ray and segment are parallel.
+					s0 = Math.max( 0, - ( a01 * segExtent + b0 ) );
+					s1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );
+					sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
 
 
-				s1 = ( a01 > 0 ) ? - segExtent : segExtent;
-				s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
-				sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
+				}
 
 
 			}
 			}
 
 
-			if ( optionalPointOnRay ) {
+		} else {
 
 
-				optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
+			// Ray and segment are parallel.
 
 
-			}
+			s1 = ( a01 > 0 ) ? - segExtent : segExtent;
+			s0 = Math.max( 0, - ( a01 * s1 + b0 ) );
+			sqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;
 
 
-			if ( optionalPointOnSegment ) {
+		}
 
 
-				optionalPointOnSegment.copy( segDir ).multiplyScalar( s1 ).add( segCenter );
+		if ( optionalPointOnRay ) {
 
 
-			}
+			optionalPointOnRay.copy( this.direction ).multiplyScalar( s0 ).add( this.origin );
 
 
-			return sqrDist;
+		}
 
 
-		};
+		if ( optionalPointOnSegment ) {
 
 
-	}(),
+			optionalPointOnSegment.copy( _segDir ).multiplyScalar( s1 ).add( _segCenter );
 
 
-	intersectSphere: function () {
+		}
 
 
-		var v1 = new Vector3();
+		return sqrDist;
 
 
-		return function intersectSphere( sphere, target ) {
+	},
 
 
-			v1.subVectors( sphere.center, this.origin );
-			var tca = v1.dot( this.direction );
-			var d2 = v1.dot( v1 ) - tca * tca;
-			var radius2 = sphere.radius * sphere.radius;
+	intersectSphere: function ( sphere, target ) {
 
 
-			if ( d2 > radius2 ) return null;
+		if ( _vector === undefined ) _vector = new Vector3();
 
 
-			var thc = Math.sqrt( radius2 - d2 );
+		_vector.subVectors( sphere.center, this.origin );
+		var tca = _vector.dot( this.direction );
+		var d2 = _vector.dot( _vector ) - tca * tca;
+		var radius2 = sphere.radius * sphere.radius;
 
 
-			// t0 = first intersect point - entrance on front of sphere
-			var t0 = tca - thc;
+		if ( d2 > radius2 ) return null;
 
 
-			// t1 = second intersect point - exit point on back of sphere
-			var t1 = tca + thc;
+		var thc = Math.sqrt( radius2 - d2 );
 
 
-			// test to see if both t0 and t1 are behind the ray - if so, return null
-			if ( t0 < 0 && t1 < 0 ) return null;
+		// t0 = first intersect point - entrance on front of sphere
+		var t0 = tca - thc;
 
 
-			// test to see if t0 is behind the ray:
-			// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
-			// in order to always return an intersect point that is in front of the ray.
-			if ( t0 < 0 ) return this.at( t1, target );
+		// t1 = second intersect point - exit point on back of sphere
+		var t1 = tca + thc;
 
 
-			// else t0 is in front of the ray, so return the first collision point scaled by t0
-			return this.at( t0, target );
+		// test to see if both t0 and t1 are behind the ray - if so, return null
+		if ( t0 < 0 && t1 < 0 ) return null;
 
 
-		};
+		// test to see if t0 is behind the ray:
+		// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,
+		// in order to always return an intersect point that is in front of the ray.
+		if ( t0 < 0 ) return this.at( t1, target );
 
 
-	}(),
+		// else t0 is in front of the ray, so return the first collision point scaled by t0
+		return this.at( t0, target );
+
+	},
 
 
 	intersectsSphere: function ( sphere ) {
 	intersectsSphere: function ( sphere ) {
 
 
@@ -430,100 +422,97 @@ Object.assign( Ray.prototype, {
 
 
 	},
 	},
 
 
-	intersectsBox: ( function () {
-
-		var v = new Vector3();
-
-		return function intersectsBox( box ) {
+	intersectsBox: function ( box ) {
 
 
-			return this.intersectBox( box, v ) !== null;
+		if ( _vector === undefined ) _vector = new Vector3();
 
 
-		};
+		return this.intersectBox( box, _vector ) !== null;
 
 
-	} )(),
+	},
 
 
-	intersectTriangle: function () {
+	intersectTriangle: function ( a, b, c, backfaceCulling, target ) {
 
 
 		// Compute the offset origin, edges, and normal.
 		// Compute the offset origin, edges, and normal.
-		var diff = new Vector3();
-		var edge1 = new Vector3();
-		var edge2 = new Vector3();
-		var normal = new Vector3();
 
 
-		return function intersectTriangle( a, b, c, backfaceCulling, target ) {
+		if ( _diff === undefined ) {
 
 
-			// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
+			_diff = new Vector3();
+			_edge1 = new Vector3();
+			_edge2 = new Vector3();
+			_normal = new Vector3();
 
 
-			edge1.subVectors( b, a );
-			edge2.subVectors( c, a );
-			normal.crossVectors( edge1, edge2 );
+		}
 
 
-			// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
-			// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
-			//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
-			//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
-			//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
-			var DdN = this.direction.dot( normal );
-			var sign;
+		// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h
 
 
-			if ( DdN > 0 ) {
+		_edge1.subVectors( b, a );
+		_edge2.subVectors( c, a );
+		_normal.crossVectors( _edge1, _edge2 );
 
 
-				if ( backfaceCulling ) return null;
-				sign = 1;
+		// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,
+		// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by
+		//   |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))
+		//   |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))
+		//   |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)
+		var DdN = this.direction.dot( _normal );
+		var sign;
 
 
-			} else if ( DdN < 0 ) {
+		if ( DdN > 0 ) {
 
 
-				sign = - 1;
-				DdN = - DdN;
+			if ( backfaceCulling ) return null;
+			sign = 1;
 
 
-			} else {
+		} else if ( DdN < 0 ) {
 
 
-				return null;
+			sign = - 1;
+			DdN = - DdN;
 
 
-			}
+		} else {
+
+			return null;
 
 
-			diff.subVectors( this.origin, a );
-			var DdQxE2 = sign * this.direction.dot( edge2.crossVectors( diff, edge2 ) );
+		}
 
 
-			// b1 < 0, no intersection
-			if ( DdQxE2 < 0 ) {
+		_diff.subVectors( this.origin, a );
+		var DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );
 
 
-				return null;
+		// b1 < 0, no intersection
+		if ( DdQxE2 < 0 ) {
 
 
-			}
+			return null;
 
 
-			var DdE1xQ = sign * this.direction.dot( edge1.cross( diff ) );
+		}
 
 
-			// b2 < 0, no intersection
-			if ( DdE1xQ < 0 ) {
+		var DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );
 
 
-				return null;
+		// b2 < 0, no intersection
+		if ( DdE1xQ < 0 ) {
 
 
-			}
+			return null;
 
 
-			// b1+b2 > 1, no intersection
-			if ( DdQxE2 + DdE1xQ > DdN ) {
+		}
 
 
-				return null;
+		// b1+b2 > 1, no intersection
+		if ( DdQxE2 + DdE1xQ > DdN ) {
 
 
-			}
+			return null;
 
 
-			// Line intersects triangle, check if ray does.
-			var QdN = - sign * diff.dot( normal );
+		}
 
 
-			// t < 0, no intersection
-			if ( QdN < 0 ) {
+		// Line intersects triangle, check if ray does.
+		var QdN = - sign * _diff.dot( _normal );
 
 
-				return null;
+		// t < 0, no intersection
+		if ( QdN < 0 ) {
 
 
-			}
+			return null;
 
 
-			// Ray intersects triangle.
-			return this.at( QdN / DdN, target );
+		}
 
 
-		};
+		// Ray intersects triangle.
+		return this.at( QdN / DdN, target );
 
 
-	}(),
+	},
 
 
 	applyMatrix4: function ( matrix4 ) {
 	applyMatrix4: function ( matrix4 ) {
 
 

+ 151 - 159
src/math/Triangle.js

@@ -5,6 +5,9 @@ import { Vector3 } from './Vector3.js';
  * @author mrdoob / http://mrdoob.com/
  * @author mrdoob / http://mrdoob.com/
  */
  */
 
 
+var _v0, _v1, _v2, _v3;
+var _vab, _vac, _vbc, _vap, _vbp, _vcp;
+
 function Triangle( a, b, c ) {
 function Triangle( a, b, c ) {
 
 
 	this.a = ( a !== undefined ) ? a : new Vector3();
 	this.a = ( a !== undefined ) ? a : new Vector3();
@@ -15,134 +18,122 @@ function Triangle( a, b, c ) {
 
 
 Object.assign( Triangle, {
 Object.assign( Triangle, {
 
 
-	getNormal: function () {
-
-		var v0 = new Vector3();
-
-		return function getNormal( a, b, c, target ) {
+	getNormal: function ( a, b, c, target ) {
 
 
-			if ( target === undefined ) {
+		if ( _v0 === undefined ) _v0 = new Vector3();
 
 
-				console.warn( 'THREE.Triangle: .getNormal() target is now required' );
-				target = new Vector3();
+		if ( target === undefined ) {
 
 
-			}
+			console.warn( 'THREE.Triangle: .getNormal() target is now required' );
+			target = new Vector3();
 
 
-			target.subVectors( c, b );
-			v0.subVectors( a, b );
-			target.cross( v0 );
+		}
 
 
-			var targetLengthSq = target.lengthSq();
-			if ( targetLengthSq > 0 ) {
+		target.subVectors( c, b );
+		_v0.subVectors( a, b );
+		target.cross( _v0 );
 
 
-				return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
+		var targetLengthSq = target.lengthSq();
+		if ( targetLengthSq > 0 ) {
 
 
-			}
+			return target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );
 
 
-			return target.set( 0, 0, 0 );
+		}
 
 
-		};
+		return target.set( 0, 0, 0 );
 
 
-	}(),
+	},
 
 
 	// static/instance method to calculate barycentric coordinates
 	// static/instance method to calculate barycentric coordinates
 	// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
 	// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
-	getBarycoord: function () {
-
-		var v0 = new Vector3();
-		var v1 = new Vector3();
-		var v2 = new Vector3();
+	getBarycoord: function ( point, a, b, c, target ) {
 
 
-		return function getBarycoord( point, a, b, c, target ) {
+		if ( _v1 === undefined ) {
 
 
-			v0.subVectors( c, a );
-			v1.subVectors( b, a );
-			v2.subVectors( point, a );
+			_v0 = new Vector3();
+			_v1 = new Vector3();
+			_v2 = new Vector3();
 
 
-			var dot00 = v0.dot( v0 );
-			var dot01 = v0.dot( v1 );
-			var dot02 = v0.dot( v2 );
-			var dot11 = v1.dot( v1 );
-			var dot12 = v1.dot( v2 );
-
-			var denom = ( dot00 * dot11 - dot01 * dot01 );
-
-			if ( target === undefined ) {
-
-				console.warn( 'THREE.Triangle: .getBarycoord() target is now required' );
-				target = new Vector3();
+		}
 
 
-			}
+		_v0.subVectors( c, a );
+		_v1.subVectors( b, a );
+		_v2.subVectors( point, a );
 
 
-			// collinear or singular triangle
-			if ( denom === 0 ) {
+		var dot00 = _v0.dot( _v0 );
+		var dot01 = _v0.dot( _v1 );
+		var dot02 = _v0.dot( _v2 );
+		var dot11 = _v1.dot( _v1 );
+		var dot12 = _v1.dot( _v2 );
 
 
-				// arbitrary location outside of triangle?
-				// not sure if this is the best idea, maybe should be returning undefined
-				return target.set( - 2, - 1, - 1 );
+		var denom = ( dot00 * dot11 - dot01 * dot01 );
 
 
-			}
+		if ( target === undefined ) {
 
 
-			var invDenom = 1 / denom;
-			var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
-			var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
+			console.warn( 'THREE.Triangle: .getBarycoord() target is now required' );
+			target = new Vector3();
 
 
-			// barycentric coordinates must always sum to 1
-			return target.set( 1 - u - v, v, u );
+		}
 
 
-		};
+		// collinear or singular triangle
+		if ( denom === 0 ) {
 
 
-	}(),
+			// arbitrary location outside of triangle?
+			// not sure if this is the best idea, maybe should be returning undefined
+			return target.set( - 2, - 1, - 1 );
 
 
-	containsPoint: function () {
+		}
 
 
-		var v1 = new Vector3();
+		var invDenom = 1 / denom;
+		var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
+		var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
 
 
-		return function containsPoint( point, a, b, c ) {
+		// barycentric coordinates must always sum to 1
+		return target.set( 1 - u - v, v, u );
 
 
-			Triangle.getBarycoord( point, a, b, c, v1 );
+	},
 
 
-			return ( v1.x >= 0 ) && ( v1.y >= 0 ) && ( ( v1.x + v1.y ) <= 1 );
+	containsPoint: function ( point, a, b, c ) {
 
 
-		};
+		if ( _v3 === undefined ) _v3 = new Vector3();
 
 
-	}(),
+		Triangle.getBarycoord( point, a, b, c, _v3 );
 
 
-	getUV: function () {
+		return ( _v3.x >= 0 ) && ( _v3.y >= 0 ) && ( ( _v3.x + _v3.y ) <= 1 );
 
 
-		var barycoord = new Vector3();
+	},
 
 
-		return function getUV( point, p1, p2, p3, uv1, uv2, uv3, target ) {
+	getUV: function ( point, p1, p2, p3, uv1, uv2, uv3, target ) {
 
 
-			this.getBarycoord( point, p1, p2, p3, barycoord );
+		if ( _v3 === undefined ) _v3 = new Vector3();
 
 
-			target.set( 0, 0 );
-			target.addScaledVector( uv1, barycoord.x );
-			target.addScaledVector( uv2, barycoord.y );
-			target.addScaledVector( uv3, barycoord.z );
+		this.getBarycoord( point, p1, p2, p3, _v3 );
 
 
-			return target;
+		target.set( 0, 0 );
+		target.addScaledVector( uv1, _v3.x );
+		target.addScaledVector( uv2, _v3.y );
+		target.addScaledVector( uv3, _v3.z );
 
 
-		};
+		return target;
 
 
-	}(),
+	},
 
 
-	isFrontFacing: function () {
+	isFrontFacing: function ( a, b, c, direction ) {
 
 
-		var v0 = new Vector3();
-		var v1 = new Vector3();
+		if ( _v1 === undefined ) {
 
 
-		return function isFrontFacing( a, b, c, direction ) {
+			_v0 = new Vector3();
+			_v1 = new Vector3();
 
 
-			v0.subVectors( c, b );
-			v1.subVectors( a, b );
+		}
 
 
-			// strictly front facing
-			return ( v0.cross( v1 ).dot( direction ) < 0 ) ? true : false;
+		_v0.subVectors( c, b );
+		_v1.subVectors( a, b );
 
 
-		};
+		// strictly front facing
+		return ( _v0.cross( _v1 ).dot( direction ) < 0 ) ? true : false;
 
 
-	}()
+	}
 
 
 } );
 } );
 
 
@@ -186,19 +177,19 @@ Object.assign( Triangle.prototype, {
 
 
 	getArea: function () {
 	getArea: function () {
 
 
-		var v0 = new Vector3();
-		var v1 = new Vector3();
+		if ( _v1 === undefined ) {
 
 
-		return function getArea() {
+			_v0 = new Vector3();
+			_v1 = new Vector3();
 
 
-			v0.subVectors( this.c, this.b );
-			v1.subVectors( this.a, this.b );
+		}
 
 
-			return v0.cross( v1 ).length() * 0.5;
+		_v0.subVectors( this.c, this.b );
+		_v1.subVectors( this.a, this.b );
 
 
-		};
+		return _v0.cross( _v1 ).length() * 0.5;
 
 
-	}(),
+	},
 
 
 	getMidpoint: function ( target ) {
 	getMidpoint: function ( target ) {
 
 
@@ -262,103 +253,104 @@ Object.assign( Triangle.prototype, {
 
 
 	},
 	},
 
 
-	closestPointToPoint: function () {
+	closestPointToPoint: function ( p, target ) {
+
+		if ( _vab === undefined ) {
 
 
-		var vab = new Vector3();
-		var vac = new Vector3();
-		var vbc = new Vector3();
-		var vap = new Vector3();
-		var vbp = new Vector3();
-		var vcp = new Vector3();
+			_vab = new Vector3();
+			_vac = new Vector3();
+			_vbc = new Vector3();
+			_vap = new Vector3();
+			_vbp = new Vector3();
+			_vcp = new Vector3();
 
 
-		return function closestPointToPoint( p, target ) {
+		}
 
 
-			if ( target === undefined ) {
+		if ( target === undefined ) {
 
 
-				console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' );
-				target = new Vector3();
+			console.warn( 'THREE.Triangle: .closestPointToPoint() target is now required' );
+			target = new Vector3();
 
 
-			}
+		}
 
 
-			var a = this.a, b = this.b, c = this.c;
-			var v, w;
+		var a = this.a, b = this.b, c = this.c;
+		var v, w;
 
 
-			// algorithm thanks to Real-Time Collision Detection by Christer Ericson,
-			// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
-			// under the accompanying license; see chapter 5.1.5 for detailed explanation.
-			// basically, we're distinguishing which of the voronoi regions of the triangle
-			// the point lies in with the minimum amount of redundant computation.
+		// algorithm thanks to Real-Time Collision Detection by Christer Ericson,
+		// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,
+		// under the accompanying license; see chapter 5.1.5 for detailed explanation.
+		// basically, we're distinguishing which of the voronoi regions of the triangle
+		// the point lies in with the minimum amount of redundant computation.
 
 
-			vab.subVectors( b, a );
-			vac.subVectors( c, a );
-			vap.subVectors( p, a );
-			var d1 = vab.dot( vap );
-			var d2 = vac.dot( vap );
-			if ( d1 <= 0 && d2 <= 0 ) {
+		_vab.subVectors( b, a );
+		_vac.subVectors( c, a );
+		_vap.subVectors( p, a );
+		var d1 = _vab.dot( _vap );
+		var d2 = _vac.dot( _vap );
+		if ( d1 <= 0 && d2 <= 0 ) {
 
 
-				// vertex region of A; barycentric coords (1, 0, 0)
-				return target.copy( a );
+			// vertex region of A; barycentric coords (1, 0, 0)
+			return target.copy( a );
 
 
-			}
+		}
 
 
-			vbp.subVectors( p, b );
-			var d3 = vab.dot( vbp );
-			var d4 = vac.dot( vbp );
-			if ( d3 >= 0 && d4 <= d3 ) {
+		_vbp.subVectors( p, b );
+		var d3 = _vab.dot( _vbp );
+		var d4 = _vac.dot( _vbp );
+		if ( d3 >= 0 && d4 <= d3 ) {
 
 
-				// vertex region of B; barycentric coords (0, 1, 0)
-				return target.copy( b );
+			// vertex region of B; barycentric coords (0, 1, 0)
+			return target.copy( b );
 
 
-			}
+		}
 
 
-			var vc = d1 * d4 - d3 * d2;
-			if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
+		var vc = d1 * d4 - d3 * d2;
+		if ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {
 
 
-				v = d1 / ( d1 - d3 );
-				// edge region of AB; barycentric coords (1-v, v, 0)
-				return target.copy( a ).addScaledVector( vab, v );
+			v = d1 / ( d1 - d3 );
+			// edge region of AB; barycentric coords (1-v, v, 0)
+			return target.copy( a ).addScaledVector( _vab, v );
 
 
-			}
+		}
 
 
-			vcp.subVectors( p, c );
-			var d5 = vab.dot( vcp );
-			var d6 = vac.dot( vcp );
-			if ( d6 >= 0 && d5 <= d6 ) {
+		_vcp.subVectors( p, c );
+		var d5 = _vab.dot( _vcp );
+		var d6 = _vac.dot( _vcp );
+		if ( d6 >= 0 && d5 <= d6 ) {
 
 
-				// vertex region of C; barycentric coords (0, 0, 1)
-				return target.copy( c );
+			// vertex region of C; barycentric coords (0, 0, 1)
+			return target.copy( c );
 
 
-			}
+		}
 
 
-			var vb = d5 * d2 - d1 * d6;
-			if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
+		var vb = d5 * d2 - d1 * d6;
+		if ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {
 
 
-				w = d2 / ( d2 - d6 );
-				// edge region of AC; barycentric coords (1-w, 0, w)
-				return target.copy( a ).addScaledVector( vac, w );
+			w = d2 / ( d2 - d6 );
+			// edge region of AC; barycentric coords (1-w, 0, w)
+			return target.copy( a ).addScaledVector( _vac, w );
 
 
-			}
+		}
 
 
-			var va = d3 * d6 - d5 * d4;
-			if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
+		var va = d3 * d6 - d5 * d4;
+		if ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {
 
 
-				vbc.subVectors( c, b );
-				w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
-				// edge region of BC; barycentric coords (0, 1-w, w)
-				return target.copy( b ).addScaledVector( vbc, w ); // edge region of BC
+			_vbc.subVectors( c, b );
+			w = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );
+			// edge region of BC; barycentric coords (0, 1-w, w)
+			return target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC
 
 
-			}
+		}
 
 
-			// face region
-			var denom = 1 / ( va + vb + vc );
-			// u = va * denom
-			v = vb * denom;
-			w = vc * denom;
-			return target.copy( a ).addScaledVector( vab, v ).addScaledVector( vac, w );
+		// face region
+		var denom = 1 / ( va + vb + vc );
+		// u = va * denom
+		v = vb * denom;
+		w = vc * denom;
 
 
-		};
+		return target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );
 
 
-	}(),
+	},
 
 
 	equals: function ( triangle ) {
 	equals: function ( triangle ) {