Browse Source

Merge branch 'dev' into FBX-Loader-AnimationFixes

Kyle Larson 8 years ago
parent
commit
cb7628ae9c
68 changed files with 2295 additions and 2210 deletions
  1. 249 297
      build/three.js
  2. 208 234
      build/three.min.js
  3. 249 297
      build/three.module.js
  4. 3 3
      docs/api/lights/RectAreaLight.html
  5. 4 4
      editor/js/libs/ui.js
  6. 80 42
      examples/js/loaders/FBXLoader2.js
  7. 15 19
      examples/js/renderers/CSS3DRenderer.js
  8. 75 15
      examples/js/vr/PaintViveController.js
  9. 15 11
      examples/webvr_vive_paint.html
  10. 2 4
      src/animation/AnimationAction.js
  11. 47 53
      src/animation/AnimationClip.js
  12. 251 260
      src/animation/AnimationMixer.js
  13. 2 5
      src/animation/AnimationObjectGroup.js
  14. 275 276
      src/animation/PropertyBinding.js
  15. 4 6
      src/animation/PropertyMixer.js
  16. 1 2
      src/audio/Audio.js
  17. 10 8
      src/core/BufferAttribute.js
  18. 22 37
      src/core/BufferGeometry.js
  19. 2 4
      src/core/Clock.js
  20. 2 2
      src/core/EventDispatcher.js
  21. 2 4
      src/core/Face3.js
  22. 32 47
      src/core/Geometry.js
  23. 10 8
      src/core/InterleavedBuffer.js
  24. 19 10
      src/core/InterleavedBufferAttribute.js
  25. 2 4
      src/core/Layers.js
  26. 2 5
      src/core/Object3D.js
  27. 2 6
      src/core/Raycaster.js
  28. 3 4
      src/extras/core/Curve.js
  29. 7 7
      src/extras/core/ShapePath.js
  30. 1 1
      src/geometries/ExtrudeGeometry.js
  31. 37 41
      src/loaders/Loader.js
  32. 12 11
      src/materials/Material.js
  33. 2 4
      src/materials/MultiMaterial.js
  34. 2 4
      src/math/Box2.js
  35. 3 7
      src/math/Box3.js
  36. 27 29
      src/math/Color.js
  37. 2 4
      src/math/Cylindrical.js
  38. 48 32
      src/math/Euler.js
  39. 3 6
      src/math/Frustum.js
  40. 14 16
      src/math/Interpolant.js
  41. 2 4
      src/math/Line3.js
  42. 3 7
      src/math/Matrix3.js
  43. 9 27
      src/math/Matrix4.js
  44. 2 4
      src/math/Plane.js
  45. 121 102
      src/math/Quaternion.js
  46. 2 6
      src/math/Ray.js
  47. 3 7
      src/math/Sphere.js
  48. 2 4
      src/math/Spherical.js
  49. 60 64
      src/math/Triangle.js
  50. 39 37
      src/math/Vector2.js
  51. 10 30
      src/math/Vector3.js
  52. 4 12
      src/math/Vector4.js
  53. 2 4
      src/math/interpolants/CubicInterpolant.js
  54. 3 6
      src/math/interpolants/DiscreteInterpolant.js
  55. 3 6
      src/math/interpolants/LinearInterpolant.js
  56. 3 6
      src/math/interpolants/QuaternionLinearInterpolant.js
  57. 0 1
      src/objects/LOD.js
  58. 0 1
      src/objects/SkinnedMesh.js
  59. 1 0
      src/renderers/WebGL2Renderer.js
  60. 2 5
      src/renderers/WebGLRenderTarget.js
  61. 1 0
      src/renderers/WebGLRenderer.js
  62. 1 0
      src/renderers/webgl/WebGLClipping.js
  63. 1 0
      src/renderers/webgl/WebGLProperties.js
  64. 1 0
      src/renderers/webgl/WebGLShader.js
  65. 11 8
      src/textures/Texture.js
  66. 1 0
      utils/exporters/blender/addons/io_three/constants.py
  67. 258 36
      utils/exporters/blender/addons/io_three/exporter/api/mesh.py
  68. 4 4
      utils/exporters/blender/addons/io_three/exporter/geometry.py

File diff suppressed because it is too large
+ 249 - 297
build/three.js


File diff suppressed because it is too large
+ 208 - 234
build/three.min.js


File diff suppressed because it is too large
+ 249 - 297
build/three.module.js


+ 3 - 3
docs/api/lights/RectAreaLight.html

@@ -52,12 +52,12 @@ scene.add(rectLight)
 		<h2>Constructor</h2>
 
 
-		<h3>[name]( [page:Integer color], [page:Float intensity], [page:Float distance], [page:Radians angle], [page:Float penumbra], [page:Float decay] )</h3>
+		<h3>[name]( [page:Integer color], [page:Float intensity], [page:Float width], [page:Float height] )</h3>
 		<div>
 			[page:Integer color] - (optional) hexadecimal color of the light. Default is 0xffffff (white).<br />
-			[page:Float intensity] - (optional) numeric value of the light's strength/intensity. Default is 1.<br /><br />
+			[page:Float intensity] - (optional) numeric value of the light's strength/intensity. Default is 1.<br />
 			[page:Float width] - (optional) width of the light. Default is 10.<br />
-			[page:Float height] - (optional) height of the light. Default is 10.
+			[page:Float height] - (optional) height of the light. Default is 10.<br /><br />
 
 			Creates a new [name].
 		</div>

+ 4 - 4
editor/js/libs/ui.js

@@ -862,10 +862,10 @@ UI.Integer.prototype.setValue = function ( value ) {
 
 };
 
-UI.Number.prototype.setStep = function ( step ) {
-
-	this.step = step;
-
+UI.Integer.prototype.setStep = function ( step ) {
+	
+	this.step = parseInt( step ); 
+	
 	return this;
 
 };

+ 80 - 42
examples/js/loaders/FBXLoader2.js

@@ -163,7 +163,9 @@
 					 * @type {[number, number, string][]}
 					 */
 					var connectionArray = FBXTree.Connections.properties.connections;
-					connectionArray.forEach( function ( connection ) {
+					for ( var connectionArrayIndex = 0, connectionArrayLength = connectionArray.length; connectionArrayIndex < connectionArrayLength; ++ connectionArrayIndex ) {
+
+						var connection = connectionArray[ connectionArrayIndex ];
 
 						if ( ! connectionMap.has( connection[ 0 ] ) ) {
 
@@ -189,7 +191,7 @@
 						var childRelationship = { ID: connection[ 0 ], relationship: connection[ 2 ] };
 						connectionMap.get( connection[ 1 ] ).children.push( childRelationship );
 
-					} );
+					}
 
 				}
 
@@ -370,7 +372,9 @@
 
 						}
 
-						childrenRelationships.forEach( function ( relationship ) {
+						for ( var childrenRelationshipsIndex = 0, childrenRelationshipsLength = childrenRelationships.length; childrenRelationshipsIndex < childrenRelationshipsLength; ++ childrenRelationshipsIndex ) {
+
+							var relationship = childrenRelationships[ childrenRelationshipsIndex ];
 
 							var type = relationship.relationship;
 							switch ( type ) {
@@ -389,7 +393,7 @@
 
 							}
 
-						} );
+						}
 
 						return parameters;
 
@@ -440,7 +444,9 @@
 
 					var subDeformers = new Map();
 					var subDeformerArray = [];
-					connections.children.forEach( function ( child ) {
+					for ( var childrenIndex = 0, childrenLength = connections.children.length; childrenIndex < childrenLength; ++ childrenIndex ) {
+
+						var child = connections.children[ childrenIndex ];
 
 						var subDeformerNode = DeformerNodes[ child.ID ];
 						var subDeformer = {
@@ -454,7 +460,7 @@
 						subDeformers.set( child.ID, subDeformer );
 						subDeformerArray.push( subDeformer );
 
-					} );
+					}
 
 					return {
 						map: subDeformers,
@@ -800,11 +806,11 @@
 								// we expect.  So we create an intermediate buffer that points to the index in the buffer,
 								// for conforming with the other functions we've written for other data.
 								var materialIndices = [];
-								materialIndexBuffer.forEach( function ( materialIndex, index ) {
+								for ( var materialIndexBufferIndex = 0, materialIndexBufferLength = materialIndexBuffer.length; materialIndexBufferIndex < materialIndexBufferLength; ++ materialIndexBufferIndex ) {
 
-									materialIndices.push( index );
+									materialIndices.push( materialIndexBufferIndex );
 
-								} );
+								}
 
 								return {
 									dataSize: 1,
@@ -966,12 +972,14 @@
 						var vertices = curve.getPoints( controlPoints.length * 1.5 );
 
 						var vertexBuffer = [];
-						vertices.forEach( function ( position ) {
+						for ( var verticesIndex = 0, verticesLength = vertices.length; verticesIndex < verticesLength; ++ verticesIndex ) {
+
+							var position = vertices[ verticesIndex ];
 
 							var array = position.toArray();
 							vertexBuffer = vertexBuffer.concat( array );
 
-						} );
+						}
 
 						var geometry = new THREE.BufferGeometry();
 						geometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( vertexBuffer ), 3 ) );
@@ -1054,7 +1062,9 @@
 								 */
 								var materials = [];
 
-								conns.children.forEach( function ( child ) {
+								for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) {
+
+									var child = conns.children[ childrenIndex ];
 
 									if ( geometryMap.has( child.ID ) ) {
 
@@ -1068,7 +1078,7 @@
 
 									}
 
-								} );
+								}
 								if ( materials.length > 1 ) {
 
 									material = new THREE.MultiMaterial( materials );
@@ -1084,11 +1094,13 @@
 								}
 								if ( geometry.FBX_Deformer ) {
 
-									materials.forEach( function ( material ) {
+									for ( var materialsIndex = 0, materialsLength = materials.length; materialsIndex < materialsLength; ++ materialsIndex ) {
+
+										var material = materials[ materialsIndex ];
 
 										material.skinning = true;
 
-									} );
+									}
 									material.skinning = true;
 									model = new THREE.SkinnedMesh( geometry, material );
 
@@ -1102,7 +1114,9 @@
 							case "NurbsCurve":
 								var geometry = null;
 
-								conns.children.forEach( function ( child ) {
+								for ( var childrenIndex = 0, childrenLength = conns.children.length; childrenIndex < childrenLength; ++ childrenIndex ) {
+
+									var child = conns.children[ childrenIndex ];
 
 									if ( geometryMap.has( child.ID ) ) {
 
@@ -1110,7 +1124,7 @@
 
 									}
 
-								} );
+								}
 
 								// FBX does not list materials for Nurbs lines, so we'll just put our own in here.
 								material = new THREE.LineBasicMaterial( { color: 0x3300ff, linewidth: 5 } );
@@ -1133,7 +1147,9 @@
 
 				}
 
-				modelArray.forEach( function ( model ) {
+				for ( var modelArrayIndex = 0, modelArrayLength = modelArray.length; modelArrayIndex < modelArrayLength; ++ modelArrayIndex ) {
+
+					var model = modelArray[ modelArrayIndex ];
 
 					var node = ModelNode[ model.FBX_ID ];
 
@@ -1183,7 +1199,7 @@
 
 					}
 
-				} );
+				}
 
 
 				// Now with the bones created, we can update the skeletons and bind them to the skinned meshes.
@@ -1206,19 +1222,24 @@
 					var PoseNode = BindPoseNode.subNodes.PoseNode;
 					var worldMatrices = new Map();
 
-					PoseNode.forEach( function ( node ) {
+					for ( var PoseNodeIndex = 0, PoseNodeLength = PoseNode.length; PoseNodeIndex < PoseNodeLength; ++ PoseNodeIndex ) {
+
+						var node = PoseNode[ PoseNodeIndex ];
 
 						var rawMatWrd = parseMatrixArray( node.subNodes.Matrix.properties.a );
 
 						worldMatrices.set( parseInt( node.id ), rawMatWrd );
 
-					} );
+					}
 
 				}
 
 				deformerMap.forEach( function ( deformer, FBX_ID ) {
 
-					deformer.array.forEach( function ( subDeformer, subDeformerIndex ) {
+					for ( var deformerArrayIndex = 0, deformerArrayLength = deformer.array.length; deformerArrayIndex < deformerArrayLength; ++ deformerArrayIndex ) {
+
+						//var subDeformer = deformer.array[ deformerArrayIndex ];
+						var subDeformerIndex = deformerArrayIndex;
 
 						/**
 						 * @type {THREE.Bone}
@@ -1226,18 +1247,20 @@
 						var bone = deformer.bones[ subDeformerIndex ];
 						if ( ! worldMatrices.has( bone.FBX_ID ) ) {
 
-							return;
+							break;
 
 						}
 						var mat = worldMatrices.get( bone.FBX_ID );
 						bone.matrixWorld.copy( mat );
 
-					} );
+					}
 
 					// Now that skeleton is in bind pose, bind to model.
 					deformer.skeleton = new THREE.Skeleton( deformer.bones );
 					var conns = connections.get( FBX_ID );
-					conns.parents.forEach( function ( parent ) {
+					for ( var parentsIndex = 0, parentsLength = conns.parents.length; parentsIndex < parentsLength; ++ parentsIndex ) {
+
+						var parent = conns.parents[ parentsIndex ];
 
 						if ( geometryMap.has( parent.ID ) ) {
 
@@ -1258,13 +1281,15 @@
 
 						}
 
-					} );
+					}
 
 				} );
 
 				// Skeleton is now bound, we are now free to set up the
 				// scene graph.
-				modelArray.forEach( function ( model ) {
+				for ( var modelArrayIndex = 0, modelArrayLength = modelArray.length; modelArrayIndex < modelArrayLength; ++ modelArrayIndex ) {
+
+					var model = modelArray[ modelArrayIndex ];
 
 					var node = ModelNode[ model.FBX_ID ];
 
@@ -1292,7 +1317,7 @@
 
 					}
 
-				} );
+				}
 
 				// Silly hack with the animation parsing.  We're gonna pretend the scene graph has a skeleton
 				// to attach animations to, since FBXs treat animations as animations for the entire scene,
@@ -2001,7 +2026,9 @@
 							var currentLayer = returnObject.layers.get( children[ childIndex ].ID );
 							layers.push( currentLayer );
 
-							currentLayer.forEach( function ( layer ) {
+							for ( var currentLayerIndex = 0, currentLayerLength = currentLayer.length; currentLayerIndex < currentLayerLength; ++ currentLayerIndex ) {
+
+								var layer = currentLayer[ currentLayerIndex ];
 
 								if ( layer ) {
 
@@ -2216,7 +2243,7 @@
 
 								}
 
-							} );
+							}
 
 						}
 
@@ -2776,7 +2803,9 @@
 
 					var bones = group.skeleton.bones;
 
-					bones.forEach( function ( bone ) {
+					for ( var bonesIndex = 0, bonesLength = bones.length; bonesIndex < bonesLength; ++ bonesIndex ) {
+
+						var bone = bones[ bonesIndex ];
 
 						var name = bone.name.replace( /.*:/, '' );
 						var parentIndex = bones.findIndex( function ( parentBone ) {
@@ -2786,15 +2815,20 @@
 						} );
 						animationData.hierarchy.push( { parent: parentIndex, name: name, keys: [] } );
 
-					} );
+					}
 
 					for ( var frame = 0; frame < stack.frames; frame ++ ) {
 
-						bones.forEach( function ( bone, boneIndex ) {
+						for ( var bonesIndex = 0, bonesLength = bones.length; bonesIndex < bonesLength; ++ bonesIndex ) {
+
+							var bone = bones[ bonesIndex ];
+							var boneIndex = bonesIndex;
 
 							var animationNode = stack.layers[ 0 ][ boneIndex ];
 
-							animationData.hierarchy.forEach( function ( node ) {
+							for ( var hierarchyIndex = 0, hierarchyLength = animationData.hierarchy.length; hierarchyIndex < hierarchyLength; ++ hierarchyIndex ) {
+
+								var node = animationData.hierarchy[ hierarchyIndex ];
 
 								if ( node.name === bone.name ) {
 
@@ -2802,9 +2836,9 @@
 
 								}
 
-							} );
+							}
 
-						} );
+						}
 
 					}
 
@@ -3047,7 +3081,9 @@
 			var skinIndexBuffer = [];
 			var skinWeightBuffer = [];
 
-			this.vertices.forEach( function ( vertex ) {
+			for ( var verticesIndex = 0, verticesLength = this.vertices.length; verticesIndex < verticesLength; ++ verticesIndex ) {
+
+				var vertex = this.vertices[ verticesIndex ];
 
 				var flatVertex = vertex.flattenToBuffers();
 				vertexBuffer = vertexBuffer.concat( flatVertex.vertexBuffer );
@@ -3056,7 +3092,7 @@
 				skinIndexBuffer = skinIndexBuffer.concat( flatVertex.skinIndexBuffer );
 				skinWeightBuffer = skinWeightBuffer.concat( flatVertex.skinWeightBuffer );
 
-			} );
+			}
 
 			return {
 				vertexBuffer: vertexBuffer,
@@ -3127,8 +3163,9 @@
 
 			var materialIndex = this.materialIndex;
 
-			this.triangles.forEach( function ( triangle ) {
+			for ( var triangleIndex = 0, triangleLength = this.triangles.length; triangleIndex < triangleLength; ++ triangleIndex ) {
 
+				var triangle = this.triangles[ triangleIndex ];
 				var flatTriangle = triangle.flattenToBuffers();
 				vertexBuffer = vertexBuffer.concat( flatTriangle.vertexBuffer );
 				normalBuffer = normalBuffer.concat( flatTriangle.normalBuffer );
@@ -3137,7 +3174,7 @@
 				skinWeightBuffer = skinWeightBuffer.concat( flatTriangle.skinWeightBuffer );
 				materialIndexBuffer = materialIndexBuffer.concat( [ materialIndex, materialIndex, materialIndex ] );
 
-			} );
+			}
 
 			return {
 				vertexBuffer: vertexBuffer,
@@ -3184,8 +3221,9 @@
 
 			var materialIndexBuffer = [];
 
-			this.faces.forEach( function ( face ) {
+			for ( var faceIndex = 0, faceLength = this.faces.length; faceIndex < faceLength; ++ faceIndex ) {
 
+				var face = this.faces[ faceIndex ];
 				var flatFace = face.flattenToBuffers();
 				vertexBuffer = vertexBuffer.concat( flatFace.vertexBuffer );
 				normalBuffer = normalBuffer.concat( flatFace.normalBuffer );
@@ -3194,7 +3232,7 @@
 				skinWeightBuffer = skinWeightBuffer.concat( flatFace.skinWeightBuffer );
 				materialIndexBuffer = materialIndexBuffer.concat( flatFace.materialIndexBuffer );
 
-			} );
+			}
 
 			return {
 				vertexBuffer: vertexBuffer,

+ 15 - 19
examples/js/renderers/CSS3DRenderer.js

@@ -10,7 +10,7 @@ THREE.CSS3DObject = function ( element ) {
 	this.element = element;
 	this.element.style.position = 'absolute';
 
-	this.addEventListener( 'removed', function ( event ) {
+	this.addEventListener( 'removed', function () {
 
 		if ( this.element.parentNode !== null ) {
 
@@ -41,7 +41,6 @@ THREE.CSS3DRenderer = function () {
 	console.log( 'THREE.CSS3DRenderer', THREE.REVISION );
 
 	var _width, _height;
-	var _widthHalf, _heightHalf;
 
 	var matrix = new THREE.Matrix4();
 
@@ -62,6 +61,10 @@ THREE.CSS3DRenderer = function () {
 
 	var cameraElement = document.createElement( 'div' );
 
+	cameraElement.style.position = 'absolute';
+	cameraElement.style.left = '50%';
+	cameraElement.style.top = '50%';
+
 	cameraElement.style.WebkitTransformStyle = 'preserve-3d';
 	cameraElement.style.MozTransformStyle = 'preserve-3d';
 	cameraElement.style.oTransformStyle = 'preserve-3d';
@@ -71,7 +74,7 @@ THREE.CSS3DRenderer = function () {
 
 	this.setClearColor = function () {};
 
-	this.getSize = function() {
+	this.getSize = function () {
 
 		return {
 			width: _width,
@@ -85,24 +88,18 @@ THREE.CSS3DRenderer = function () {
 		_width = width;
 		_height = height;
 
-		_widthHalf = _width / 2;
-		_heightHalf = _height / 2;
-
 		domElement.style.width = width + 'px';
 		domElement.style.height = height + 'px';
 
-		cameraElement.style.width = width + 'px';
-		cameraElement.style.height = height + 'px';
-
 	};
 
-	var epsilon = function ( value ) {
+	function epsilon( value ) {
 
 		return Math.abs( value ) < Number.EPSILON ? 0 : value;
 
-	};
+	}
 
-	var getCameraCSSMatrix = function ( matrix ) {
+	function getCameraCSSMatrix( matrix ) {
 
 		var elements = matrix.elements;
 
@@ -125,9 +122,9 @@ THREE.CSS3DRenderer = function () {
 			epsilon( elements[ 15 ] ) +
 		')';
 
-	};
+	}
 
-	var getObjectCSSMatrix = function ( matrix ) {
+	function getObjectCSSMatrix( matrix ) {
 
 		var elements = matrix.elements;
 
@@ -150,9 +147,9 @@ THREE.CSS3DRenderer = function () {
 			epsilon( elements[ 15 ] ) +
 		')';
 
-	};
+	}
 
-	var renderObject = function ( object, camera ) {
+	function renderObject( object, camera ) {
 
 		if ( object instanceof THREE.CSS3DObject ) {
 
@@ -208,7 +205,7 @@ THREE.CSS3DRenderer = function () {
 
 		}
 
-	};
+	}
 
 	this.render = function ( scene, camera ) {
 
@@ -231,8 +228,7 @@ THREE.CSS3DRenderer = function () {
 
 		camera.matrixWorldInverse.getInverse( camera.matrixWorld );
 
-		var style = "translate3d(0,0," + fov + "px)" + getCameraCSSMatrix( camera.matrixWorldInverse ) +
-			" translate3d(" + _widthHalf + "px," + _heightHalf + "px, 0)";
+		var style = 'translateZ(' + fov + 'px)' + getCameraCSSMatrix( camera.matrixWorldInverse );
 
 		if ( cache.camera.style !== style ) {
 

+ 75 - 15
examples/js/vr/PaintViveController.js

@@ -25,17 +25,18 @@ THREE.PaintViveController = function ( id ) {
 		var context = canvas.getContext( '2d' );
 		var imageData = context.getImageData( 0, 0, 256, 256 );
 		var data = imageData.data;
+		var swatchColor = new THREE.Color();
 
 		for ( var i = 0, j = 0; i < data.length; i += 4, j ++ ) {
 
 			var x = ( ( j % 256 ) / 256 ) - 0.5;
 			var y = ( Math.floor( j / 256 ) / 256 ) - 0.5;
 
-			color.setHSL( Math.atan2( y, x ) / PI2, 1,( 0.5 - Math.sqrt( x * x + y * y ) ) * 2.0 );
+			swatchColor.setHSL( Math.atan2( y, x ) / PI2, 1,( 0.5 - Math.sqrt( x * x + y * y ) ) * 2.0 );
 
-			data[ i + 0 ] = color.r * 256;
-			data[ i + 1 ] = color.g * 256;
-			data[ i + 2 ] = color.b * 256;
+			data[ i + 0 ] = swatchColor.r * 256;
+			data[ i + 1 ] = swatchColor.g * 256;
+			data[ i + 2 ] = swatchColor.b * 256;
 			data[ i + 3 ] = 256;
 
 		}
@@ -46,19 +47,53 @@ THREE.PaintViveController = function ( id ) {
 
 	}
 
+	// COLOR UI
+
 	var geometry = new THREE.CircleGeometry( 1, 32 );
 	var material = new THREE.MeshBasicMaterial( { map: generateHueTexture() } );
-	var mesh = new THREE.Mesh( geometry, material );
-	mesh.position.set( 0, 0.005, 0.0495 );
-	mesh.rotation.x = - 1.45;
-	mesh.scale.setScalar( 0.02 );
-	this.add( mesh );
+	var colorUI = new THREE.Mesh( geometry, material );
+	colorUI.position.set( 0, 0.005, 0.0495 );
+	colorUI.rotation.x = - 1.45;
+	colorUI.scale.setScalar( 0.02 );
+	this.add( colorUI );
 
 	var geometry = new THREE.IcosahedronGeometry( 0.1, 2 );
 	var material = new THREE.MeshBasicMaterial();
 	material.color = color;
 	var ball = new THREE.Mesh( geometry, material );
-	mesh.add( ball );
+	colorUI.add( ball );
+
+
+	// SIZE UI
+	var sizeUI = new THREE.Group();
+	sizeUI.position.set( 0, 0.005, 0.0495 );
+	sizeUI.rotation.x = - 1.45;
+	sizeUI.scale.setScalar( 0.02 );
+	this.add( sizeUI );
+
+	var triangleShape = new THREE.Shape();
+	triangleShape.moveTo( 0, -1 );
+	triangleShape.lineTo( 1, 1 );
+	triangleShape.lineTo( -1, 1 );
+
+	var geometry = new THREE.ShapeGeometry( triangleShape );
+	var material = new THREE.MeshBasicMaterial( { color: 0x222222, wireframe:true } );
+	var sizeUIOutline = new THREE.Mesh( geometry, material ) ;
+	sizeUIOutline.position.z = 0.001;
+	resizeTriangleGeometry(sizeUIOutline.geometry, 1.0);
+	sizeUI.add( sizeUIOutline );
+
+	var geometry = new THREE.ShapeGeometry( triangleShape );
+	var material = new THREE.MeshBasicMaterial( {side: THREE.DoubleSide } );
+	material.color = color;
+	var sizeUIFill = new THREE.Mesh( geometry, material ) ;
+	sizeUIFill.position.z = 0.0011;
+	resizeTriangleGeometry(sizeUIFill.geometry, 0.5);
+	sizeUI.add( sizeUIFill );
+
+	sizeUI.visible = false;
+
+
 
 	function onAxisChanged( event ) {
 
@@ -69,27 +104,52 @@ THREE.PaintViveController = function ( id ) {
 
 		if ( mode === MODES.COLOR ) {
 			color.setHSL( Math.atan2( y, x ) / PI2, 1, ( 0.5 - Math.sqrt( x * x + y * y ) ) * 2.0 );
-			ball.position.x = event.axes[ 0 ];
-			ball.position.y = event.axes[ 1 ];
+
+			ball.position.set(event.axes[ 0 ], event.axes[ 1 ], 0);
 		}
 
 		if ( mode === MODES.SIZE ) {
-			size = y + 1;
+			var ratio = (0.5 - y);
+			size = ratio * 2;
+
+			resizeTriangleGeometry(sizeUIFill.geometry, ratio);
 		}
 
 	}
 
+	function resizeTriangleGeometry(geometry, ratio) {
+
+
+
+		var x = 0, y =0;
+		var fullWidth = 0.75; fullHeight = 1.5;
+		var angle = Math.atan((fullWidth/2)/fullHeight);
+
+		var bottomY = y - fullHeight/2;
+		var height = fullHeight * ratio;
+		var width = (Math.tan(angle) * height) * 2;
+
+		geometry.vertices[0].set( x, bottomY, 0);
+		geometry.vertices[1].set( x + width/2, bottomY + height, 0 );
+		geometry.vertices[2].set( x - width/2, bottomY + height, 0  );
+
+		geometry.verticesNeedUpdate = true;
+
+	}
+
 	function onGripsDown( event ) {
 
 		if ( mode === MODES.COLOR ) {
 			mode = MODES.SIZE;
-			mesh.visible = false;
+			colorUI.visible = false;
+			sizeUI.visible = true;
 			return;
 		}
 
 		if ( mode === MODES.SIZE ) {
 			mode = MODES.COLOR;
-			mesh.visible = true;
+			colorUI.visible = true;
+			sizeUI.visible = false;
 			return;
 		}
 

+ 15 - 11
examples/webvr_vive_paint.html

@@ -174,7 +174,7 @@
 
 					// var pivot = new THREE.Group();
 					// var pivot = new THREE.Mesh( new THREE.BoxGeometry( 0.01, 0.01, 0.01 ) );
-					var pivot = new THREE.Mesh( new THREE.IcosahedronGeometry( 0.002, 2 ) );
+					var pivot = new THREE.Mesh( new THREE.IcosahedronGeometry( 0.01, 2 ) );
 					pivot.name = 'pivot';
 					pivot.position.y = -0.016;
 					pivot.position.z = -0.043;
@@ -249,28 +249,31 @@
 				scene.add( line );
 
 				// Shapes
+				shapes[ 'tube' ] = getTubeShapes(1.0);
+			}
+
+			function getTubeShapes(size) {
 
 				var PI2 = Math.PI * 2;
 
 				var sides = 10;
 				var array = [];
-
-				for ( var i = 0; i < sides; i ++ ) {
+				var radius = 0.01 * size;
+				for( var i = 0; i < sides; i ++ ){
 
 					var angle = ( i / sides ) * PI2;
-					array.push( new THREE.Vector3( Math.sin( angle ) * 0.01, Math.cos( angle ) * 0.01, 0 ) );
-
+					array.push( new THREE.Vector3( Math.sin( angle ) * radius, Math.cos( angle ) * radius, 0 ) );
 				}
 
-				shapes[ 'tube' ] = array;
-
+				return array;
 			}
 
+
 			function stroke( controller, point1, point2, matrix1, matrix2 ) {
 
 				var color = controller.getColor();
 
-				var shape = shapes[ 'tube' ];
+				var shapes = getTubeShapes( controller.getSize() );
 
 				var geometry = line.geometry;
 				var attributes = geometry.attributes;
@@ -280,10 +283,10 @@
 				var normals = attributes.normal.array;
 				var colors = attributes.color.array;
 
-				for ( var j = 0, jl = shape.length; j < jl; j ++ ) {
+				for ( var j = 0, jl = shapes.length; j < jl; j ++ ) {
 
-					var vertex1 = shape[ j ];
-					var vertex2 = shape[ ( j + 1 ) % jl ];
+					var vertex1 = shapes[ j ];
+					var vertex2 = shapes[ ( j + 1 ) % jl ];
 
 					// positions
 
@@ -406,6 +409,7 @@
 				if ( pivot ) {
 
 					pivot.material.color.copy( controller.getColor() );
+					pivot.scale.setScalar(controller.getSize());
 
 					var matrix = pivot.matrixWorld;
 

+ 2 - 4
src/animation/AnimationAction.js

@@ -76,9 +76,7 @@ function AnimationAction( mixer, clip, localRoot ) {
 
 }
 
-AnimationAction.prototype = {
-
-	constructor: AnimationAction,
+Object.assign( AnimationAction.prototype, {
 
 	// State & Scheduling
 
@@ -651,7 +649,7 @@ AnimationAction.prototype = {
 
 	}
 
-};
+} );
 
 
 export { AnimationAction };

+ 47 - 53
src/animation/AnimationClip.js

@@ -32,55 +32,6 @@ function AnimationClip( name, duration, tracks ) {
 
 }
 
-AnimationClip.prototype = {
-
-	constructor: AnimationClip,
-
-	resetDuration: function() {
-
-		var tracks = this.tracks,
-			duration = 0;
-
-		for ( var i = 0, n = tracks.length; i !== n; ++ i ) {
-
-			var track = this.tracks[ i ];
-
-			duration = Math.max( duration, track.times[ track.times.length - 1 ] );
-
-		}
-
-		this.duration = duration;
-
-	},
-
-	trim: function() {
-
-		for ( var i = 0; i < this.tracks.length; i ++ ) {
-
-			this.tracks[ i ].trim( 0, this.duration );
-
-		}
-
-		return this;
-
-	},
-
-	optimize: function() {
-
-		for ( var i = 0; i < this.tracks.length; i ++ ) {
-
-			this.tracks[ i ].optimize();
-
-		}
-
-		return this;
-
-	}
-
-};
-
-// Static methods:
-
 Object.assign( AnimationClip, {
 
 	parse: function( json ) {
@@ -98,8 +49,7 @@ Object.assign( AnimationClip, {
 		return new AnimationClip( json.name, json.duration, tracks );
 
 	},
-
-
+	
 	toJSON: function( clip ) {
 
 		var tracks = [],
@@ -122,8 +72,7 @@ Object.assign( AnimationClip, {
 		return json;
 
 	},
-
-
+	
 	CreateFromMorphTargetSequence: function( name, morphTargetSequence, fps, noLoop ) {
 
 		var numMorphTargets = morphTargetSequence.length;
@@ -359,5 +308,50 @@ Object.assign( AnimationClip, {
 
 } );
 
+Object.assign( AnimationClip.prototype, {
+
+	resetDuration: function() {
+
+		var tracks = this.tracks,
+			duration = 0;
+
+		for ( var i = 0, n = tracks.length; i !== n; ++ i ) {
+
+			var track = this.tracks[ i ];
+
+			duration = Math.max( duration, track.times[ track.times.length - 1 ] );
+
+		}
+
+		this.duration = duration;
+
+	},
+
+	trim: function() {
+
+		for ( var i = 0; i < this.tracks.length; i ++ ) {
+
+			this.tracks[ i ].trim( 0, this.duration );
+
+		}
+
+		return this;
+
+	},
+
+	optimize: function() {
+
+		for ( var i = 0; i < this.tracks.length; i ++ ) {
+
+			this.tracks[ i ].optimize();
+
+		}
+
+		return this;
+
+	}
+
+} );
+
 
 export { AnimationClip };

+ 251 - 260
src/animation/AnimationMixer.js

@@ -27,259 +27,7 @@ function AnimationMixer( root ) {
 
 }
 
-AnimationMixer.prototype = {
-
-	constructor: AnimationMixer,
-
-	// return an action for a clip optionally using a custom root target
-	// object (this method allocates a lot of dynamic memory in case a
-	// previously unknown clip/root combination is specified)
-	clipAction: function ( clip, optionalRoot ) {
-
-		var root = optionalRoot || this._root,
-			rootUuid = root.uuid,
-
-			clipObject = typeof clip === 'string' ?
-					AnimationClip.findByName( root, clip ) : clip,
-
-			clipUuid = clipObject !== null ? clipObject.uuid : clip,
-
-			actionsForClip = this._actionsByClip[ clipUuid ],
-			prototypeAction = null;
-
-		if ( actionsForClip !== undefined ) {
-
-			var existingAction =
-					actionsForClip.actionByRoot[ rootUuid ];
-
-			if ( existingAction !== undefined ) {
-
-				return existingAction;
-
-			}
-
-			// we know the clip, so we don't have to parse all
-			// the bindings again but can just copy
-			prototypeAction = actionsForClip.knownActions[ 0 ];
-
-			// also, take the clip from the prototype action
-			if ( clipObject === null )
-				clipObject = prototypeAction._clip;
-
-		}
-
-		// clip must be known when specified via string
-		if ( clipObject === null ) return null;
-
-		// allocate all resources required to run it
-		var newAction = new AnimationAction( this, clipObject, optionalRoot );
-
-		this._bindAction( newAction, prototypeAction );
-
-		// and make the action known to the memory manager
-		this._addInactiveAction( newAction, clipUuid, rootUuid );
-
-		return newAction;
-
-	},
-
-	// get an existing action
-	existingAction: function ( clip, optionalRoot ) {
-
-		var root = optionalRoot || this._root,
-			rootUuid = root.uuid,
-
-			clipObject = typeof clip === 'string' ?
-					AnimationClip.findByName( root, clip ) : clip,
-
-			clipUuid = clipObject ? clipObject.uuid : clip,
-
-			actionsForClip = this._actionsByClip[ clipUuid ];
-
-		if ( actionsForClip !== undefined ) {
-
-			return actionsForClip.actionByRoot[ rootUuid ] || null;
-
-		}
-
-		return null;
-
-	},
-
-	// deactivates all previously scheduled actions
-	stopAllAction: function () {
-
-		var actions = this._actions,
-			nActions = this._nActiveActions,
-			bindings = this._bindings,
-			nBindings = this._nActiveBindings;
-
-		this._nActiveActions = 0;
-		this._nActiveBindings = 0;
-
-		for ( var i = 0; i !== nActions; ++ i ) {
-
-			actions[ i ].reset();
-
-		}
-
-		for ( var i = 0; i !== nBindings; ++ i ) {
-
-			bindings[ i ].useCount = 0;
-
-		}
-
-		return this;
-
-	},
-
-	// advance the time and update apply the animation
-	update: function ( deltaTime ) {
-
-		deltaTime *= this.timeScale;
-
-		var actions = this._actions,
-			nActions = this._nActiveActions,
-
-			time = this.time += deltaTime,
-			timeDirection = Math.sign( deltaTime ),
-
-			accuIndex = this._accuIndex ^= 1;
-
-		// run active actions
-
-		for ( var i = 0; i !== nActions; ++ i ) {
-
-			var action = actions[ i ];
-
-			if ( action.enabled ) {
-
-				action._update( time, deltaTime, timeDirection, accuIndex );
-
-			}
-
-		}
-
-		// update scene graph
-
-		var bindings = this._bindings,
-			nBindings = this._nActiveBindings;
-
-		for ( var i = 0; i !== nBindings; ++ i ) {
-
-			bindings[ i ].apply( accuIndex );
-
-		}
-
-		return this;
-
-	},
-
-	// return this mixer's root target object
-	getRoot: function () {
-
-		return this._root;
-
-	},
-
-	// free all resources specific to a particular clip
-	uncacheClip: function ( clip ) {
-
-		var actions = this._actions,
-			clipUuid = clip.uuid,
-			actionsByClip = this._actionsByClip,
-			actionsForClip = actionsByClip[ clipUuid ];
-
-		if ( actionsForClip !== undefined ) {
-
-			// note: just calling _removeInactiveAction would mess up the
-			// iteration state and also require updating the state we can
-			// just throw away
-
-			var actionsToRemove = actionsForClip.knownActions;
-
-			for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
-
-				var action = actionsToRemove[ i ];
-
-				this._deactivateAction( action );
-
-				var cacheIndex = action._cacheIndex,
-					lastInactiveAction = actions[ actions.length - 1 ];
-
-				action._cacheIndex = null;
-				action._byClipCacheIndex = null;
-
-				lastInactiveAction._cacheIndex = cacheIndex;
-				actions[ cacheIndex ] = lastInactiveAction;
-				actions.pop();
-
-				this._removeInactiveBindingsForAction( action );
-
-			}
-
-			delete actionsByClip[ clipUuid ];
-
-		}
-
-	},
-
-	// free all resources specific to a particular root target object
-	uncacheRoot: function ( root ) {
-
-		var rootUuid = root.uuid,
-			actionsByClip = this._actionsByClip;
-
-		for ( var clipUuid in actionsByClip ) {
-
-			var actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
-				action = actionByRoot[ rootUuid ];
-
-			if ( action !== undefined ) {
-
-				this._deactivateAction( action );
-				this._removeInactiveAction( action );
-
-			}
-
-		}
-
-		var bindingsByRoot = this._bindingsByRootAndName,
-			bindingByName = bindingsByRoot[ rootUuid ];
-
-		if ( bindingByName !== undefined ) {
-
-			for ( var trackName in bindingByName ) {
-
-				var binding = bindingByName[ trackName ];
-				binding.restoreOriginalState();
-				this._removeInactiveBinding( binding );
-
-			}
-
-		}
-
-	},
-
-	// remove a targeted clip from the cache
-	uncacheAction: function ( clip, optionalRoot ) {
-
-		var action = this.existingAction( clip, optionalRoot );
-
-		if ( action !== null ) {
-
-			this._deactivateAction( action );
-			this._removeInactiveAction( action );
-
-		}
-
-	}
-
-};
-
-// Implementation details:
-
-Object.assign( AnimationMixer.prototype, {
+Object.assign( AnimationMixer.prototype, EventDispatcher.prototype, {
 
 	_bindAction: function ( action, prototypeAction ) {
 
@@ -332,8 +80,8 @@ Object.assign( AnimationMixer.prototype, {
 						_propertyBindings[ i ].binding.parsedPath;
 
 				binding = new PropertyMixer(
-						PropertyBinding.create( root, trackName, path ),
-						track.ValueTypeName, track.getValueSize() );
+					PropertyBinding.create( root, trackName, path ),
+					track.ValueTypeName, track.getValueSize() );
 
 				++ binding.referenceCount;
 				this._addInactiveBinding( binding, rootUuid, trackName );
@@ -362,7 +110,7 @@ Object.assign( AnimationMixer.prototype, {
 					actionsForClip = this._actionsByClip[ clipUuid ];
 
 				this._bindAction( action,
-						actionsForClip && actionsForClip.knownActions[ 0 ] );
+					actionsForClip && actionsForClip.knownActions[ 0 ] );
 
 				this._addInactiveAction( action, clipUuid, rootUuid );
 
@@ -710,8 +458,8 @@ Object.assign( AnimationMixer.prototype, {
 		if ( interpolant === undefined ) {
 
 			interpolant = new LinearInterpolant(
-					new Float32Array( 2 ), new Float32Array( 2 ),
-						1, this._controlInterpolantsResultBuffer );
+				new Float32Array( 2 ), new Float32Array( 2 ),
+				1, this._controlInterpolantsResultBuffer );
 
 			interpolant.__cacheIndex = lastActiveIndex;
 			interpolants[ lastActiveIndex ] = interpolant;
@@ -739,10 +487,253 @@ Object.assign( AnimationMixer.prototype, {
 
 	},
 
-	_controlInterpolantsResultBuffer: new Float32Array( 1 )
+	_controlInterpolantsResultBuffer: new Float32Array( 1 ),
+
+	// return an action for a clip optionally using a custom root target
+	// object (this method allocates a lot of dynamic memory in case a
+	// previously unknown clip/root combination is specified)
+	clipAction: function ( clip, optionalRoot ) {
+
+		var root = optionalRoot || this._root,
+			rootUuid = root.uuid,
+
+			clipObject = typeof clip === 'string' ?
+				AnimationClip.findByName( root, clip ) : clip,
+
+			clipUuid = clipObject !== null ? clipObject.uuid : clip,
+
+			actionsForClip = this._actionsByClip[ clipUuid ],
+			prototypeAction = null;
+
+		if ( actionsForClip !== undefined ) {
+
+			var existingAction =
+					actionsForClip.actionByRoot[ rootUuid ];
+
+			if ( existingAction !== undefined ) {
+
+				return existingAction;
+
+			}
+
+			// we know the clip, so we don't have to parse all
+			// the bindings again but can just copy
+			prototypeAction = actionsForClip.knownActions[ 0 ];
+
+			// also, take the clip from the prototype action
+			if ( clipObject === null )
+				clipObject = prototypeAction._clip;
+
+		}
+
+		// clip must be known when specified via string
+		if ( clipObject === null ) return null;
+
+		// allocate all resources required to run it
+		var newAction = new AnimationAction( this, clipObject, optionalRoot );
+
+		this._bindAction( newAction, prototypeAction );
+
+		// and make the action known to the memory manager
+		this._addInactiveAction( newAction, clipUuid, rootUuid );
+
+		return newAction;
+
+	},
+
+	// get an existing action
+	existingAction: function ( clip, optionalRoot ) {
+
+		var root = optionalRoot || this._root,
+			rootUuid = root.uuid,
+
+			clipObject = typeof clip === 'string' ?
+				AnimationClip.findByName( root, clip ) : clip,
+
+			clipUuid = clipObject ? clipObject.uuid : clip,
+
+			actionsForClip = this._actionsByClip[ clipUuid ];
+
+		if ( actionsForClip !== undefined ) {
+
+			return actionsForClip.actionByRoot[ rootUuid ] || null;
+
+		}
+
+		return null;
+
+	},
+
+	// deactivates all previously scheduled actions
+	stopAllAction: function () {
+
+		var actions = this._actions,
+			nActions = this._nActiveActions,
+			bindings = this._bindings,
+			nBindings = this._nActiveBindings;
+
+		this._nActiveActions = 0;
+		this._nActiveBindings = 0;
+
+		for ( var i = 0; i !== nActions; ++ i ) {
+
+			actions[ i ].reset();
+
+		}
+
+		for ( var i = 0; i !== nBindings; ++ i ) {
+
+			bindings[ i ].useCount = 0;
+
+		}
+
+		return this;
+
+	},
+
+	// advance the time and update apply the animation
+	update: function ( deltaTime ) {
+
+		deltaTime *= this.timeScale;
+
+		var actions = this._actions,
+			nActions = this._nActiveActions,
+
+			time = this.time += deltaTime,
+			timeDirection = Math.sign( deltaTime ),
+
+			accuIndex = this._accuIndex ^= 1;
+
+		// run active actions
+
+		for ( var i = 0; i !== nActions; ++ i ) {
+
+			var action = actions[ i ];
+
+			if ( action.enabled ) {
+
+				action._update( time, deltaTime, timeDirection, accuIndex );
+
+			}
+
+		}
+
+		// update scene graph
+
+		var bindings = this._bindings,
+			nBindings = this._nActiveBindings;
+
+		for ( var i = 0; i !== nBindings; ++ i ) {
+
+			bindings[ i ].apply( accuIndex );
+
+		}
+
+		return this;
+
+	},
+
+	// return this mixer's root target object
+	getRoot: function () {
+
+		return this._root;
+
+	},
+
+	// free all resources specific to a particular clip
+	uncacheClip: function ( clip ) {
+
+		var actions = this._actions,
+			clipUuid = clip.uuid,
+			actionsByClip = this._actionsByClip,
+			actionsForClip = actionsByClip[ clipUuid ];
+
+		if ( actionsForClip !== undefined ) {
+
+			// note: just calling _removeInactiveAction would mess up the
+			// iteration state and also require updating the state we can
+			// just throw away
+
+			var actionsToRemove = actionsForClip.knownActions;
+
+			for ( var i = 0, n = actionsToRemove.length; i !== n; ++ i ) {
+
+				var action = actionsToRemove[ i ];
+
+				this._deactivateAction( action );
+
+				var cacheIndex = action._cacheIndex,
+					lastInactiveAction = actions[ actions.length - 1 ];
+
+				action._cacheIndex = null;
+				action._byClipCacheIndex = null;
+
+				lastInactiveAction._cacheIndex = cacheIndex;
+				actions[ cacheIndex ] = lastInactiveAction;
+				actions.pop();
+
+				this._removeInactiveBindingsForAction( action );
+
+			}
+
+			delete actionsByClip[ clipUuid ];
+
+		}
+
+	},
+
+	// free all resources specific to a particular root target object
+	uncacheRoot: function ( root ) {
+
+		var rootUuid = root.uuid,
+			actionsByClip = this._actionsByClip;
+
+		for ( var clipUuid in actionsByClip ) {
+
+			var actionByRoot = actionsByClip[ clipUuid ].actionByRoot,
+				action = actionByRoot[ rootUuid ];
+
+			if ( action !== undefined ) {
+
+				this._deactivateAction( action );
+				this._removeInactiveAction( action );
+
+			}
+
+		}
+
+		var bindingsByRoot = this._bindingsByRootAndName,
+			bindingByName = bindingsByRoot[ rootUuid ];
+
+		if ( bindingByName !== undefined ) {
+
+			for ( var trackName in bindingByName ) {
+
+				var binding = bindingByName[ trackName ];
+				binding.restoreOriginalState();
+				this._removeInactiveBinding( binding );
+
+			}
+
+		}
+
+	},
+
+	// remove a targeted clip from the cache
+	uncacheAction: function ( clip, optionalRoot ) {
+
+		var action = this.existingAction( clip, optionalRoot );
+
+		if ( action !== null ) {
+
+			this._deactivateAction( action );
+			this._removeInactiveAction( action );
+
+		}
+
+	}
 
 } );
 
-Object.assign( AnimationMixer.prototype, EventDispatcher.prototype );
 
 export { AnimationMixer };

+ 2 - 5
src/animation/AnimationObjectGroup.js

@@ -71,9 +71,7 @@ function AnimationObjectGroup( var_args ) {
 
 }
 
-AnimationObjectGroup.prototype = {
-
-	constructor: AnimationObjectGroup,
+Object.assign( AnimationObjectGroup.prototype, {
 
 	isAnimationObjectGroup: true,
 
@@ -371,8 +369,7 @@ AnimationObjectGroup.prototype = {
 
 	}
 
-};
-
+} );
 
 
 export { AnimationObjectGroup };

+ 275 - 276
src/animation/PropertyBinding.js

@@ -8,265 +8,219 @@
  * @author tschw
  */
 
-function PropertyBinding( rootNode, path, parsedPath ) {
-
-	this.path = path;
-	this.parsedPath = parsedPath ||
-			PropertyBinding.parseTrackName( path );
+function Composite ( targetGroup, path, optionalParsedPath ) {
 
-	this.node = PropertyBinding.findNode(
-			rootNode, this.parsedPath.nodeName ) || rootNode;
+	var parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );
 
-	this.rootNode = rootNode;
+	this._targetGroup = targetGroup;
+	this._bindings = targetGroup.subscribe_( path, parsedPath );
 
 }
 
-PropertyBinding.prototype = {
-
-	constructor: PropertyBinding,
+Object.assign( Composite.prototype, {
 
-	getValue: function getValue_unbound( targetArray, offset ) {
-
-		this.bind();
-		this.getValue( targetArray, offset );
-
-		// Note: This class uses a State pattern on a per-method basis:
-		// 'bind' sets 'this.getValue' / 'setValue' and shadows the
-		// prototype version of these methods with one that represents
-		// the bound state. When the property is not found, the methods
-		// become no-ops.
+	getValue: function( array, offset ) {
 
-	},
+		this.bind(); // bind all binding
 
-	setValue: function getValue_unbound( sourceArray, offset ) {
+		var firstValidIndex = this._targetGroup.nCachedObjects_,
+			binding = this._bindings[ firstValidIndex ];
 
-		this.bind();
-		this.setValue( sourceArray, offset );
+		// and only call .getValue on the first
+		if ( binding !== undefined ) binding.getValue( array, offset );
 
 	},
 
-	// create getter / setter pair for a property in the scene graph
-	bind: function() {
-
-		var targetObject = this.node,
-			parsedPath = this.parsedPath,
-
-			objectName = parsedPath.objectName,
-			propertyName = parsedPath.propertyName,
-			propertyIndex = parsedPath.propertyIndex;
-
-		if ( ! targetObject ) {
-
-			targetObject = PropertyBinding.findNode(
-					this.rootNode, parsedPath.nodeName ) || this.rootNode;
-
-			this.node = targetObject;
-
-		}
+	setValue: function( array, offset ) {
 
-		// set fail state so we can just 'return' on error
-		this.getValue = this._getValue_unavailable;
-		this.setValue = this._setValue_unavailable;
+		var bindings = this._bindings;
 
- 		// ensure there is a value node
-		if ( ! targetObject ) {
+		for ( var i = this._targetGroup.nCachedObjects_,
+				  n = bindings.length; i !== n; ++ i ) {
 
-			console.error( "  trying to update node for track: " + this.path + " but it wasn't found." );
-			return;
+			bindings[ i ].setValue( array, offset );
 
 		}
 
-		if ( objectName ) {
-
-			var objectIndex = parsedPath.objectIndex;
-
-			// special cases were we need to reach deeper into the hierarchy to get the face materials....
-			switch ( objectName ) {
-
-				case 'materials':
+	},
 
-					if ( ! targetObject.material ) {
+	bind: function() {
 
-						console.error( '  can not bind to material as node does not have a material', this );
-						return;
+		var bindings = this._bindings;
 
-					}
+		for ( var i = this._targetGroup.nCachedObjects_,
+				  n = bindings.length; i !== n; ++ i ) {
 
-					if ( ! targetObject.material.materials ) {
+			bindings[ i ].bind();
 
-						console.error( '  can not bind to material.materials as node.material does not have a materials array', this );
-						return;
+		}
 
-					}
+	},
 
-					targetObject = targetObject.material.materials;
+	unbind: function() {
 
-					break;
+		var bindings = this._bindings;
 
-				case 'bones':
+		for ( var i = this._targetGroup.nCachedObjects_,
+				  n = bindings.length; i !== n; ++ i ) {
 
-					if ( ! targetObject.skeleton ) {
+			bindings[ i ].unbind();
 
-						console.error( '  can not bind to bones as node does not have a skeleton', this );
-						return;
+		}
 
-					}
+	}
 
-					// potential future optimization: skip this if propertyIndex is already an integer
-					// and convert the integer string to a true integer.
+} );
 
-					targetObject = targetObject.skeleton.bones;
 
-					// support resolving morphTarget names into indices.
-					for ( var i = 0; i < targetObject.length; i ++ ) {
+function PropertyBinding( rootNode, path, parsedPath ) {
 
-						if ( targetObject[ i ].name === objectIndex ) {
+	this.path = path;
+	this.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );
 
-							objectIndex = i;
-							break;
+	this.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName ) || rootNode;
 
-						}
+	this.rootNode = rootNode;
 
-					}
+}
 
-					break;
+Object.assign( PropertyBinding, {
 
-				default:
+	Composite: Composite,
 
-					if ( targetObject[ objectName ] === undefined ) {
+	create: function( root, path, parsedPath ) {
 
-						console.error( '  can not bind to objectName of node, undefined', this );
-						return;
+		if ( ! ( root && root.isAnimationObjectGroup ) ) {
 
-					}
+			return new PropertyBinding( root, path, parsedPath );
 
-					targetObject = targetObject[ objectName ];
+		} else {
 
-			}
+			return new PropertyBinding.Composite( root, path, parsedPath );
 
+		}
 
-			if ( objectIndex !== undefined ) {
+	},
 
-				if ( targetObject[ objectIndex ] === undefined ) {
+	parseTrackName: function( trackName ) {
 
-					console.error( "  trying to bind to objectIndex of objectName, but is undefined:", this, targetObject );
-					return;
+		// matches strings in the form of:
+		//    nodeName.property
+		//    nodeName.property[accessor]
+		//    nodeName.material.property[accessor]
+		//    uuid.property[accessor]
+		//    uuid.objectName[objectIndex].propertyName[propertyIndex]
+		//    parentName/nodeName.property
+		//    parentName/parentName/nodeName.property[index]
+		//    .bone[Armature.DEF_cog].position
+		//    scene:helium_balloon_model:helium_balloon_model.position
+		// created and tested via https://regex101.com/#javascript
 
-				}
+		var re = /^((?:[\w-]+[\/:])*)([\w-]+)?(?:\.([\w-]+)(?:\[(.+)\])?)?\.([\w-]+)(?:\[(.+)\])?$/;
+		var matches = re.exec( trackName );
 
-				targetObject = targetObject[ objectIndex ];
+		if ( ! matches ) {
 
-			}
+			throw new Error( "cannot parse trackName at all: " + trackName );
 
 		}
 
-		// resolve property
-		var nodeProperty = targetObject[ propertyName ];
-
-		if ( nodeProperty === undefined ) {
+		var results = {
+			// directoryName: matches[ 1 ], // (tschw) currently unused
+			nodeName: matches[ 2 ], 	// allowed to be null, specified root node.
+			objectName: matches[ 3 ],
+			objectIndex: matches[ 4 ],
+			propertyName: matches[ 5 ],
+			propertyIndex: matches[ 6 ]	// allowed to be null, specifies that the whole property is set.
+		};
 
-			var nodeName = parsedPath.nodeName;
+		if ( results.propertyName === null || results.propertyName.length === 0 ) {
 
-			console.error( "  trying to update property for track: " + nodeName +
-					'.' + propertyName + " but it wasn't found.", targetObject );
-			return;
+			throw new Error( "can not parse propertyName from trackName: " + trackName );
 
 		}
 
-		// determine versioning scheme
-		var versioning = this.Versioning.None;
+		return results;
 
-		if ( targetObject.needsUpdate !== undefined ) { // material
+	},
 
-			versioning = this.Versioning.NeedsUpdate;
-			this.targetObject = targetObject;
+	findNode: function( root, nodeName ) {
 
-		} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
+		if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) {
 
-			versioning = this.Versioning.MatrixWorldNeedsUpdate;
-			this.targetObject = targetObject;
+			return root;
 
 		}
 
-		// determine how the property gets bound
-		var bindingType = this.BindingType.Direct;
-
-		if ( propertyIndex !== undefined ) {
-			// access a sub element of the property array (only primitives are supported right now)
-
-			if ( propertyName === "morphTargetInfluences" ) {
-				// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
+		// search into skeleton bones.
+		if ( root.skeleton ) {
 
-				// support resolving morphTarget names into indices.
-				if ( ! targetObject.geometry ) {
+			var searchSkeleton = function( skeleton ) {
 
-					console.error( '  can not bind to morphTargetInfluences becasuse node does not have a geometry', this );
-					return;
+				for( var i = 0; i < skeleton.bones.length; i ++ ) {
 
-				}
+					var bone = skeleton.bones[ i ];
 
-				if ( ! targetObject.geometry.morphTargets ) {
+					if ( bone.name === nodeName ) {
 
-					console.error( '  can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this );
-					return;
+						return bone;
 
+					}
 				}
 
-				for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {
+				return null;
 
-					if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) {
+			};
 
-						propertyIndex = i;
-						break;
+			var bone = searchSkeleton( root.skeleton );
 
-					}
+			if ( bone ) {
 
-				}
+				return bone;
 
 			}
+		}
 
-			bindingType = this.BindingType.ArrayElement;
+		// search into node subtree.
+		if ( root.children ) {
 
-			this.resolvedProperty = nodeProperty;
-			this.propertyIndex = propertyIndex;
+			var searchNodeSubtree = function( children ) {
 
-		} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
-			// must use copy for Object3D.Euler/Quaternion
+				for( var i = 0; i < children.length; i ++ ) {
 
-			bindingType = this.BindingType.HasFromToArray;
+					var childNode = children[ i ];
 
-			this.resolvedProperty = nodeProperty;
+					if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
 
-		} else if ( Array.isArray( nodeProperty ) ) {
+						return childNode;
 
-			bindingType = this.BindingType.EntireArray;
+					}
 
-			this.resolvedProperty = nodeProperty;
+					var result = searchNodeSubtree( childNode.children );
 
-		} else {
+					if ( result ) return result;
 
-			this.propertyName = propertyName;
+				}
 
-		}
+				return null;
 
-		// select getter / setter
-		this.getValue = this.GetterByBindingType[ bindingType ];
-		this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
+			};
 
-	},
+			var subTreeNode = searchNodeSubtree( root.children );
 
-	unbind: function() {
+			if ( subTreeNode ) {
 
-		this.node = null;
+				return subTreeNode;
 
-		// back to the prototype version of getValue / setValue
-		// note: avoiding to mutate the shape of 'this' via 'delete'
-		this.getValue = this._getValue_unbound;
-		this.setValue = this._setValue_unbound;
+			}
+
+		}
+
+		return null;
 
 	}
 
-};
+} );
 
 Object.assign( PropertyBinding.prototype, { // prototype, continued
 
@@ -274,10 +228,6 @@ Object.assign( PropertyBinding.prototype, { // prototype, continued
 	_getValue_unavailable: function() {},
 	_setValue_unavailable: function() {},
 
-	// initial state of these methods that calls 'bind'
-	_getValue_unbound: PropertyBinding.prototype.getValue,
-	_setValue_unbound: PropertyBinding.prototype.setValue,
-
 	BindingType: {
 		Direct: 0,
 		EntireArray: 1,
@@ -444,209 +394,258 @@ Object.assign( PropertyBinding.prototype, { // prototype, continued
 
 		]
 
-	]
+	],
 
-} );
+	getValue: function getValue_unbound( targetArray, offset ) {
 
-PropertyBinding.Composite =
-		function( targetGroup, path, optionalParsedPath ) {
+		this.bind();
+		this.getValue( targetArray, offset );
 
-	var parsedPath = optionalParsedPath ||
-			PropertyBinding.parseTrackName( path );
+		// Note: This class uses a State pattern on a per-method basis:
+		// 'bind' sets 'this.getValue' / 'setValue' and shadows the
+		// prototype version of these methods with one that represents
+		// the bound state. When the property is not found, the methods
+		// become no-ops.
 
-	this._targetGroup = targetGroup;
-	this._bindings = targetGroup.subscribe_( path, parsedPath );
+	},
 
-};
+	setValue: function getValue_unbound( sourceArray, offset ) {
 
-PropertyBinding.Composite.prototype = {
+		this.bind();
+		this.setValue( sourceArray, offset );
 
-	constructor: PropertyBinding.Composite,
+	},
 
-	getValue: function( array, offset ) {
+	// create getter / setter pair for a property in the scene graph
+	bind: function() {
 
-		this.bind(); // bind all binding
+		var targetObject = this.node,
+			parsedPath = this.parsedPath,
 
-		var firstValidIndex = this._targetGroup.nCachedObjects_,
-			binding = this._bindings[ firstValidIndex ];
+			objectName = parsedPath.objectName,
+			propertyName = parsedPath.propertyName,
+			propertyIndex = parsedPath.propertyIndex;
 
-		// and only call .getValue on the first
-		if ( binding !== undefined ) binding.getValue( array, offset );
+		if ( ! targetObject ) {
 
-	},
+			targetObject = PropertyBinding.findNode(
+					this.rootNode, parsedPath.nodeName ) || this.rootNode;
 
-	setValue: function( array, offset ) {
+			this.node = targetObject;
 
-		var bindings = this._bindings;
+		}
 
-		for ( var i = this._targetGroup.nCachedObjects_,
-				n = bindings.length; i !== n; ++ i ) {
+		// set fail state so we can just 'return' on error
+		this.getValue = this._getValue_unavailable;
+		this.setValue = this._setValue_unavailable;
 
-			bindings[ i ].setValue( array, offset );
+		// ensure there is a value node
+		if ( ! targetObject ) {
 
-		}
+			console.error( "  trying to update node for track: " + this.path + " but it wasn't found." );
+			return;
 
-	},
+		}
 
-	bind: function() {
+		if ( objectName ) {
 
-		var bindings = this._bindings;
+			var objectIndex = parsedPath.objectIndex;
 
-		for ( var i = this._targetGroup.nCachedObjects_,
-				n = bindings.length; i !== n; ++ i ) {
+			// special cases were we need to reach deeper into the hierarchy to get the face materials....
+			switch ( objectName ) {
 
-			bindings[ i ].bind();
+				case 'materials':
 
-		}
+					if ( ! targetObject.material ) {
 
-	},
+						console.error( '  can not bind to material as node does not have a material', this );
+						return;
 
-	unbind: function() {
+					}
 
-		var bindings = this._bindings;
+					if ( ! targetObject.material.materials ) {
 
-		for ( var i = this._targetGroup.nCachedObjects_,
-				n = bindings.length; i !== n; ++ i ) {
+						console.error( '  can not bind to material.materials as node.material does not have a materials array', this );
+						return;
 
-			bindings[ i ].unbind();
+					}
 
-		}
+					targetObject = targetObject.material.materials;
 
-	}
+					break;
 
-};
+				case 'bones':
 
-PropertyBinding.create = function( root, path, parsedPath ) {
+					if ( ! targetObject.skeleton ) {
 
-	if ( ! ( root && root.isAnimationObjectGroup ) ) {
+						console.error( '  can not bind to bones as node does not have a skeleton', this );
+						return;
 
-		return new PropertyBinding( root, path, parsedPath );
+					}
 
-	} else {
+					// potential future optimization: skip this if propertyIndex is already an integer
+					// and convert the integer string to a true integer.
 
-		return new PropertyBinding.Composite( root, path, parsedPath );
+					targetObject = targetObject.skeleton.bones;
 
-	}
+					// support resolving morphTarget names into indices.
+					for ( var i = 0; i < targetObject.length; i ++ ) {
 
-};
+						if ( targetObject[ i ].name === objectIndex ) {
 
-PropertyBinding.parseTrackName = function( trackName ) {
+							objectIndex = i;
+							break;
 
-	// matches strings in the form of:
-	//    nodeName.property
-	//    nodeName.property[accessor]
-	//    nodeName.material.property[accessor]
-	//    uuid.property[accessor]
-	//    uuid.objectName[objectIndex].propertyName[propertyIndex]
-	//    parentName/nodeName.property
-	//    parentName/parentName/nodeName.property[index]
-	//    .bone[Armature.DEF_cog].position
-	//    scene:helium_balloon_model:helium_balloon_model.position
-	// created and tested via https://regex101.com/#javascript
+						}
 
-	var re = /^((?:[\w-]+[\/:])*)([\w-]+)?(?:\.([\w-]+)(?:\[(.+)\])?)?\.([\w-]+)(?:\[(.+)\])?$/;
-	var matches = re.exec( trackName );
+					}
 
-	if ( ! matches ) {
+					break;
 
-		throw new Error( "cannot parse trackName at all: " + trackName );
+				default:
 
-	}
+					if ( targetObject[ objectName ] === undefined ) {
 
-	var results = {
-		// directoryName: matches[ 1 ], // (tschw) currently unused
-		nodeName: matches[ 2 ], 	// allowed to be null, specified root node.
-		objectName: matches[ 3 ],
-		objectIndex: matches[ 4 ],
-		propertyName: matches[ 5 ],
-		propertyIndex: matches[ 6 ]	// allowed to be null, specifies that the whole property is set.
-	};
+						console.error( '  can not bind to objectName of node, undefined', this );
+						return;
 
-	if ( results.propertyName === null || results.propertyName.length === 0 ) {
+					}
 
-		throw new Error( "can not parse propertyName from trackName: " + trackName );
+					targetObject = targetObject[ objectName ];
 
-	}
+			}
 
-	return results;
 
-};
+			if ( objectIndex !== undefined ) {
 
-PropertyBinding.findNode = function( root, nodeName ) {
+				if ( targetObject[ objectIndex ] === undefined ) {
 
-	if ( ! nodeName || nodeName === "" || nodeName === "root" || nodeName === "." || nodeName === -1 || nodeName === root.name || nodeName === root.uuid ) {
+					console.error( "  trying to bind to objectIndex of objectName, but is undefined:", this, targetObject );
+					return;
 
-		return root;
+				}
 
-	}
+				targetObject = targetObject[ objectIndex ];
 
-	// search into skeleton bones.
-	if ( root.skeleton ) {
+			}
 
-		var searchSkeleton = function( skeleton ) {
+		}
 
-			for( var i = 0; i < skeleton.bones.length; i ++ ) {
+		// resolve property
+		var nodeProperty = targetObject[ propertyName ];
 
-				var bone = skeleton.bones[ i ];
+		if ( nodeProperty === undefined ) {
 
-				if ( bone.name === nodeName ) {
+			var nodeName = parsedPath.nodeName;
 
-					return bone;
+			console.error( "  trying to update property for track: " + nodeName +
+				'.' + propertyName + " but it wasn't found.", targetObject );
+			return;
 
-				}
-			}
+		}
 
-			return null;
+		// determine versioning scheme
+		var versioning = this.Versioning.None;
 
-		};
+		if ( targetObject.needsUpdate !== undefined ) { // material
 
-		var bone = searchSkeleton( root.skeleton );
+			versioning = this.Versioning.NeedsUpdate;
+			this.targetObject = targetObject;
 
-		if ( bone ) {
+		} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform
 
-			return bone;
+			versioning = this.Versioning.MatrixWorldNeedsUpdate;
+			this.targetObject = targetObject;
 
 		}
-	}
 
-	// search into node subtree.
-	if ( root.children ) {
+		// determine how the property gets bound
+		var bindingType = this.BindingType.Direct;
+
+		if ( propertyIndex !== undefined ) {
+			// access a sub element of the property array (only primitives are supported right now)
+
+			if ( propertyName === "morphTargetInfluences" ) {
+				// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.
 
-		var searchNodeSubtree = function( children ) {
+				// support resolving morphTarget names into indices.
+				if ( ! targetObject.geometry ) {
 
-			for( var i = 0; i < children.length; i ++ ) {
+					console.error( '  can not bind to morphTargetInfluences becasuse node does not have a geometry', this );
+					return;
 
-				var childNode = children[ i ];
+				}
 
-				if ( childNode.name === nodeName || childNode.uuid === nodeName ) {
+				if ( ! targetObject.geometry.morphTargets ) {
 
-					return childNode;
+					console.error( '  can not bind to morphTargetInfluences becasuse node does not have a geometry.morphTargets', this );
+					return;
 
 				}
 
-				var result = searchNodeSubtree( childNode.children );
+				for ( var i = 0; i < this.node.geometry.morphTargets.length; i ++ ) {
 
-				if ( result ) return result;
+					if ( targetObject.geometry.morphTargets[ i ].name === propertyIndex ) {
+
+						propertyIndex = i;
+						break;
+
+					}
+
+				}
 
 			}
 
-			return null;
+			bindingType = this.BindingType.ArrayElement;
 
-		};
+			this.resolvedProperty = nodeProperty;
+			this.propertyIndex = propertyIndex;
+
+		} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {
+			// must use copy for Object3D.Euler/Quaternion
+
+			bindingType = this.BindingType.HasFromToArray;
 
-		var subTreeNode = searchNodeSubtree( root.children );
+			this.resolvedProperty = nodeProperty;
 
-		if ( subTreeNode ) {
+		} else if ( Array.isArray( nodeProperty ) ) {
+      
+			bindingType = this.BindingType.EntireArray;
 
-			return subTreeNode;
+			this.resolvedProperty = nodeProperty;
+
+		} else {
+
+			this.propertyName = propertyName;
 
 		}
 
+		// select getter / setter
+		this.getValue = this.GetterByBindingType[ bindingType ];
+		this.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];
+
+	},
+
+	unbind: function() {
+
+		this.node = null;
+
+		// back to the prototype version of getValue / setValue
+		// note: avoiding to mutate the shape of 'this' via 'delete'
+		this.getValue = this._getValue_unbound;
+		this.setValue = this._setValue_unbound;
+
 	}
 
-	return null;
+} );
+
+//!\ DECLARE ALIAS AFTER assign prototype !
+Object.assign( PropertyBinding.prototype, {
 
-};
+	// initial state of these methods that calls 'bind'
+	_getValue_unbound: PropertyBinding.prototype.getValue,
+	_setValue_unbound: PropertyBinding.prototype.setValue,
 
+} );
 
 export { PropertyBinding };

+ 4 - 6
src/animation/PropertyMixer.js

@@ -56,9 +56,7 @@ function PropertyMixer( binding, typeName, valueSize ) {
 
 }
 
-PropertyMixer.prototype = {
-
-	constructor: PropertyMixer,
+Object.assign( PropertyMixer.prototype, {
 
 	// accumulate data in the 'incoming' region into 'accu<i>'
 	accumulate: function( accuIndex, weight ) {
@@ -118,7 +116,7 @@ PropertyMixer.prototype = {
 			var originalValueOffset = stride * 3;
 
 			this._mixBufferRegion(
-					buffer, offset, originalValueOffset, 1 - weight, stride );
+				buffer, offset, originalValueOffset, 1 - weight, stride );
 
 		}
 
@@ -188,7 +186,7 @@ PropertyMixer.prototype = {
 	_slerp: function( buffer, dstOffset, srcOffset, t, stride ) {
 
 		Quaternion.slerpFlat( buffer, dstOffset,
-				buffer, dstOffset, buffer, srcOffset, t );
+			buffer, dstOffset, buffer, srcOffset, t );
 
 	},
 
@@ -206,7 +204,7 @@ PropertyMixer.prototype = {
 
 	}
 
-};
+} );
 
 
 export { PropertyMixer };

+ 1 - 2
src/audio/Audio.js

@@ -286,8 +286,7 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 		return this.gain.gain.value;
 
 	},
-
-
+	
 	setVolume: function ( value ) {
 
 		this.gain.gain.value = value;

+ 10 - 8
src/core/BufferAttribute.js

@@ -32,17 +32,19 @@ function BufferAttribute( array, itemSize, normalized ) {
 
 }
 
-BufferAttribute.prototype = {
+Object.defineProperty( BufferAttribute.prototype, "needsUpdate", {
 
-	constructor: BufferAttribute,
-
-	isBufferAttribute: true,
+	set: function(value) { 
+		
+		if ( value === true ) this.version ++;
+	
+	}
 
-	set needsUpdate( value ) {
+});
 
-		if ( value === true ) this.version ++;
+Object.assign( BufferAttribute.prototype, {
 
-	},
+	isBufferAttribute: true,
 
 	setArray: function ( array ) {
 
@@ -335,7 +337,7 @@ BufferAttribute.prototype = {
 
 	}
 
-};
+} );
 
 //
 

+ 22 - 37
src/core/BufferGeometry.js

@@ -39,9 +39,9 @@ function BufferGeometry() {
 
 }
 
-BufferGeometry.prototype = {
+BufferGeometry.MaxIndex = 65535;
 
-	constructor: BufferGeometry,
+Object.assign( BufferGeometry.prototype, EventDispatcher.prototype, {
 
 	isBufferGeometry: true,
 
@@ -173,12 +173,10 @@ BufferGeometry.prototype = {
 
 		// rotate geometry around world x-axis
 
-		var m1;
+		var m1 = new Matrix4();
 
 		return function rotateX( angle ) {
 
-			if ( m1 === undefined ) m1 = new Matrix4();
-
 			m1.makeRotationX( angle );
 
 			this.applyMatrix( m1 );
@@ -193,12 +191,10 @@ BufferGeometry.prototype = {
 
 		// rotate geometry around world y-axis
 
-		var m1;
+		var m1 = new Matrix4();
 
 		return function rotateY( angle ) {
 
-			if ( m1 === undefined ) m1 = new Matrix4();
-
 			m1.makeRotationY( angle );
 
 			this.applyMatrix( m1 );
@@ -213,12 +209,10 @@ BufferGeometry.prototype = {
 
 		// rotate geometry around world z-axis
 
-		var m1;
+		var m1 = new Matrix4();
 
 		return function rotateZ( angle ) {
 
-			if ( m1 === undefined ) m1 = new Matrix4();
-
 			m1.makeRotationZ( angle );
 
 			this.applyMatrix( m1 );
@@ -233,12 +227,10 @@ BufferGeometry.prototype = {
 
 		// translate geometry
 
-		var m1;
+		var m1 = new Matrix4();
 
 		return function translate( x, y, z ) {
 
-			if ( m1 === undefined ) m1 = new Matrix4();
-
 			m1.makeTranslation( x, y, z );
 
 			this.applyMatrix( m1 );
@@ -253,12 +245,10 @@ BufferGeometry.prototype = {
 
 		// scale geometry
 
-		var m1;
+		var m1 = new Matrix4();
 
 		return function scale( x, y, z ) {
 
-			if ( m1 === undefined ) m1 = new Matrix4();
-
 			m1.makeScale( x, y, z );
 
 			this.applyMatrix( m1 );
@@ -271,12 +261,10 @@ BufferGeometry.prototype = {
 
 	lookAt: function () {
 
-		var obj;
+		var obj = new Object3D();
 
 		return function lookAt( vector ) {
 
-			if ( obj === undefined ) obj = new Object3D();
-
 			obj.lookAt( vector );
 
 			obj.updateMatrix();
@@ -979,28 +967,28 @@ BufferGeometry.prototype = {
 	clone: function () {
 
 		/*
-		// Handle primitives
+		 // Handle primitives
 
-		var parameters = this.parameters;
+		 var parameters = this.parameters;
 
-		if ( parameters !== undefined ) {
+		 if ( parameters !== undefined ) {
 
-			var values = [];
+		 var values = [];
 
-			for ( var key in parameters ) {
+		 for ( var key in parameters ) {
 
-				values.push( parameters[ key ] );
+		 values.push( parameters[ key ] );
 
-			}
+		 }
 
-			var geometry = Object.create( this.constructor.prototype );
-			this.constructor.apply( geometry, values );
-			return geometry;
+		 var geometry = Object.create( this.constructor.prototype );
+		 this.constructor.apply( geometry, values );
+		 return geometry;
 
-		}
+		 }
 
-		return new this.constructor().copy( this );
-		*/
+		 return new this.constructor().copy( this );
+		 */
 
 		return new BufferGeometry().copy( this );
 
@@ -1109,10 +1097,7 @@ BufferGeometry.prototype = {
 
 	}
 
-};
-
-BufferGeometry.MaxIndex = 65535;
+} );
 
-Object.assign( BufferGeometry.prototype, EventDispatcher.prototype );
 
 export { BufferGeometry };

+ 2 - 4
src/core/Clock.js

@@ -14,9 +14,7 @@ function Clock( autoStart ) {
 
 }
 
-Clock.prototype = {
-
-	constructor: Clock,
+Object.assign( Clock.prototype, {
 
 	start: function () {
 
@@ -67,7 +65,7 @@ Clock.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Clock };

+ 2 - 2
src/core/EventDispatcher.js

@@ -4,7 +4,7 @@
 
 function EventDispatcher() {}
 
-EventDispatcher.prototype = {
+Object.assign( EventDispatcher.prototype, {
 
 	addEventListener: function ( type, listener ) {
 
@@ -87,7 +87,7 @@ EventDispatcher.prototype = {
 
 	}
 
-};
+} );
 
 
 export { EventDispatcher };

+ 2 - 4
src/core/Face3.js

@@ -22,9 +22,7 @@ function Face3( a, b, c, normal, color, materialIndex ) {
 
 }
 
-Face3.prototype = {
-
-	constructor: Face3,
+Object.assign( Face3.prototype, {
 
 	clone: function () {
 
@@ -59,7 +57,7 @@ Face3.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Face3 };

+ 32 - 47
src/core/Geometry.js

@@ -59,9 +59,7 @@ function Geometry() {
 
 }
 
-Geometry.prototype = {
-
-	constructor: Geometry,
+Object.assign( Geometry.prototype, EventDispatcher.prototype, {
 
 	isGeometry: true,
 
@@ -112,12 +110,10 @@ Geometry.prototype = {
 
 		// rotate geometry around world x-axis
 
-		var m1;
+		var m1 = new Matrix4();
 
 		return function rotateX( angle ) {
 
-			if ( m1 === undefined ) m1 = new Matrix4();
-
 			m1.makeRotationX( angle );
 
 			this.applyMatrix( m1 );
@@ -132,12 +128,10 @@ Geometry.prototype = {
 
 		// rotate geometry around world y-axis
 
-		var m1;
+		var m1 = new Matrix4();
 
 		return function rotateY( angle ) {
 
-			if ( m1 === undefined ) m1 = new Matrix4();
-
 			m1.makeRotationY( angle );
 
 			this.applyMatrix( m1 );
@@ -152,12 +146,10 @@ Geometry.prototype = {
 
 		// rotate geometry around world z-axis
 
-		var m1;
+		var m1 = new Matrix4();
 
 		return function rotateZ( angle ) {
 
-			if ( m1 === undefined ) m1 = new Matrix4();
-
 			m1.makeRotationZ( angle );
 
 			this.applyMatrix( m1 );
@@ -172,12 +164,10 @@ Geometry.prototype = {
 
 		// translate geometry
 
-		var m1;
+		var m1 = new Matrix4();
 
 		return function translate( x, y, z ) {
 
-			if ( m1 === undefined ) m1 = new Matrix4();
-
 			m1.makeTranslation( x, y, z );
 
 			this.applyMatrix( m1 );
@@ -192,12 +182,10 @@ Geometry.prototype = {
 
 		// scale geometry
 
-		var m1;
+		var m1 = new Matrix4();
 
 		return function scale( x, y, z ) {
 
-			if ( m1 === undefined ) m1 = new Matrix4();
-
 			m1.makeScale( x, y, z );
 
 			this.applyMatrix( m1 );
@@ -210,12 +198,10 @@ Geometry.prototype = {
 
 	lookAt: function () {
 
-		var obj;
+		var obj = new Object3D();
 
 		return function lookAt( vector ) {
 
-			if ( obj === undefined ) obj = new Object3D();
-
 			obj.lookAt( vector );
 
 			obj.updateMatrix();
@@ -714,15 +700,15 @@ Geometry.prototype = {
 		}
 
 		var normalMatrix,
-		vertexOffset = this.vertices.length,
-		vertices1 = this.vertices,
-		vertices2 = geometry.vertices,
-		faces1 = this.faces,
-		faces2 = geometry.faces,
-		uvs1 = this.faceVertexUvs[ 0 ],
-		uvs2 = geometry.faceVertexUvs[ 0 ],
-		colors1 = this.colors,
-		colors2 = geometry.colors;
+			vertexOffset = this.vertices.length,
+			vertices1 = this.vertices,
+			vertices2 = geometry.vertices,
+			faces1 = this.faces,
+			faces2 = geometry.faces,
+			uvs1 = this.faceVertexUvs[ 0 ],
+			uvs2 = geometry.faceVertexUvs[ 0 ],
+			colors1 = this.colors,
+			colors2 = geometry.colors;
 
 		if ( materialIndexOffset === undefined ) materialIndexOffset = 0;
 
@@ -759,8 +745,8 @@ Geometry.prototype = {
 		for ( i = 0, il = faces2.length; i < il; i ++ ) {
 
 			var face = faces2[ i ], faceCopy, normal, color,
-			faceVertexNormals = face.vertexNormals,
-			faceVertexColors = face.vertexColors;
+				faceVertexNormals = face.vertexNormals,
+				faceVertexColors = face.vertexColors;
 
 			faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
 			faceCopy.normal.copy( face.normal );
@@ -1171,28 +1157,28 @@ Geometry.prototype = {
 	clone: function () {
 
 		/*
-		// Handle primitives
+		 // Handle primitives
 
-		var parameters = this.parameters;
+		 var parameters = this.parameters;
 
-		if ( parameters !== undefined ) {
+		 if ( parameters !== undefined ) {
 
-			var values = [];
+		 var values = [];
 
-			for ( var key in parameters ) {
+		 for ( var key in parameters ) {
 
-				values.push( parameters[ key ] );
+		 values.push( parameters[ key ] );
 
-			}
+		 }
 
-			var geometry = Object.create( this.constructor.prototype );
-			this.constructor.apply( geometry, values );
-			return geometry;
+		 var geometry = Object.create( this.constructor.prototype );
+		 this.constructor.apply( geometry, values );
+		 return geometry;
 
-		}
+		 }
 
-		return new this.constructor().copy( this );
-		*/
+		 return new this.constructor().copy( this );
+		 */
 
 		return new Geometry().copy( this );
 
@@ -1438,8 +1424,7 @@ Geometry.prototype = {
 
 	}
 
-};
+} );
 
-Object.assign( Geometry.prototype, EventDispatcher.prototype );
 
 export { GeometryIdCount, Geometry };

+ 10 - 8
src/core/InterleavedBuffer.js

@@ -21,17 +21,19 @@ function InterleavedBuffer( array, stride ) {
 
 }
 
-InterleavedBuffer.prototype = {
+Object.defineProperty( InterleavedBuffer.prototype, "needsUpdate", {
 
-	constructor: InterleavedBuffer,
-
-	isInterleavedBuffer: true,
+	set: function(value) { 
+		
+		if ( value === true ) this.version ++; 
+	
+	}
 
-	set needsUpdate( value ) {
+});
 
-		if ( value === true ) this.version ++;
+Object.assign( InterleavedBuffer.prototype, {
 
-	},
+	isInterleavedBuffer: true,
 
 	setArray: function ( array ) {
 
@@ -104,7 +106,7 @@ InterleavedBuffer.prototype = {
 
 	}
 
-};
+} );
 
 
 export { InterleavedBuffer };

+ 19 - 10
src/core/InterleavedBufferAttribute.js

@@ -16,24 +16,33 @@ function InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, normal
 
 }
 
+Object.defineProperties( InterleavedBufferAttribute.prototype, {
 
-InterleavedBufferAttribute.prototype = {
+	"count" : {
 
-	constructor: InterleavedBufferAttribute,
+		get: function () {
 
-	isInterleavedBufferAttribute: true,
-
-	get count() {
+			return this.data.count;
 
-		return this.data.count;
+		}
 
 	},
 
-	get array() {
+	"array" : {
 
-		return this.data.array;
+		get: function () {
 
-	},
+			return this.data.array;
+
+		}
+
+	}
+
+} );
+
+Object.assign( InterleavedBufferAttribute.prototype, {
+
+	isInterleavedBufferAttribute: true,
 
 	setX: function ( index, x ) {
 
@@ -127,7 +136,7 @@ InterleavedBufferAttribute.prototype = {
 
 	}
 
-};
+} );
 
 
 export { InterleavedBufferAttribute };

+ 2 - 4
src/core/Layers.js

@@ -8,9 +8,7 @@ function Layers() {
 
 }
 
-Layers.prototype = {
-
-	constructor: Layers,
+Object.assign( Layers.prototype, {
 
 	set: function ( channel ) {
 
@@ -42,7 +40,7 @@ Layers.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Layers };

+ 2 - 5
src/core/Object3D.js

@@ -101,9 +101,7 @@ function Object3D() {
 Object3D.DefaultUp = new Vector3( 0, 1, 0 );
 Object3D.DefaultMatrixAutoUpdate = true;
 
-Object3D.prototype = {
-
-	constructor: Object3D,
+Object.assign( Object3D.prototype, EventDispatcher.prototype, {
 
 	isObject3D: true,
 
@@ -730,8 +728,7 @@ Object3D.prototype = {
 
 	}
 
-};
+} );
 
-Object.assign( Object3D.prototype, EventDispatcher.prototype );
 
 export { Object3D };

+ 2 - 6
src/core/Raycaster.js

@@ -59,11 +59,7 @@ function intersectObject( object, raycaster, intersects, recursive ) {
 
 }
 
-//
-
-Raycaster.prototype = {
-
-	constructor: Raycaster,
+Object.assign( Raycaster.prototype, {
 
 	linePrecision: 1,
 
@@ -130,7 +126,7 @@ Raycaster.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Raycaster };

+ 3 - 4
src/extras/core/Curve.js

@@ -39,9 +39,7 @@ import { Matrix4 } from '../../math/Matrix4';
 
 function Curve() {}
 
-Curve.prototype = {
-
-	constructor: Curve,
+Object.assign( Curve.prototype, {
 
 	// Virtual base class method to overwrite and implement in subclasses
 	//	- t [0 .. 1]
@@ -382,6 +380,7 @@ Curve.prototype = {
 
 	}
 
-};
+} );
+
 
 export { Curve };

+ 7 - 7
src/extras/core/ShapePath.js

@@ -1,12 +1,11 @@
-/**
- * @author zz85 / http://www.lab4games.net/zz85/blog
- * minimal class for proxing functions to Path. Replaces old "extractSubpaths()"
- **/
-
 import { Path } from './Path';
 import { Shape } from './Shape';
 import { ShapeUtils } from '../ShapeUtils';
 
+/**
+ * @author zz85 / http://www.lab4games.net/zz85/blog
+ * minimal class for proxing functions to Path. Replaces old "extractSubpaths()"
+ **/
 
 function ShapePath() {
 
@@ -15,7 +14,7 @@ function ShapePath() {
 
 }
 
-ShapePath.prototype = {
+Object.assign( ShapePath.prototype, {
 
 	moveTo: function ( x, y ) {
 
@@ -276,6 +275,7 @@ ShapePath.prototype = {
 
 	}
 
-};
+} );
+
 
 export { ShapePath };

+ 1 - 1
src/geometries/ExtrudeGeometry.js

@@ -23,7 +23,7 @@ import { ShapeUtils } from '../extras/ShapeUtils';
  *  extrudePath: <THREE.Curve> // curve to extrude shape along
  *  frames: <Object> // containing arrays of tangents, normals, binormals
  *
- *  uvGenerator: <Object> // object that provides UV generator functions
+ *  UVGenerator: <Object> // object that provides UV generator functions
  *
  * }
  **/

+ 37 - 41
src/loaders/Loader.js

@@ -32,9 +32,40 @@ function Loader() {
 
 }
 
-Loader.prototype = {
+Loader.Handlers = {
+
+	handlers: [],
+
+	add: function ( regex, loader ) {
+
+		this.handlers.push( regex, loader );
+
+	},
+
+	get: function ( file ) {
+
+		var handlers = this.handlers;
+
+		for ( var i = 0, l = handlers.length; i < l; i += 2 ) {
+
+			var regex = handlers[ i ];
+			var loader = handlers[ i + 1 ];
 
-	constructor: Loader,
+			if ( regex.test( file ) ) {
+
+				return loader;
+
+			}
+
+		}
+
+		return null;
+
+	}
+
+};
+
+Object.assign( Loader.prototype, {
 
 	crossOrigin: undefined,
 
@@ -75,14 +106,12 @@ Loader.prototype = {
 			CustomBlending: CustomBlending
 		};
 
-		var color, textureLoader, materialLoader;
+		var color = new Color();
+		var textureLoader = new TextureLoader();
+		var materialLoader = new MaterialLoader();
 
 		return function createMaterial( m, texturePath, crossOrigin ) {
 
-			if ( color === undefined ) color = new Color();
-			if ( textureLoader === undefined ) textureLoader = new TextureLoader();
-			if ( materialLoader === undefined ) materialLoader = new MaterialLoader();
-
 			// convert from old material format
 
 			var textures = {};
@@ -320,40 +349,7 @@ Loader.prototype = {
 
 	} )()
 
-};
-
-Loader.Handlers = {
-
-	handlers: [],
-
-	add: function ( regex, loader ) {
-
-		this.handlers.push( regex, loader );
-
-	},
-
-	get: function ( file ) {
-
-		var handlers = this.handlers;
-
-		for ( var i = 0, l = handlers.length; i < l; i += 2 ) {
-
-			var regex = handlers[ i ];
-			var loader = handlers[ i + 1 ];
-
-			if ( regex.test( file ) ) {
-
-				return loader;
-
-			}
-
-		}
-
-		return null;
-
-	}
-
-};
+} );
 
 
 export { Loader };

+ 12 - 11
src/materials/Material.js

@@ -63,24 +63,26 @@ function Material() {
 
 }
 
-Material.prototype = {
+Object.defineProperty( Material.prototype, "needsUpdate", {
 
-	constructor: Material,
-
-	isMaterial: true,
-
-	get needsUpdate() {
+	get: function() {
 
 		return this._needsUpdate;
 
 	},
-
-	set needsUpdate( value ) {
+	
+	set: function(value) {
 
 		if ( value === true ) this.update();
 		this._needsUpdate = value;
 
-	},
+	}
+
+});
+
+Object.assign( Material.prototype, EventDispatcher.prototype, {
+
+	isMaterial: true,
 
 	setValues: function ( values ) {
 
@@ -346,8 +348,7 @@ Material.prototype = {
 
 	}
 
-};
+} );
 
-Object.assign( Material.prototype, EventDispatcher.prototype );
 
 export { Material };

+ 2 - 4
src/materials/MultiMaterial.js

@@ -16,9 +16,7 @@ function MultiMaterial( materials ) {
 
 }
 
-MultiMaterial.prototype = {
-
-	constructor: MultiMaterial,
+Object.assign( MultiMaterial.prototype, {
 
 	isMultiMaterial: true,
 
@@ -68,7 +66,7 @@ MultiMaterial.prototype = {
 
 	}
 
-};
+} );
 
 
 export { MultiMaterial };

+ 2 - 4
src/math/Box2.js

@@ -11,9 +11,7 @@ function Box2( min, max ) {
 
 }
 
-Box2.prototype = {
-
-	constructor: Box2,
+Object.assign( Box2.prototype, {
 
 	set: function ( min, max ) {
 
@@ -216,7 +214,7 @@ Box2.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Box2 };

+ 3 - 7
src/math/Box3.js

@@ -13,9 +13,7 @@ function Box3( min, max ) {
 
 }
 
-Box3.prototype = {
-
-	constructor: Box3,
+Object.assign( Box3.prototype, {
 
 	isBox3: true,
 
@@ -310,12 +308,10 @@ Box3.prototype = {
 
 	intersectsSphere: ( function () {
 
-		var closestPoint;
+		var closestPoint = new Vector3();
 
 		return function intersectsSphere( sphere ) {
 
-			if ( closestPoint === undefined ) closestPoint = new Vector3();
-
 			// Find the point on the AABB closest to the sphere center.
 			this.clampPoint( sphere.center, closestPoint );
 
@@ -483,7 +479,7 @@ Box3.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Box3 };

+ 27 - 29
src/math/Color.js

@@ -4,6 +4,31 @@ import { _Math } from './Math';
  * @author mrdoob / http://mrdoob.com/
  */
 
+var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
+	'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
+	'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
+	'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
+	'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
+	'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
+	'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
+	'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
+	'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
+	'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
+	'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
+	'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
+	'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
+	'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
+	'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
+	'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
+	'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
+	'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
+	'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
+	'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
+	'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
+	'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
+	'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
+	'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
+
 function Color( r, g, b ) {
 
 	if ( g === undefined && b === undefined ) {
@@ -17,9 +42,7 @@ function Color( r, g, b ) {
 
 }
 
-Color.prototype = {
-
-	constructor: Color,
+Object.assign( Color.prototype, {
 
 	isColor: true,
 
@@ -494,32 +517,7 @@ Color.prototype = {
 
 	}
 
-};
-
-var ColorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,
-'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,
-'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,
-'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,
-'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,
-'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,
-'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,
-'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,
-'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,
-'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,
-'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,
-'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,
-'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,
-'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,
-'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,
-'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,
-'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,
-'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,
-'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,
-'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,
-'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,
-'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,
-'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,
-'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };
+} );
 
 
 export { Color };

+ 2 - 4
src/math/Cylindrical.js

@@ -15,9 +15,7 @@ function Cylindrical( radius, theta, y ) {
 
 }
 
-Cylindrical.prototype = {
-
-	constructor: Cylindrical,
+Object.assign( Cylindrical.prototype, {
 
 	set: function ( radius, theta, y ) {
 
@@ -55,7 +53,7 @@ Cylindrical.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Cylindrical };

+ 48 - 32
src/math/Euler.js

@@ -22,63 +22,81 @@ Euler.RotationOrders = [ 'XYZ', 'YZX', 'ZXY', 'XZY', 'YXZ', 'ZYX' ];
 
 Euler.DefaultOrder = 'XYZ';
 
-Euler.prototype = {
+Object.defineProperties( Euler.prototype, {
 
-	constructor: Euler,
+	"x" : {
 
-	isEuler: true,
+		get: function () {
 
-	get x () {
+			return this._x;
 
-		return this._x;
+		},
 
-	},
+		set: function ( value ) {
 
-	set x ( value ) {
+			this._x = value;
+			this.onChangeCallback();
 
-		this._x = value;
-		this.onChangeCallback();
+		}
 
 	},
 
-	get y () {
+	"y" : {
 
-		return this._y;
+		get: function () {
 
-	},
+			return this._y;
 
-	set y ( value ) {
+		},
 
-		this._y = value;
-		this.onChangeCallback();
+		set: function ( value ) {
+
+			this._y = value;
+			this.onChangeCallback();
+
+		}
 
 	},
 
-	get z () {
+	"z" : {
 
-		return this._z;
+		get: function () {
 
-	},
+			return this._z;
 
-	set z ( value ) {
+		},
 
-		this._z = value;
-		this.onChangeCallback();
+		set: function ( value ) {
+
+			this._z = value;
+			this.onChangeCallback();
+
+		}
 
 	},
 
-	get order () {
+	"order" : {
 
-		return this._order;
+		get: function () {
 
-	},
+			return this._order;
 
-	set order ( value ) {
+		},
 
-		this._order = value;
-		this.onChangeCallback();
+		set: function ( value ) {
 
-	},
+			this._order = value;
+			this.onChangeCallback();
+
+		}
+
+	}
+
+});
+
+Object.assign( Euler.prototype, {
+
+	isEuler: true,
 
 	set: function ( x, y, z, order ) {
 
@@ -237,12 +255,10 @@ Euler.prototype = {
 
 	setFromQuaternion: function () {
 
-		var matrix;
+		var matrix = new Matrix4();
 
 		return function setFromQuaternion( q, order, update ) {
 
-			if ( matrix === undefined ) matrix = new Matrix4();
-
 			matrix.makeRotationFromQuaternion( q );
 
 			return this.setFromRotationMatrix( matrix, order, update );
@@ -330,7 +346,7 @@ Euler.prototype = {
 
 	onChangeCallback: function () {}
 
-};
+} );
 
 
 export { Euler };

+ 3 - 6
src/math/Frustum.js

@@ -23,9 +23,7 @@ function Frustum( p0, p1, p2, p3, p4, p5 ) {
 
 }
 
-Frustum.prototype = {
-
-	constructor: Frustum,
+Object.assign( Frustum.prototype, {
 
 	set: function ( p0, p1, p2, p3, p4, p5 ) {
 
@@ -178,8 +176,7 @@ Frustum.prototype = {
 		};
 
 	}(),
-
-
+	
 	containsPoint: function ( point ) {
 
 		var planes = this.planes;
@@ -198,7 +195,7 @@ Frustum.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Frustum };

+ 14 - 16
src/math/Interpolant.js

@@ -20,8 +20,7 @@
  * @author tschw
  */
 
-function Interpolant(
-		parameterPositions, sampleValues, sampleSize, resultBuffer ) {
+function Interpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 
 	this.parameterPositions = parameterPositions;
 	this._cachedIndex = 0;
@@ -33,9 +32,7 @@ function Interpolant(
 
 }
 
-Interpolant.prototype = {
-
-	constructor: Interpolant,
+Object.assign( Interpolant.prototype, {
 
 	evaluate: function( t ) {
 
@@ -52,10 +49,10 @@ Interpolant.prototype = {
 				var right;
 
 				linear_scan: {
-//- See http://jsperf.com/comparison-to-undefined/3
-//- slower code:
-//-
-//- 				if ( t >= t1 || t1 === undefined ) {
+					//- See http://jsperf.com/comparison-to-undefined/3
+					//- slower code:
+					//-
+					//- 				if ( t >= t1 || t1 === undefined ) {
 					forward_scan: if ( ! ( t < t1 ) ) {
 
 						for ( var giveUpAt = i1 + 2; ;) {
@@ -92,8 +89,8 @@ Interpolant.prototype = {
 
 					}
 
-//- slower code:
-//-					if ( t < t0 || t0 === undefined ) {
+					//- slower code:
+					//-					if ( t < t0 || t0 === undefined ) {
 					if ( ! ( t >= t0 ) ) {
 
 						// looping?
@@ -244,15 +241,16 @@ Interpolant.prototype = {
 
 	}
 
-};
+} );
 
+//!\ DECLARE ALIAS AFTER assign prototype !
 Object.assign( Interpolant.prototype, {
 
-	beforeStart_: //( 0, t, t0 ), returns this.resultBuffer
-		Interpolant.prototype.copySampleValue_,
+	//( 0, t, t0 ), returns this.resultBuffer
+	beforeStart_: Interpolant.prototype.copySampleValue_,
 
-	afterEnd_: //( N-1, tN-1, t ), returns this.resultBuffer
-		Interpolant.prototype.copySampleValue_
+	//( N-1, tN-1, t ), returns this.resultBuffer
+	afterEnd_: Interpolant.prototype.copySampleValue_,
 
 } );
 

+ 2 - 4
src/math/Line3.js

@@ -12,9 +12,7 @@ function Line3( start, end ) {
 
 }
 
-Line3.prototype = {
-
-	constructor: Line3,
+Object.assign( Line3.prototype, {
 
 	set: function ( start, end ) {
 
@@ -126,7 +124,7 @@ Line3.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Line3 };

+ 3 - 7
src/math/Matrix3.js

@@ -25,9 +25,7 @@ function Matrix3() {
 
 }
 
-Matrix3.prototype = {
-
-	constructor: Matrix3,
+Object.assign( Matrix3.prototype, {
 
 	isMatrix3: true,
 
@@ -97,12 +95,10 @@ Matrix3.prototype = {
 
 	applyToBufferAttribute: function () {
 
-		var v1;
+		var v1 = new Vector3();
 
 		return function applyToBufferAttribute( attribute ) {
 
-			if ( v1 === undefined ) v1 = new Vector3();
-
 			for ( var i = 0, l = attribute.count; i < l; i ++ ) {
 
 				v1.x = attribute.getX( i );
@@ -274,7 +270,7 @@ Matrix3.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Matrix3 };

+ 9 - 27
src/math/Matrix4.js

@@ -33,9 +33,7 @@ function Matrix4() {
 
 }
 
-Matrix4.prototype = {
-
-	constructor: Matrix4,
+Object.assign( Matrix4.prototype, {
 
 	isMatrix4: true,
 
@@ -119,12 +117,10 @@ Matrix4.prototype = {
 
 	extractRotation: function () {
 
-		var v1;
+		var v1 = new Vector3();
 
 		return function extractRotation( m ) {
 
-			if ( v1 === undefined ) v1 = new Vector3();
-
 			var te = this.elements;
 			var me = m.elements;
 
@@ -317,18 +313,12 @@ Matrix4.prototype = {
 
 	lookAt: function () {
 
-		var x, y, z;
+		var x = new Vector3();
+		var y = new Vector3();
+		var z = new Vector3();
 
 		return function lookAt( eye, target, up ) {
 
-			if ( x === undefined ) {
-
-				x = new Vector3();
-				y = new Vector3();
-				z = new Vector3();
-
-			}
-
 			var te = this.elements;
 
 			z.subVectors( eye, target ).normalize();
@@ -450,12 +440,10 @@ Matrix4.prototype = {
 
 	applyToBufferAttribute: function () {
 
-		var v1;
+		var v1 = new Vector3();
 
 		return function applyToBufferAttribute( attribute ) {
 
-			if ( v1 === undefined ) v1 = new Vector3();
-
 			for ( var i = 0, l = attribute.count; i < l; i ++ ) {
 
 				v1.x = attribute.getX( i );
@@ -772,17 +760,11 @@ Matrix4.prototype = {
 
 	decompose: function () {
 
-		var vector, matrix;
+		var vector = new Vector3();
+		var matrix = new Matrix4();
 
 		return function decompose( position, quaternion, scale ) {
 
-			if ( vector === undefined ) {
-
-				vector = new Vector3();
-				matrix = new Matrix4();
-
-			}
-
 			var te = this.elements;
 
 			var sx = vector.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
@@ -939,7 +921,7 @@ Matrix4.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Matrix4 };

+ 2 - 4
src/math/Plane.js

@@ -12,9 +12,7 @@ function Plane( normal, constant ) {
 
 }
 
-Plane.prototype = {
-
-	constructor: Plane,
+Object.assign( Plane.prototype, {
 
 	set: function ( normal, constant ) {
 
@@ -232,7 +230,7 @@ Plane.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Plane };

+ 121 - 102
src/math/Quaternion.js

@@ -16,62 +16,153 @@ function Quaternion( x, y, z, w ) {
 
 }
 
-Quaternion.prototype = {
-
-	constructor: Quaternion,
+Object.assign( Quaternion, {
 
-	get x () {
+	slerp: function( qa, qb, qm, t ) {
 
-		return this._x;
+		return qm.copy( qa ).slerp( qb, t );
 
 	},
 
-	set x ( value ) {
+	slerpFlat: function(
+			dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
 
-		this._x = value;
-		this.onChangeCallback();
+		// fuzz-free, array-based Quaternion SLERP operation
 
-	},
+		var x0 = src0[ srcOffset0 + 0 ],
+			y0 = src0[ srcOffset0 + 1 ],
+			z0 = src0[ srcOffset0 + 2 ],
+			w0 = src0[ srcOffset0 + 3 ],
+
+			x1 = src1[ srcOffset1 + 0 ],
+			y1 = src1[ srcOffset1 + 1 ],
+			z1 = src1[ srcOffset1 + 2 ],
+			w1 = src1[ srcOffset1 + 3 ];
 
-	get y () {
+		if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
 
-		return this._y;
+			var s = 1 - t,
 
-	},
+				cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
 
-	set y ( value ) {
+				dir = ( cos >= 0 ? 1 : - 1 ),
+				sqrSin = 1 - cos * cos;
 
-		this._y = value;
-		this.onChangeCallback();
+			// Skip the Slerp for tiny steps to avoid numeric problems:
+			if ( sqrSin > Number.EPSILON ) {
 
-	},
+				var sin = Math.sqrt( sqrSin ),
+					len = Math.atan2( sin, cos * dir );
 
-	get z () {
+				s = Math.sin( s * len ) / sin;
+				t = Math.sin( t * len ) / sin;
 
-		return this._z;
+			}
 
-	},
+			var tDir = t * dir;
 
-	set z ( value ) {
+			x0 = x0 * s + x1 * tDir;
+			y0 = y0 * s + y1 * tDir;
+			z0 = z0 * s + z1 * tDir;
+			w0 = w0 * s + w1 * tDir;
 
-		this._z = value;
-		this.onChangeCallback();
+			// Normalize in case we just did a lerp:
+			if ( s === 1 - t ) {
+
+				var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
+
+				x0 *= f;
+				y0 *= f;
+				z0 *= f;
+				w0 *= f;
+
+			}
+
+		}
+
+		dst[ dstOffset ] = x0;
+		dst[ dstOffset + 1 ] = y0;
+		dst[ dstOffset + 2 ] = z0;
+		dst[ dstOffset + 3 ] = w0;
+
+	}
+
+} );
+
+Object.defineProperties( Quaternion.prototype, {
+
+	"x" : {
+
+		get: function () {
+
+			return this._x;
+
+		},
+
+		set: function ( value ) {
+
+			this._x = value;
+			this.onChangeCallback();
+
+		}
 
 	},
 
-	get w () {
+	"y" : {
+
+		get: function () {
+
+			return this._y;
+
+		},
 
-		return this._w;
+		set: function ( value ) {
+
+			this._y = value;
+			this.onChangeCallback();
+
+		}
 
 	},
 
-	set w ( value ) {
+	"z" : {
 
-		this._w = value;
-		this.onChangeCallback();
+		get: function () {
+
+			return this._z;
+
+		},
+
+		set: function ( value ) {
+
+			this._z = value;
+			this.onChangeCallback();
+
+		}
 
 	},
 
+	"w" : {
+
+		get: function () {
+
+			return this._w;
+
+		},
+
+		set: function ( value ) {
+
+			this._w = value;
+			this.onChangeCallback();
+
+		}
+
+	}
+
+});
+
+Object.assign( Quaternion.prototype, {
+
 	set: function ( x, y, z, w ) {
 
 		this._x = x;
@@ -259,7 +350,8 @@ Quaternion.prototype = {
 
 		// assumes direction vectors vFrom and vTo are normalized
 
-		var v1, r;
+		var v1 = new Vector3();
+		var r;
 
 		var EPS = 0.000001;
 
@@ -453,7 +545,7 @@ Quaternion.prototype = {
 
 		var halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );
 		var ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,
-		ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
+			ratioB = Math.sin( t * halfTheta ) / sinHalfTheta;
 
 		this._w = ( w * ratioA + this._w * ratioB );
 		this._x = ( x * ratioA + this._x * ratioB );
@@ -511,79 +603,6 @@ Quaternion.prototype = {
 
 	onChangeCallback: function () {}
 
-};
-
-Object.assign( Quaternion, {
-
-	slerp: function( qa, qb, qm, t ) {
-
-		return qm.copy( qa ).slerp( qb, t );
-
-	},
-
-	slerpFlat: function(
-			dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {
-
-		// fuzz-free, array-based Quaternion SLERP operation
-
-		var x0 = src0[ srcOffset0 + 0 ],
-			y0 = src0[ srcOffset0 + 1 ],
-			z0 = src0[ srcOffset0 + 2 ],
-			w0 = src0[ srcOffset0 + 3 ],
-
-			x1 = src1[ srcOffset1 + 0 ],
-			y1 = src1[ srcOffset1 + 1 ],
-			z1 = src1[ srcOffset1 + 2 ],
-			w1 = src1[ srcOffset1 + 3 ];
-
-		if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
-
-			var s = 1 - t,
-
-				cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
-
-				dir = ( cos >= 0 ? 1 : - 1 ),
-				sqrSin = 1 - cos * cos;
-
-			// Skip the Slerp for tiny steps to avoid numeric problems:
-			if ( sqrSin > Number.EPSILON ) {
-
-				var sin = Math.sqrt( sqrSin ),
-					len = Math.atan2( sin, cos * dir );
-
-				s = Math.sin( s * len ) / sin;
-				t = Math.sin( t * len ) / sin;
-
-			}
-
-			var tDir = t * dir;
-
-			x0 = x0 * s + x1 * tDir;
-			y0 = y0 * s + y1 * tDir;
-			z0 = z0 * s + z1 * tDir;
-			w0 = w0 * s + w1 * tDir;
-
-			// Normalize in case we just did a lerp:
-			if ( s === 1 - t ) {
-
-				var f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );
-
-				x0 *= f;
-				y0 *= f;
-				z0 *= f;
-				w0 *= f;
-
-			}
-
-		}
-
-		dst[ dstOffset ] = x0;
-		dst[ dstOffset + 1 ] = y0;
-		dst[ dstOffset + 2 ] = z0;
-		dst[ dstOffset + 3 ] = w0;
-
-	}
-
 } );
 
 

+ 2 - 6
src/math/Ray.js

@@ -11,9 +11,7 @@ function Ray( origin, direction ) {
 
 }
 
-Ray.prototype = {
-
-	constructor: Ray,
+Object.assign( Ray.prototype, {
 
 	set: function ( origin, direction ) {
 
@@ -325,8 +323,6 @@ Ray.prototype = {
 
 	},
 
-
-
 	intersectsPlane: function ( plane ) {
 
 		// check if the ray lies on the plane first
@@ -534,7 +530,7 @@ Ray.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Ray };

+ 3 - 7
src/math/Sphere.js

@@ -13,9 +13,7 @@ function Sphere( center, radius ) {
 
 }
 
-Sphere.prototype = {
-
-	constructor: Sphere,
+Object.assign( Sphere.prototype, {
 
 	set: function ( center, radius ) {
 
@@ -28,12 +26,10 @@ Sphere.prototype = {
 
 	setFromPoints: function () {
 
-		var box;
+		var box = new Box3();
 
 		return function setFromPoints( points, optionalCenter ) {
 
-			if ( box === undefined ) box = new Box3(); // see #10547
-
 			var center = this.center;
 
 			if ( optionalCenter !== undefined ) {
@@ -176,7 +172,7 @@ Sphere.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Sphere };

+ 2 - 4
src/math/Spherical.js

@@ -20,9 +20,7 @@ function Spherical( radius, phi, theta ) {
 
 }
 
-Spherical.prototype = {
-
-	constructor: Spherical,
+Object.assign( Spherical.prototype, {
 
 	set: function ( radius, phi, theta ) {
 
@@ -80,7 +78,7 @@ Spherical.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Spherical };

+ 60 - 64
src/math/Triangle.js

@@ -15,92 +15,94 @@ function Triangle( a, b, c ) {
 
 }
 
-Triangle.normal = function () {
+Object.assign( Triangle, {
 
-	var v0 = new Vector3();
+	normal: function () {
 
-	return function normal( a, b, c, optionalTarget ) {
+		var v0 = new Vector3();
 
-		var result = optionalTarget || new Vector3();
+		return function normal( a, b, c, optionalTarget ) {
 
-		result.subVectors( c, b );
-		v0.subVectors( a, b );
-		result.cross( v0 );
+			var result = optionalTarget || new Vector3();
 
-		var resultLengthSq = result.lengthSq();
-		if ( resultLengthSq > 0 ) {
+			result.subVectors( c, b );
+			v0.subVectors( a, b );
+			result.cross( v0 );
 
-			return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );
+			var resultLengthSq = result.lengthSq();
+			if ( resultLengthSq > 0 ) {
 
-		}
+				return result.multiplyScalar( 1 / Math.sqrt( resultLengthSq ) );
+
+			}
 
-		return result.set( 0, 0, 0 );
+			return result.set( 0, 0, 0 );
 
-	};
+		};
 
-}();
+	}(),
 
-// static/instance method to calculate barycentric coordinates
-// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
-Triangle.barycoordFromPoint = function () {
+	// static/instance method to calculate barycentric coordinates
+	// based on: http://www.blackpawn.com/texts/pointinpoly/default.html
+	barycoordFromPoint: function () {
 
-	var v0 = new Vector3();
-	var v1 = new Vector3();
-	var v2 = new Vector3();
+		var v0 = new Vector3();
+		var v1 = new Vector3();
+		var v2 = new Vector3();
 
-	return function barycoordFromPoint( point, a, b, c, optionalTarget ) {
+		return function barycoordFromPoint( point, a, b, c, optionalTarget ) {
 
-		v0.subVectors( c, a );
-		v1.subVectors( b, a );
-		v2.subVectors( point, a );
+			v0.subVectors( c, a );
+			v1.subVectors( b, a );
+			v2.subVectors( point, a );
 
-		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 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 );
+			var denom = ( dot00 * dot11 - dot01 * dot01 );
 
-		var result = optionalTarget || new Vector3();
+			var result = optionalTarget || new Vector3();
 
-		// collinear or singular triangle
-		if ( denom === 0 ) {
+			// 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 result.set( - 2, - 1, - 1 );
+				// arbitrary location outside of triangle?
+				// not sure if this is the best idea, maybe should be returning undefined
+				return result.set( - 2, - 1, - 1 );
 
-		}
+			}
 
-		var invDenom = 1 / denom;
-		var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
-		var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
+			var invDenom = 1 / denom;
+			var u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;
+			var v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;
 
-		// barycentric coordinates must always sum to 1
-		return result.set( 1 - u - v, v, u );
+			// barycentric coordinates must always sum to 1
+			return result.set( 1 - u - v, v, u );
 
-	};
+		};
 
-}();
+	}(),
 
-Triangle.containsPoint = function () {
+	containsPoint: function () {
 
-	var v1 = new Vector3();
+		var v1 = new Vector3();
 
-	return function containsPoint( point, a, b, c ) {
+		return function containsPoint( point, a, b, c ) {
 
-		var result = Triangle.barycoordFromPoint( point, a, b, c, v1 );
+			var result = Triangle.barycoordFromPoint( point, a, b, c, v1 );
 
-		return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );
+			return ( result.x >= 0 ) && ( result.y >= 0 ) && ( ( result.x + result.y ) <= 1 );
 
-	};
+		};
 
-}();
+	}()
 
-Triangle.prototype = {
+} );
 
-	constructor: Triangle,
+Object.assign( Triangle.prototype, {
 
 	set: function ( a, b, c ) {
 
@@ -189,19 +191,13 @@ Triangle.prototype = {
 
 	closestPointToPoint: function () {
 
-		var plane, edgeList, projectedPoint, closestPoint;
+		var plane = new Plane();
+		var edgeList = [ new Line3(), new Line3(), new Line3() ];
+		var projectedPoint = new Vector3();
+		var closestPoint = new Vector3();
 
 		return function closestPointToPoint( point, optionalTarget ) {
 
-			if ( plane === undefined ) {
-
-				plane = new Plane();
-				edgeList = [ new Line3(), new Line3(), new Line3() ];
-				projectedPoint = new Vector3();
-				closestPoint = new Vector3();
-
-			}
-
 			var result = optionalTarget || new Vector3();
 			var minDistance = Infinity;
 
@@ -256,7 +252,7 @@ Triangle.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Triangle };

+ 39 - 37
src/math/Vector2.js

@@ -12,37 +12,45 @@ function Vector2( x, y ) {
 
 }
 
-Vector2.prototype = {
-
-	constructor: Vector2,
-
-	isVector2: true,
-
-	get width() {
-
-		return this.x;
-
-	},
-
-	set width( value ) {
-
-		this.x = value;
-
-	},
-
-	get height() {
-
-		return this.y;
-
-	},
-
-	set height( value ) {
+Object.defineProperties( Vector2.prototype, {
+
+	"width" : {
+		
+		get: function () { 
+			
+			return this.x; 
+		
+		},
+		
+		set: function ( value ) { 
+			
+			this.x = value; 
+		
+		}
+		
+	},
+
+	"height" : {
+		
+		get: function () { 
+			
+			return this.y; 
+		
+		},
+		
+		set: function ( value ) { 
+			
+			this.y = value; 
+		
+		}
+		
+	}
 
-		this.y = value;
+} );
 
-	},
+Object.assign( Vector2.prototype, {
 
-	//
+	isVector2: true,
 
 	set: function ( x, y ) {
 
@@ -269,17 +277,11 @@ Vector2.prototype = {
 
 	clampScalar: function () {
 
-		var min, max;
+		var min = new Vector2();
+		var max = new Vector2();
 
 		return function clampScalar( minVal, maxVal ) {
 
-			if ( min === undefined ) {
-
-				min = new Vector2();
-				max = new Vector2();
-
-			}
-
 			min.set( minVal, minVal );
 			max.set( maxVal, maxVal );
 
@@ -482,7 +484,7 @@ Vector2.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Vector2 };

+ 10 - 30
src/math/Vector3.js

@@ -19,9 +19,7 @@ function Vector3( x, y, z ) {
 
 }
 
-Vector3.prototype = {
-
-	constructor: Vector3,
+Object.assign( Vector3.prototype, {
 
 	isVector3: true,
 
@@ -246,7 +244,7 @@ Vector3.prototype = {
 
 	applyEuler: function () {
 
-		var quaternion;
+		var quaternion = new Quaternion();
 
 		return function applyEuler( euler ) {
 
@@ -256,8 +254,6 @@ Vector3.prototype = {
 
 			}
 
-			if ( quaternion === undefined ) quaternion = new Quaternion();
-
 			return this.applyQuaternion( quaternion.setFromEuler( euler ) );
 
 		};
@@ -266,12 +262,10 @@ Vector3.prototype = {
 
 	applyAxisAngle: function () {
 
-		var quaternion;
+		var quaternion = new Quaternion();
 
 		return function applyAxisAngle( axis, angle ) {
 
-			if ( quaternion === undefined ) quaternion = new Quaternion();
-
 			return this.applyQuaternion( quaternion.setFromAxisAngle( axis, angle ) );
 
 		};
@@ -329,12 +323,10 @@ Vector3.prototype = {
 
 	project: function () {
 
-		var matrix;
+		var matrix = new Matrix4();
 
 		return function project( camera ) {
 
-			if ( matrix === undefined ) matrix = new Matrix4();
-
 			matrix.multiplyMatrices( camera.projectionMatrix, matrix.getInverse( camera.matrixWorld ) );
 			return this.applyMatrix4( matrix );
 
@@ -344,12 +336,10 @@ Vector3.prototype = {
 
 	unproject: function () {
 
-		var matrix;
+		var matrix = new Matrix4();
 
 		return function unproject( camera ) {
 
-			if ( matrix === undefined ) matrix = new Matrix4();
-
 			matrix.multiplyMatrices( camera.matrixWorld, matrix.getInverse( camera.projectionMatrix ) );
 			return this.applyMatrix4( matrix );
 
@@ -423,17 +413,11 @@ Vector3.prototype = {
 
 	clampScalar: function () {
 
-		var min, max;
+		var min = new Vector3();
+		var max = new Vector3();
 
 		return function clampScalar( minVal, maxVal ) {
 
-			if ( min === undefined ) {
-
-				min = new Vector3();
-				max = new Vector3();
-
-			}
-
 			min.set( minVal, minVal, minVal );
 			max.set( maxVal, maxVal, maxVal );
 
@@ -595,12 +579,10 @@ Vector3.prototype = {
 
 	projectOnPlane: function () {
 
-		var v1;
+		var v1 = new Vector3();
 
 		return function projectOnPlane( planeNormal ) {
 
-			if ( v1 === undefined ) v1 = new Vector3();
-
 			v1.copy( this ).projectOnVector( planeNormal );
 
 			return this.sub( v1 );
@@ -614,12 +596,10 @@ Vector3.prototype = {
 		// reflect incident vector off plane orthogonal to normal
 		// normal is assumed to have unit length
 
-		var v1;
+		var v1 = new Vector3();
 
 		return function reflect( normal ) {
 
-			if ( v1 === undefined ) v1 = new Vector3();
-
 			return this.sub( v1.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );
 
 		};
@@ -760,7 +740,7 @@ Vector3.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Vector3 };

+ 4 - 12
src/math/Vector4.js

@@ -15,9 +15,7 @@ function Vector4( x, y, z, w ) {
 
 }
 
-Vector4.prototype = {
-
-	constructor: Vector4,
+Object.assign( Vector4.prototype, {
 
 	isVector4: true,
 
@@ -450,17 +448,11 @@ Vector4.prototype = {
 
 	clampScalar: function () {
 
-		var min, max;
+		var min = new Vector4();
+		var max = new Vector4();
 
 		return function clampScalar( minVal, maxVal ) {
 
-			if ( min === undefined ) {
-
-				min = new Vector4();
-				max = new Vector4();
-
-			}
-
 			min.set( minVal, minVal, minVal, minVal );
 			max.set( maxVal, maxVal, maxVal, maxVal );
 
@@ -628,7 +620,7 @@ Vector4.prototype = {
 
 	}
 
-};
+} );
 
 
 export { Vector4 };

+ 2 - 4
src/math/interpolants/CubicInterpolant.js

@@ -12,8 +12,7 @@ import { WrapAroundEnding, ZeroSlopeEnding } from '../../constants';
  * @author tschw
  */
 
-function CubicInterpolant(
-		parameterPositions, sampleValues, sampleSize, resultBuffer ) {
+function CubicInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 
 	Interpolant.call(
 			this, parameterPositions, sampleValues, sampleSize, resultBuffer );
@@ -25,8 +24,7 @@ function CubicInterpolant(
 
 }
 
-CubicInterpolant.prototype =
-		Object.assign( Object.create( Interpolant.prototype ), {
+CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
 
 	constructor: CubicInterpolant,
 

+ 3 - 6
src/math/interpolants/DiscreteInterpolant.js

@@ -8,16 +8,13 @@ import { Interpolant } from '../Interpolant';
  * @author tschw
  */
 
-function DiscreteInterpolant(
-		parameterPositions, sampleValues, sampleSize, resultBuffer ) {
+function DiscreteInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 
-	Interpolant.call(
-			this, parameterPositions, sampleValues, sampleSize, resultBuffer );
+	Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
 
 }
 
-DiscreteInterpolant.prototype =
-		Object.assign( Object.create( Interpolant.prototype ), {
+DiscreteInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
 
 	constructor: DiscreteInterpolant,
 

+ 3 - 6
src/math/interpolants/LinearInterpolant.js

@@ -4,16 +4,13 @@ import { Interpolant } from '../Interpolant';
  * @author tschw
  */
 
-function LinearInterpolant(
-		parameterPositions, sampleValues, sampleSize, resultBuffer ) {
+function LinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 
-	Interpolant.call(
-			this, parameterPositions, sampleValues, sampleSize, resultBuffer );
+	Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
 
 }
 
-LinearInterpolant.prototype =
-		Object.assign( Object.create( Interpolant.prototype ), {
+LinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
 
 	constructor: LinearInterpolant,
 

+ 3 - 6
src/math/interpolants/QuaternionLinearInterpolant.js

@@ -7,16 +7,13 @@ import { Quaternion } from '../Quaternion';
  * @author tschw
  */
 
-function QuaternionLinearInterpolant(
-		parameterPositions, sampleValues, sampleSize, resultBuffer ) {
+function QuaternionLinearInterpolant( parameterPositions, sampleValues, sampleSize, resultBuffer ) {
 
-	Interpolant.call(
-			this, parameterPositions, sampleValues, sampleSize, resultBuffer );
+	Interpolant.call( this, parameterPositions, sampleValues, sampleSize, resultBuffer );
 
 }
 
-QuaternionLinearInterpolant.prototype =
-		Object.assign( Object.create( Interpolant.prototype ), {
+QuaternionLinearInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype ), {
 
 	constructor: QuaternionLinearInterpolant,
 

+ 0 - 1
src/objects/LOD.js

@@ -22,7 +22,6 @@ function LOD() {
 
 }
 
-
 LOD.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 	constructor: LOD,

+ 0 - 1
src/objects/SkinnedMesh.js

@@ -71,7 +71,6 @@ function SkinnedMesh( geometry, material, useVertexTexture ) {
 
 }
 
-
 SkinnedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 	constructor: SkinnedMesh,

+ 1 - 0
src/renderers/WebGL2Renderer.js

@@ -182,4 +182,5 @@ function WebGL2Renderer( parameters ) {
 
 }
 
+
 export { WebGL2Renderer };

+ 2 - 5
src/renderers/WebGLRenderTarget.js

@@ -39,9 +39,7 @@ function WebGLRenderTarget( width, height, options ) {
 
 }
 
-WebGLRenderTarget.prototype = {
-
-	constructor: WebGLRenderTarget,
+Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype, {
 
 	isWebGLRenderTarget: true,
 
@@ -90,8 +88,7 @@ WebGLRenderTarget.prototype = {
 
 	}
 
-};
+} );
 
-Object.assign( WebGLRenderTarget.prototype, EventDispatcher.prototype );
 
 export { WebGLRenderTarget };

+ 1 - 0
src/renderers/WebGLRenderer.js

@@ -2884,4 +2884,5 @@ function WebGLRenderer( parameters ) {
 
 }
 
+
 export { WebGLRenderer };

+ 1 - 0
src/renderers/webgl/WebGLClipping.js

@@ -161,4 +161,5 @@ function WebGLClipping() {
 
 }
 
+
 export { WebGLClipping };

+ 1 - 0
src/renderers/webgl/WebGLProperties.js

@@ -40,4 +40,5 @@ function WebGLProperties() {
 
 }
 
+
 export { WebGLProperties };

+ 1 - 0
src/renderers/webgl/WebGLShader.js

@@ -42,4 +42,5 @@ function WebGLShader( gl, type, string ) {
 
 }
 
+
 export { WebGLShader };

+ 11 - 8
src/textures/Texture.js

@@ -59,17 +59,21 @@ function Texture( image, mapping, wrapS, wrapT, magFilter, minFilter, format, ty
 Texture.DEFAULT_IMAGE = undefined;
 Texture.DEFAULT_MAPPING = UVMapping;
 
-Texture.prototype = {
+Object.defineProperty( Texture.prototype, "needsUpdate", {
 
-	constructor: Texture,
+	set: function(value) { 
+		
+		if ( value === true ) this.version ++; 
+	
+	}
 
-	isTexture: true,
+});
 
-	set needsUpdate( value ) {
+Object.assign( Texture.prototype, EventDispatcher.prototype, {
 
-		if ( value === true ) this.version ++;
+	constructor: Texture,
 
-	},
+	isTexture: true,
 
 	clone: function () {
 
@@ -285,8 +289,7 @@ Texture.prototype = {
 
 	}
 
-};
+} );
 
-Object.assign( Texture.prototype, EventDispatcher.prototype );
 
 export { Texture };

+ 1 - 0
utils/exporters/blender/addons/io_three/constants.py

@@ -41,6 +41,7 @@ NUMERIC = {
     'SphericalReflectionMapping': 305,
 
     'RepeatWrapping': 1000,
+    'repeat': 1000,
     'ClampToEdgeWrapping': 1001,
     'MirroredRepeatWrapping': 1002,
 

+ 258 - 36
utils/exporters/blender/addons/io_three/exporter/api/mesh.py

@@ -12,6 +12,33 @@ from . import object as object_
 from .. import constants, utilities, logger, exceptions
 
 
+# flips vectors 
+
+#TODO: add these strings into constants.py
+
+XZ_Y = "XZ_Y"
+X_ZY = "X_ZY"
+XYZ = "XYZ"
+_XY_Z = "_XY_Z"
+
+
+def flip_axes (a, dir=XYZ):
+    """
+
+    :function to swap vectors:
+
+    """
+
+    if dir == XZ_Y:
+        a = (a[0], a[2], -a[1])
+    elif dir == X_ZY:
+        a = (a[0], -a[2], a[1])
+    elif dir == _XY_Z:
+        a = (-a[0], -a[1], a[2])
+
+    return (a[0], a[1], a[2])
+
+
 def _mesh(func):
     """
 
@@ -107,7 +134,7 @@ def bones(mesh, options):
 
 
 @_mesh
-def buffer_normal(mesh):
+def buffer_normal(mesh, options):
     """
 
     :param mesh:
@@ -122,16 +149,43 @@ def buffer_normal(mesh):
             msg = "Non-triangulated face detected"
             raise exceptions.BufferGeometryError(msg)
 
-        for vertex_index in face.vertices:
-            normal = mesh.vertices[vertex_index].normal
-            vector = (normal.x, normal.y, normal.z) if face.use_smooth else (face.normal.x, face.normal.y, face.normal.z)
-            normals_.extend(vector)
+        # using Object Loader with skinned mesh
+        if options.get(constants.SCENE, True) and _armature(mesh):
+        
+            for vertex_index in face.vertices:
+                normal = mesh.vertices[vertex_index].normal
+                vector = flip_axes(normal, XZ_Y) if face.use_smooth else flip_axes(face.normal, XZ_Y)
+                normals_.extend(vector)
+
+        # using Object Loader with static mesh
+        elif options.get(constants.SCENE, True) and not _armature(mesh):
+
+            for vertex_index in face.vertices:
+                normal = mesh.vertices[vertex_index].normal
+                vector = flip_axes(normal, _XY_Z) if face.use_smooth else flip_axes(face.normal, _XY_Z)
+                normals_.extend(vector)
+
+        # using JSON Loader with skinned mesh
+        elif not options.get(constants.SCENE, True) and _armature(mesh):
+
+            for vertex_index in face.vertices:
+                normal = mesh.vertices[vertex_index].normal
+                vector = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
+                normals_.extend(vector)
+
+        # using JSON Loader with static mesh
+        else:
+
+            for vertex_index in face.vertices:
+                normal = mesh.vertices[vertex_index].normal
+                vector = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
+                normals_.extend(vector)
 
     return normals_
 
 
 @_mesh
-def buffer_position(mesh):
+def buffer_position(mesh, options):
     """
 
     :param mesh:
@@ -146,10 +200,37 @@ def buffer_position(mesh):
             msg = "Non-triangulated face detected"
             raise exceptions.BufferGeometryError(msg)
 
-        for vertex_index in face.vertices:
-            vertex = mesh.vertices[vertex_index]
-            vector = (vertex.co.x, vertex.co.y, vertex.co.z)
-            position.extend(vector)
+        # using Object Loader with skinned mesh
+        if options.get(constants.SCENE, True) and _armature(mesh):
+
+            for vertex_index in face.vertices:
+                vertex = mesh.vertices[vertex_index]
+                vector = flip_axes(vertex.co, XZ_Y)
+                position.extend(vector)
+
+        # using Object Loader with static mesh
+        elif options.get(constants.SCENE, True) and not _armature(mesh):
+
+            for vertex_index in face.vertices:
+                vertex = mesh.vertices[vertex_index]
+                vector = flip_axes(vertex.co, _XY_Z)
+                position.extend(vector)
+
+        # using JSON Loader with skinned mesh
+        elif not options.get(constants.SCENE, True) and _armature(mesh):
+
+            for vertex_index in face.vertices:
+                vertex = mesh.vertices[vertex_index]
+                vector = flip_axes(vertex.co)
+                position.extend(vector)
+
+        # using JSON Loader with static mesh
+        else:
+
+            for vertex_index in face.vertices:
+                vertex = mesh.vertices[vertex_index]
+                vector = flip_axes(vertex.co)
+                position.extend(vector)
 
     return position
 
@@ -293,7 +374,7 @@ def faces(mesh, options, material_list=None):
     logger.debug("Normals enabled = %s", opt_normals)
 
     uv_indices = _uvs(mesh)[1] if opt_uvs else None
-    vertex_normals = _normals(mesh) if opt_normals else None
+    vertex_normals = _normals(mesh, options) if opt_normals else None
     vertex_colours = vertex_colors(mesh) if opt_colours else None
 
     faces_data = []
@@ -305,11 +386,37 @@ def faces(mesh, options, material_list=None):
             colour_indices[str(colour)] = index
 
     normal_indices = {}
+
     if vertex_normals:
         logger.debug("Indexing normals")
-        for index, normal in enumerate(vertex_normals):
-            normal = (normal[0], normal[2], -normal[1])
-            normal_indices[str(normal)] = index
+
+        # using Object Loader with skinned mesh
+        if options.get(constants.SCENE, True) and _armature(mesh):
+
+            for index, normal in enumerate(vertex_normals):
+                normal = flip_axes(normal, XYZ)
+                normal_indices[str(normal)] = index
+
+        # using Object Loader with static mesh
+        elif options.get(constants.SCENE, True) and not _armature(mesh):
+
+            for index, normal in enumerate(vertex_normals):
+                normal = flip_axes(normal, XYZ)
+                normal_indices[str(normal)] = index
+
+        # using JSON Loader with skinned mesh
+        elif not options.get(constants.SCENE, True) and _armature(mesh):
+
+            for index, normal in enumerate(vertex_normals):
+                normal = flip_axes(normal)
+                normal_indices[str(normal)] = index
+
+        # using JSON Loader with static mesh
+        else:
+
+            for index, normal in enumerate(vertex_normals):
+                normal = flip_axes(normal)
+                normal_indices[str(normal)] = index
 
     logger.info("Parsing %d faces", len(mesh.tessfaces))
     for face in mesh.tessfaces:
@@ -355,11 +462,43 @@ def faces(mesh, options, material_list=None):
                     mask[constants.UVS] = True
 
         if vertex_normals:
-            for vertex in face.vertices:
-                normal = mesh.vertices[vertex].normal
-                normal = (normal.x, normal.z, -normal.y) if face.use_smooth else (face.normal.x, face.normal.z, -face.normal.y)
-                face_data.append(normal_indices[str(normal)])
-                mask[constants.NORMALS] = True
+
+            # using Object Loader with skinned mesh
+            if options.get(constants.SCENE, True) and _armature(mesh):
+
+                for vertex in face.vertices:
+                    normal = mesh.vertices[vertex].normal
+                    normal = flip_axes(normal, XZ_Y) if face.use_smooth else flip_axes(face.normal, XZ_Y)
+                    face_data.append(normal_indices[str(normal)])
+                    mask[constants.NORMALS] = True
+
+            # using Object Loader with static mesh
+            elif options.get(constants.SCENE, True) and not _armature(mesh):
+
+                for vertex in face.vertices:
+                    normal = mesh.vertices[vertex].normal
+                    normal = flip_axes(normal, _XY_Z) if face.use_smooth else flip_axes(face.normal, _XY_Z)
+                    face_data.append(normal_indices[str(normal)])
+                    mask[constants.NORMALS] = True
+
+            # using JSON Loader with skinned mesh
+            elif not options.get(constants.SCENE, True) and _armature(mesh):
+
+                for vertex in face.vertices:
+                    normal = mesh.vertices[vertex].normal
+                    normal = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
+                    face_data.append(normal_indices[str(normal)])
+                    mask[constants.NORMALS] = True
+
+            # using JSON Loader with static mesh
+            else:
+
+                for vertex in face.vertices:
+                    normal = mesh.vertices[vertex].normal
+                    normal = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
+                    face_data.append(normal_indices[str(normal)])
+                    mask[constants.NORMALS] = True
+            
 
         if vertex_colours:
             colours = mesh.tessface_vertex_colors.active.data[face.index]
@@ -403,8 +542,29 @@ def morph_targets(mesh, options):
         morphs.append([])
         vertices_ = object_.extract_mesh(obj, options).vertices[:]
 
-        for vertex in vertices_:
-            morphs[-1].extend([vertex.co.x, vertex.co.y, vertex.co.z])
+        # using Object Loader with skinned mesh
+        if options.get(constants.SCENE, True) and _armature(mesh):
+
+            for vertex in vertices_:
+                morphs[-1].extend(flip_axes(vertex.co, XZ_Y))
+
+        # using Object Loader with static mesh
+        elif options.get(constants.SCENE, True) and not _armature(mesh):
+
+            for vertex in vertices_:
+                morphs[-1].extend(flip_axes(vertex.co, _XY_Z))
+
+        # using JSON Loader with skinned mesh
+        elif not options.get(constants.SCENE, True) and _armature(mesh):
+
+            for vertex in vertices_:
+                morphs[-1].extend(flip_axes(vertex.co))
+
+        # using JSON Loader with static mesh
+        else:
+
+            for vertex in vertices_:
+                morphs[-1].extend(flip_axes(vertex.co))
 
     context.scene.frame_set(original_frame, 0.0)
     morphs_detected = False
@@ -605,7 +765,7 @@ def materials(mesh, options):
 
 
 @_mesh
-def normals(mesh):
+def normals(mesh, options):
     """
 
     :param mesh:
@@ -615,7 +775,7 @@ def normals(mesh):
     logger.debug("mesh.normals(%s)", mesh)
     normal_vectors = []
 
-    for vector in _normals(mesh):
+    for vector in _normals(mesh, options):
         normal_vectors.extend(vector)
 
     return normal_vectors
@@ -752,7 +912,7 @@ def vertex_colors(mesh):
 
 
 @_mesh
-def vertices(mesh):
+def vertices(mesh, options):
     """
 
     :param mesh:
@@ -762,8 +922,29 @@ def vertices(mesh):
     logger.debug("mesh.vertices(%s)", mesh)
     vertices_ = []
 
-    for vertex in mesh.vertices:
-        vertices_.extend((vertex.co.x, vertex.co.y, vertex.co.z))
+    # using Object Loader with skinned mesh
+    if options.get(constants.SCENE, True) and _armature(mesh):
+
+        for vertex in mesh.vertices:
+            vertices_.extend(flip_axes(vertex.co, XZ_Y))
+
+    # using Object Loader with static mesh
+    elif options.get(constants.SCENE, True) and not _armature(mesh):
+
+        for vertex in mesh.vertices:
+            vertices_.extend(flip_axes(vertex.co, _XY_Z))
+
+    # using JSON Loader with skinned mesh
+    elif not options.get(constants.SCENE, True) and _armature(mesh):
+
+        for vertex in mesh.vertices:
+            vertices_.extend(flip_axes(vertex.co))
+
+    # using JSON Loader with static mesh
+    else:
+
+        for vertex in mesh.vertices:
+            vertices_.extend(flip_axes(vertex.co))
 
     return vertices_
 
@@ -892,7 +1073,7 @@ def _diffuse_map(mat):
     return diffuse
 
 
-def _normals(mesh):
+def _normals(mesh, options):
     """
 
     :param mesh:
@@ -904,16 +1085,57 @@ def _normals(mesh):
     vectors_ = {}
     for face in mesh.tessfaces:
 
-        for vertex_index in face.vertices:
-            normal = mesh.vertices[vertex_index].normal
-            vector = (normal.x, normal.y, normal.z) if face.use_smooth else (face.normal.x, face.normal.y, face.normal.z)
+        if options.get(constants.SCENE, True) and _armature(mesh):
+
+            for vertex_index in face.vertices:
+                normal = mesh.vertices[vertex_index].normal
+                vector = flip_axes(normal, XZ_Y) if face.use_smooth else flip_axes(face.normal, XZ_Y)
+
+                str_vec = str(vector)
+                try:
+                    vectors_[str_vec]
+                except KeyError:
+                    vectors.append(vector)
+                    vectors_[str_vec] = True
+                    
+        elif options.get(constants.SCENE, True) and not _armature(mesh):
+
+            for vertex_index in face.vertices:
+                normal = mesh.vertices[vertex_index].normal
+                vector = flip_axes(normal,_XY_Z) if face.use_smooth else flip_axes(face.normal,_XY_Z)
+
+                str_vec = str(vector)
+                try:
+                    vectors_[str_vec]
+                except KeyError:
+                    vectors.append(vector)
+                    vectors_[str_vec] = True
+
+        elif not options.get(constants.SCENE, True) and _armature(mesh):
+
+            for vertex_index in face.vertices:
+                normal = mesh.vertices[vertex_index].normal
+                vector = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
+
+                str_vec = str(vector)
+                try:
+                    vectors_[str_vec]
+                except KeyError:
+                    vectors.append(vector)
+                    vectors_[str_vec] = True
 
-            str_vec = str(vector)
-            try:
-                vectors_[str_vec]
-            except KeyError:
-                vectors.append(vector)
-                vectors_[str_vec] = True
+        else:
+
+            for vertex_index in face.vertices:
+                normal = mesh.vertices[vertex_index].normal
+                vector = flip_axes(normal) if face.use_smooth else flip_axes(face.normal)
+
+                str_vec = str(vector)
+                try:
+                    vectors_[str_vec]
+                except KeyError:
+                    vectors.append(vector)
+                    vectors_[str_vec] = True
 
     return vectors
 

+ 4 - 4
utils/exporters/blender/addons/io_three/exporter/geometry.py

@@ -373,13 +373,13 @@ class Geometry(base_classes.BaseNode):
         option_index_type = self.options.get(constants.INDEX_TYPE)
 
         pos_tuple = (constants.POSITION, options_vertices,
-                     api.mesh.buffer_position, 3)
+                     lambda m: api.mesh.buffer_position(m, self.options), 3)
         uvs_tuple = (constants.UV, option_uvs,
                      api.mesh.buffer_uv, 2)
         uvs2_tuple = (constants.UV2, option_uvs,
                      lambda m: api.mesh.buffer_uv(m, layer=1), 2)
         normals_tuple = (constants.NORMAL, option_normals,
-                         api.mesh.buffer_normal, 3)
+                         lambda m: api.mesh.buffer_normal(m, self.options), 3)
         dispatch = (pos_tuple, uvs_tuple, uvs2_tuple, normals_tuple)
 
         for key, option, func, size in dispatch:
@@ -500,11 +500,11 @@ class Geometry(base_classes.BaseNode):
         """Parse the geometry to Three.Geometry specs"""
         if self.options.get(constants.VERTICES):
             logger.info("Parsing %s", constants.VERTICES)
-            self[constants.VERTICES] = api.mesh.vertices(self.node) or []
+            self[constants.VERTICES] = api.mesh.vertices(self.node, self.options) or []
 
         if self.options.get(constants.NORMALS):
             logger.info("Parsing %s", constants.NORMALS)
-            self[constants.NORMALS] = api.mesh.normals(self.node) or []
+            self[constants.NORMALS] = api.mesh.normals(self.node, self.options) or []
 
         if self.options.get(constants.COLORS):
             logger.info("Parsing %s", constants.COLORS)

Some files were not shown because too many files changed in this diff