Browse Source

Examples: Convert utils to ES6. (#21611)

Michael Herzog 4 years ago
parent
commit
ac847a8d38

+ 172 - 163
examples/js/utils/BufferGeometryUtils.js

@@ -1,33 +1,35 @@
 ( function () {
 
-	var BufferGeometryUtils = {
-		computeTangents: function ( geometry ) {
+	class BufferGeometryUtils {
+
+		static computeTangents( geometry ) {
 
 			geometry.computeTangents();
 			console.warn( 'THREE.BufferGeometryUtils: .computeTangents() has been removed. Use THREE.BufferGeometry.computeTangents() instead.' );
 
-		},
-
+		}
 		/**
 	 * @param	{Array<BufferGeometry>} geometries
 	 * @param	{Boolean} useGroups
 	 * @return {BufferGeometry}
 	 */
-		mergeBufferGeometries: function ( geometries, useGroups ) {
 
-			var isIndexed = geometries[ 0 ].index !== null;
-			var attributesUsed = new Set( Object.keys( geometries[ 0 ].attributes ) );
-			var morphAttributesUsed = new Set( Object.keys( geometries[ 0 ].morphAttributes ) );
-			var attributes = {};
-			var morphAttributes = {};
-			var morphTargetsRelative = geometries[ 0 ].morphTargetsRelative;
-			var mergedGeometry = new THREE.BufferGeometry();
-			var offset = 0;
 
-			for ( var i = 0; i < geometries.length; ++ i ) {
+		static mergeBufferGeometries( geometries, useGroups = false ) {
+
+			const isIndexed = geometries[ 0 ].index !== null;
+			const attributesUsed = new Set( Object.keys( geometries[ 0 ].attributes ) );
+			const morphAttributesUsed = new Set( Object.keys( geometries[ 0 ].morphAttributes ) );
+			const attributes = {};
+			const morphAttributes = {};
+			const morphTargetsRelative = geometries[ 0 ].morphTargetsRelative;
+			const mergedGeometry = new THREE.BufferGeometry();
+			let offset = 0;
 
-				var geometry = geometries[ i ];
-				var attributesCount = 0; // ensure that all geometries are indexed, or none
+			for ( let i = 0; i < geometries.length; ++ i ) {
+
+				const geometry = geometries[ i ];
+				let attributesCount = 0; // ensure that all geometries are indexed, or none
 
 				if ( isIndexed !== ( geometry.index !== null ) ) {
 
@@ -37,7 +39,7 @@
 				} // gather attributes, exit early if they're different
 
 
-				for ( var name in geometry.attributes ) {
+				for ( const name in geometry.attributes ) {
 
 					if ( ! attributesUsed.has( name ) ) {
 
@@ -68,7 +70,7 @@
 
 				}
 
-				for ( var name in geometry.morphAttributes ) {
+				for ( const name in geometry.morphAttributes ) {
 
 					if ( ! morphAttributesUsed.has( name ) ) {
 
@@ -88,7 +90,7 @@
 
 				if ( useGroups ) {
 
-					var count;
+					let count;
 
 					if ( isIndexed ) {
 
@@ -115,14 +117,14 @@
 
 			if ( isIndexed ) {
 
-				var indexOffset = 0;
-				var mergedIndex = [];
+				let indexOffset = 0;
+				const mergedIndex = [];
 
-				for ( var i = 0; i < geometries.length; ++ i ) {
+				for ( let i = 0; i < geometries.length; ++ i ) {
 
-					var index = geometries[ i ].index;
+					const index = geometries[ i ].index;
 
-					for ( var j = 0; j < index.count; ++ j ) {
+					for ( let j = 0; j < index.count; ++ j ) {
 
 						mergedIndex.push( index.getX( j ) + indexOffset );
 
@@ -137,9 +139,9 @@
 			} // merge attributes
 
 
-			for ( var name in attributes ) {
+			for ( const name in attributes ) {
 
-				var mergedAttribute = this.mergeBufferAttributes( attributes[ name ] );
+				const mergedAttribute = this.mergeBufferAttributes( attributes[ name ] );
 
 				if ( ! mergedAttribute ) {
 
@@ -153,24 +155,24 @@
 			} // merge morph attributes
 
 
-			for ( var name in morphAttributes ) {
+			for ( const name in morphAttributes ) {
 
-				var numMorphTargets = morphAttributes[ name ][ 0 ].length;
+				const numMorphTargets = morphAttributes[ name ][ 0 ].length;
 				if ( numMorphTargets === 0 ) break;
 				mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
 				mergedGeometry.morphAttributes[ name ] = [];
 
-				for ( var i = 0; i < numMorphTargets; ++ i ) {
+				for ( let i = 0; i < numMorphTargets; ++ i ) {
 
-					var morphAttributesToMerge = [];
+					const morphAttributesToMerge = [];
 
-					for ( var j = 0; j < morphAttributes[ name ].length; ++ j ) {
+					for ( let j = 0; j < morphAttributes[ name ].length; ++ j ) {
 
 						morphAttributesToMerge.push( morphAttributes[ name ][ j ][ i ] );
 
 					}
 
-					var mergedMorphAttribute = this.mergeBufferAttributes( morphAttributesToMerge );
+					const mergedMorphAttribute = this.mergeBufferAttributes( morphAttributesToMerge );
 
 					if ( ! mergedMorphAttribute ) {
 
@@ -187,22 +189,23 @@
 
 			return mergedGeometry;
 
-		},
-
+		}
 		/**
 	 * @param {Array<BufferAttribute>} attributes
 	 * @return {BufferAttribute}
 	 */
-		mergeBufferAttributes: function ( attributes ) {
 
-			var TypedArray;
-			var itemSize;
-			var normalized;
-			var arrayLength = 0;
 
-			for ( var i = 0; i < attributes.length; ++ i ) {
+		static mergeBufferAttributes( attributes ) {
+
+			let TypedArray;
+			let itemSize;
+			let normalized;
+			let arrayLength = 0;
 
-				var attribute = attributes[ i ];
+			for ( let i = 0; i < attributes.length; ++ i ) {
+
+				const attribute = attributes[ i ];
 
 				if ( attribute.isInterleavedBufferAttribute ) {
 
@@ -242,10 +245,10 @@
 
 			}
 
-			var array = new TypedArray( arrayLength );
-			var offset = 0;
+			const array = new TypedArray( arrayLength );
+			let offset = 0;
 
-			for ( var i = 0; i < attributes.length; ++ i ) {
+			for ( let i = 0; i < attributes.length; ++ i ) {
 
 				array.set( attributes[ i ].array, offset );
 				offset += attributes[ i ].array.length;
@@ -254,23 +257,24 @@
 
 			return new THREE.BufferAttribute( array, itemSize, normalized );
 
-		},
-
+		}
 		/**
 	 * @param {Array<BufferAttribute>} attributes
 	 * @return {Array<InterleavedBufferAttribute>}
 	 */
-		interleaveAttributes: function ( attributes ) {
+
+
+		static interleaveAttributes( attributes ) {
 
 			// Interleaves the provided attributes into an THREE.InterleavedBuffer and returns
 			// a set of InterleavedBufferAttributes for each attribute
-			var TypedArray;
-			var arrayLength = 0;
-			var stride = 0; // calculate the the length and type of the interleavedBuffer
+			let TypedArray;
+			let arrayLength = 0;
+			let stride = 0; // calculate the the length and type of the interleavedBuffer
 
-			for ( var i = 0, l = attributes.length; i < l; ++ i ) {
+			for ( let i = 0, l = attributes.length; i < l; ++ i ) {
 
-				var attribute = attributes[ i ];
+				const attribute = attributes[ i ];
 				if ( TypedArray === undefined ) TypedArray = attribute.array.constructor;
 
 				if ( TypedArray !== attribute.array.constructor ) {
@@ -286,25 +290,25 @@
 			} // Create the set of buffer attributes
 
 
-			var interleavedBuffer = new THREE.InterleavedBuffer( new TypedArray( arrayLength ), stride );
-			var offset = 0;
-			var res = [];
-			var getters = [ 'getX', 'getY', 'getZ', 'getW' ];
-			var setters = [ 'setX', 'setY', 'setZ', 'setW' ];
+			const interleavedBuffer = new THREE.InterleavedBuffer( new TypedArray( arrayLength ), stride );
+			let offset = 0;
+			const res = [];
+			const getters = [ 'getX', 'getY', 'getZ', 'getW' ];
+			const setters = [ 'setX', 'setY', 'setZ', 'setW' ];
 
-			for ( var j = 0, l = attributes.length; j < l; j ++ ) {
+			for ( let j = 0, l = attributes.length; j < l; j ++ ) {
 
-				var attribute = attributes[ j ];
-				var itemSize = attribute.itemSize;
-				var count = attribute.count;
-				var iba = new THREE.InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, attribute.normalized );
+				const attribute = attributes[ j ];
+				const itemSize = attribute.itemSize;
+				const count = attribute.count;
+				const iba = new THREE.InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, attribute.normalized );
 				res.push( iba );
 				offset += itemSize; // Move the data for each attribute into the new interleavedBuffer
 				// at the appropriate offset
 
-				for ( var c = 0; c < count; c ++ ) {
+				for ( let c = 0; c < count; c ++ ) {
 
-					for ( var k = 0; k < itemSize; k ++ ) {
+					for ( let k = 0; k < itemSize; k ++ ) {
 
 						iba[ setters[ k ] ]( c, attribute[ getters[ k ] ]( c ) );
 
@@ -316,60 +320,62 @@
 
 			return res;
 
-		},
-
+		}
 		/**
 	 * @param {Array<BufferGeometry>} geometry
 	 * @return {number}
 	 */
-		estimateBytesUsed: function ( geometry ) {
+
+
+		static estimateBytesUsed( geometry ) {
 
 			// Return the estimated memory used by this geometry in bytes
 			// Calculate using itemSize, count, and BYTES_PER_ELEMENT to account
 			// for InterleavedBufferAttributes.
-			var mem = 0;
+			let mem = 0;
 
-			for ( var name in geometry.attributes ) {
+			for ( const name in geometry.attributes ) {
 
-				var attr = geometry.getAttribute( name );
+				const attr = geometry.getAttribute( name );
 				mem += attr.count * attr.itemSize * attr.array.BYTES_PER_ELEMENT;
 
 			}
 
-			var indices = geometry.getIndex();
+			const indices = geometry.getIndex();
 			mem += indices ? indices.count * indices.itemSize * indices.array.BYTES_PER_ELEMENT : 0;
 			return mem;
 
-		},
-
+		}
 		/**
 	 * @param {BufferGeometry} geometry
 	 * @param {number} tolerance
 	 * @return {BufferGeometry>}
 	 */
-		mergeVertices: function ( geometry, tolerance = 1e-4 ) {
+
+
+		static mergeVertices( geometry, tolerance = 1e-4 ) {
 
 			tolerance = Math.max( tolerance, Number.EPSILON ); // Generate an index buffer if the geometry doesn't have one, or optimize it
 			// if it's already available.
 
-			var hashToIndex = {};
-			var indices = geometry.getIndex();
-			var positions = geometry.getAttribute( 'position' );
-			var vertexCount = indices ? indices.count : positions.count; // next value for triangle indices
+			const hashToIndex = {};
+			const indices = geometry.getIndex();
+			const positions = geometry.getAttribute( 'position' );
+			const vertexCount = indices ? indices.count : positions.count; // next value for triangle indices
 
-			var nextIndex = 0; // attributes and new attribute arrays
+			let nextIndex = 0; // attributes and new attribute arrays
 
-			var attributeNames = Object.keys( geometry.attributes );
-			var attrArrays = {};
-			var morphAttrsArrays = {};
-			var newIndices = [];
-			var getters = [ 'getX', 'getY', 'getZ', 'getW' ]; // initialize the arrays
+			const attributeNames = Object.keys( geometry.attributes );
+			const attrArrays = {};
+			const morphAttrsArrays = {};
+			const newIndices = [];
+			const getters = [ 'getX', 'getY', 'getZ', 'getW' ]; // initialize the arrays
 
-			for ( var i = 0, l = attributeNames.length; i < l; i ++ ) {
+			for ( let i = 0, l = attributeNames.length; i < l; i ++ ) {
 
-				var name = attributeNames[ i ];
+				const name = attributeNames[ i ];
 				attrArrays[ name ] = [];
-				var morphAttr = geometry.morphAttributes[ name ];
+				const morphAttr = geometry.morphAttributes[ name ];
 
 				if ( morphAttr ) {
 
@@ -380,22 +386,22 @@
 			} // convert the error tolerance to an amount of decimal places to truncate to
 
 
-			var decimalShift = Math.log10( 1 / tolerance );
-			var shiftMultiplier = Math.pow( 10, decimalShift );
+			const decimalShift = Math.log10( 1 / tolerance );
+			const shiftMultiplier = Math.pow( 10, decimalShift );
 
-			for ( var i = 0; i < vertexCount; i ++ ) {
+			for ( let i = 0; i < vertexCount; i ++ ) {
 
-				var index = indices ? indices.getX( i ) : i; // Generate a hash for the vertex attributes at the current index 'i'
+				const index = indices ? indices.getX( i ) : i; // Generate a hash for the vertex attributes at the current index 'i'
 
-				var hash = '';
+				let hash = '';
 
-				for ( var j = 0, l = attributeNames.length; j < l; j ++ ) {
+				for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
 
-					var name = attributeNames[ j ];
-					var attribute = geometry.getAttribute( name );
-					var itemSize = attribute.itemSize;
+					const name = attributeNames[ j ];
+					const attribute = geometry.getAttribute( name );
+					const itemSize = attribute.itemSize;
 
-					for ( var k = 0; k < itemSize; k ++ ) {
+					for ( let k = 0; k < itemSize; k ++ ) {
 
 						// double tilde truncates the decimal value
 						hash += `${~ ~ ( attribute[ getters[ k ] ]( index ) * shiftMultiplier )},`;
@@ -413,23 +419,23 @@
 				} else {
 
 					// copy data to the new index in the attribute arrays
-					for ( var j = 0, l = attributeNames.length; j < l; j ++ ) {
+					for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
 
-						var name = attributeNames[ j ];
-						var attribute = geometry.getAttribute( name );
-						var morphAttr = geometry.morphAttributes[ name ];
-						var itemSize = attribute.itemSize;
-						var newarray = attrArrays[ name ];
-						var newMorphArrays = morphAttrsArrays[ name ];
+						const name = attributeNames[ j ];
+						const attribute = geometry.getAttribute( name );
+						const morphAttr = geometry.morphAttributes[ name ];
+						const itemSize = attribute.itemSize;
+						const newarray = attrArrays[ name ];
+						const newMorphArrays = morphAttrsArrays[ name ];
 
-						for ( var k = 0; k < itemSize; k ++ ) {
+						for ( let k = 0; k < itemSize; k ++ ) {
 
-							var getterFunc = getters[ k ];
+							const getterFunc = getters[ k ];
 							newarray.push( attribute[ getterFunc ]( index ) );
 
 							if ( morphAttr ) {
 
-								for ( var m = 0, ml = morphAttr.length; m < ml; m ++ ) {
+								for ( let m = 0, ml = morphAttr.length; m < ml; m ++ ) {
 
 									newMorphArrays[ m ].push( morphAttr[ m ][ getterFunc ]( index ) );
 
@@ -453,21 +459,21 @@
 
 			const result = geometry.clone();
 
-			for ( var i = 0, l = attributeNames.length; i < l; i ++ ) {
+			for ( let i = 0, l = attributeNames.length; i < l; i ++ ) {
 
-				var name = attributeNames[ i ];
-				var oldAttribute = geometry.getAttribute( name );
-				var buffer = new oldAttribute.array.constructor( attrArrays[ name ] );
-				var attribute = new THREE.BufferAttribute( buffer, oldAttribute.itemSize, oldAttribute.normalized );
+				const name = attributeNames[ i ];
+				const oldAttribute = geometry.getAttribute( name );
+				const buffer = new oldAttribute.array.constructor( attrArrays[ name ] );
+				const attribute = new THREE.BufferAttribute( buffer, oldAttribute.itemSize, oldAttribute.normalized );
 				result.setAttribute( name, attribute ); // Update the attribute arrays
 
 				if ( name in morphAttrsArrays ) {
 
-					for ( var j = 0; j < morphAttrsArrays[ name ].length; j ++ ) {
+					for ( let j = 0; j < morphAttrsArrays[ name ].length; j ++ ) {
 
-						var oldMorphAttribute = geometry.morphAttributes[ name ][ j ];
-						var buffer = new oldMorphAttribute.array.constructor( morphAttrsArrays[ name ][ j ] );
-						var morphAttribute = new THREE.BufferAttribute( buffer, oldMorphAttribute.itemSize, oldMorphAttribute.normalized );
+						const oldMorphAttribute = geometry.morphAttributes[ name ][ j ];
+						const buffer = new oldMorphAttribute.array.constructor( morphAttrsArrays[ name ][ j ] );
+						const morphAttribute = new THREE.BufferAttribute( buffer, oldMorphAttribute.itemSize, oldMorphAttribute.normalized );
 						result.morphAttributes[ name ][ j ] = morphAttribute;
 
 					}
@@ -480,14 +486,15 @@
 			result.setIndex( newIndices );
 			return result;
 
-		},
-
+		}
 		/**
 	 * @param {BufferGeometry} geometry
 	 * @param {number} drawMode
 	 * @return {BufferGeometry>}
 	 */
-		toTrianglesDrawMode: function ( geometry, drawMode ) {
+
+
+		static toTrianglesDrawMode( geometry, drawMode ) {
 
 			if ( drawMode === THREE.TrianglesDrawMode ) {
 
@@ -498,16 +505,16 @@
 
 			if ( drawMode === THREE.TriangleFanDrawMode || drawMode === THREE.TriangleStripDrawMode ) {
 
-				var index = geometry.getIndex(); // generate index if not present
+				let index = geometry.getIndex(); // generate index if not present
 
 				if ( index === null ) {
 
-					var indices = [];
-					var position = geometry.getAttribute( 'position' );
+					const indices = [];
+					const position = geometry.getAttribute( 'position' );
 
 					if ( position !== undefined ) {
 
-						for ( var i = 0; i < position.count; i ++ ) {
+						for ( let i = 0; i < position.count; i ++ ) {
 
 							indices.push( i );
 
@@ -526,13 +533,13 @@
 				} //
 
 
-				var numberOfTriangles = index.count - 2;
-				var newIndices = [];
+				const numberOfTriangles = index.count - 2;
+				const newIndices = [];
 
 				if ( drawMode === THREE.TriangleFanDrawMode ) {
 
 					// gl.TRIANGLE_FAN
-					for ( var i = 1; i <= numberOfTriangles; i ++ ) {
+					for ( let i = 1; i <= numberOfTriangles; i ++ ) {
 
 						newIndices.push( index.getX( 0 ) );
 						newIndices.push( index.getX( i ) );
@@ -543,7 +550,7 @@
 				} else {
 
 					// gl.TRIANGLE_STRIP
-					for ( var i = 0; i < numberOfTriangles; i ++ ) {
+					for ( let i = 0; i < numberOfTriangles; i ++ ) {
 
 						if ( i % 2 === 0 ) {
 
@@ -570,7 +577,7 @@
 				} // build final geometry
 
 
-				var newGeometry = geometry.clone();
+				const newGeometry = geometry.clone();
 				newGeometry.setIndex( newIndices );
 				newGeometry.clearGroups();
 				return newGeometry;
@@ -582,15 +589,16 @@
 
 			}
 
-		},
-
+		}
 		/**
 	 * Calculates the morphed attributes of a morphed/skinned THREE.BufferGeometry.
 	 * Helpful for Raytracing or Decals.
 	 * @param {Mesh | Line | Points} object An instance of Mesh, Line or Points.
 	 * @return {Object} An Object with original position/normal attributes and morphed ones.
 	 */
-		computeMorphedAttributes: function ( object ) {
+
+
+		static computeMorphedAttributes( object ) {
 
 			if ( object.geometry.isBufferGeometry !== true ) {
 
@@ -599,23 +607,23 @@
 
 			}
 
-			var _vA = new THREE.Vector3();
+			const _vA = new THREE.Vector3();
 
-			var _vB = new THREE.Vector3();
+			const _vB = new THREE.Vector3();
 
-			var _vC = new THREE.Vector3();
+			const _vC = new THREE.Vector3();
 
-			var _tempA = new THREE.Vector3();
+			const _tempA = new THREE.Vector3();
 
-			var _tempB = new THREE.Vector3();
+			const _tempB = new THREE.Vector3();
 
-			var _tempC = new THREE.Vector3();
+			const _tempC = new THREE.Vector3();
 
-			var _morphA = new THREE.Vector3();
+			const _morphA = new THREE.Vector3();
 
-			var _morphB = new THREE.Vector3();
+			const _morphB = new THREE.Vector3();
 
-			var _morphC = new THREE.Vector3();
+			const _morphC = new THREE.Vector3();
 
 			function _calculateMorphedAttributeData( object, material, attribute, morphAttribute, morphTargetsRelative, a, b, c, modifiedAttributeArray ) {
 
@@ -625,7 +633,7 @@
 
 				_vC.fromBufferAttribute( attribute, c );
 
-				var morphInfluences = object.morphTargetInfluences;
+				const morphInfluences = object.morphTargetInfluences;
 
 				if ( material.morphTargets && morphAttribute && morphInfluences ) {
 
@@ -635,10 +643,10 @@
 
 					_morphC.set( 0, 0, 0 );
 
-					for ( var i = 0, il = morphAttribute.length; i < il; i ++ ) {
+					for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
 
-						var influence = morphInfluences[ i ];
-						var morph = morphAttribute[ i ];
+						const influence = morphInfluences[ i ];
+						const morph = morphAttribute[ i ];
 						if ( influence === 0 ) continue;
 
 						_tempA.fromBufferAttribute( morph, a );
@@ -695,22 +703,22 @@
 
 			}
 
-			var geometry = object.geometry;
-			var material = object.material;
-			var a, b, c;
-			var index = geometry.index;
-			var positionAttribute = geometry.attributes.position;
-			var morphPosition = geometry.morphAttributes.position;
-			var morphTargetsRelative = geometry.morphTargetsRelative;
-			var normalAttribute = geometry.attributes.normal;
-			var morphNormal = geometry.morphAttributes.position;
-			var groups = geometry.groups;
-			var drawRange = geometry.drawRange;
-			var i, j, il, jl;
-			var group, groupMaterial;
-			var start, end;
-			var modifiedPosition = new Float32Array( positionAttribute.count * positionAttribute.itemSize );
-			var modifiedNormal = new Float32Array( normalAttribute.count * normalAttribute.itemSize );
+			const geometry = object.geometry;
+			const material = object.material;
+			let a, b, c;
+			const index = geometry.index;
+			const positionAttribute = geometry.attributes.position;
+			const morphPosition = geometry.morphAttributes.position;
+			const morphTargetsRelative = geometry.morphTargetsRelative;
+			const normalAttribute = geometry.attributes.normal;
+			const morphNormal = geometry.morphAttributes.position;
+			const groups = geometry.groups;
+			const drawRange = geometry.drawRange;
+			let i, j, il, jl;
+			let group, groupMaterial;
+			let start, end;
+			const modifiedPosition = new Float32Array( positionAttribute.count * positionAttribute.itemSize );
+			const modifiedNormal = new Float32Array( normalAttribute.count * normalAttribute.itemSize );
 
 			if ( index !== null ) {
 
@@ -804,8 +812,8 @@
 
 			}
 
-			var morphedPositionAttribute = new THREE.Float32BufferAttribute( modifiedPosition, 3 );
-			var morphedNormalAttribute = new THREE.Float32BufferAttribute( modifiedNormal, 3 );
+			const morphedPositionAttribute = new THREE.Float32BufferAttribute( modifiedPosition, 3 );
+			const morphedNormalAttribute = new THREE.Float32BufferAttribute( modifiedNormal, 3 );
 			return {
 				positionAttribute: positionAttribute,
 				normalAttribute: normalAttribute,
@@ -814,7 +822,8 @@
 			};
 
 		}
-	};
+
+	}
 
 	THREE.BufferGeometryUtils = BufferGeometryUtils;
 

+ 207 - 193
examples/js/utils/GeometryCompressionUtils.js

@@ -6,8 +6,10 @@
  * @link https://github.com/tsherif/mesh-quantization-example
  *
  */
-	var GeometryCompressionUtils = {
-	/**
+
+	class GeometryCompressionUtils {
+
+		/**
 		 * Make the input mesh.geometry's normal attribute encoded and compressed by 3 different methods.
 		 * Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the normal data.
 		 *
@@ -15,7 +17,7 @@
 		 * @param {String} encodeMethod		"DEFAULT" || "OCT1Byte" || "OCT2Byte" || "ANGLES"
 		 *
 		 */
-		compressNormals: function ( mesh, encodeMethod ) {
+		static compressNormals( mesh, encodeMethod ) {
 
 			if ( ! mesh.geometry ) {
 
@@ -50,7 +52,7 @@
 
 				for ( let idx = 0; idx < array.length; idx += 3 ) {
 
-					const encoded = this.EncodingFuncs.defaultEncode( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 1 );
+					const encoded = EncodingFuncs.defaultEncode( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 1 );
 					result[ idx + 0 ] = encoded[ 0 ];
 					result[ idx + 1 ] = encoded[ 1 ];
 					result[ idx + 2 ] = encoded[ 2 ];
@@ -71,7 +73,7 @@
 
 				for ( let idx = 0; idx < array.length; idx += 3 ) {
 
-					const encoded = this.EncodingFuncs.octEncodeBest( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 1 );
+					const encoded = EncodingFuncs.octEncodeBest( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 1 );
 					result[ idx / 3 * 2 + 0 ] = encoded[ 0 ];
 					result[ idx / 3 * 2 + 1 ] = encoded[ 1 ];
 
@@ -86,7 +88,7 @@
 
 				for ( let idx = 0; idx < array.length; idx += 3 ) {
 
-					const encoded = this.EncodingFuncs.octEncodeBest( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 2 );
+					const encoded = EncodingFuncs.octEncodeBest( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 2 );
 					result[ idx / 3 * 2 + 0 ] = encoded[ 0 ];
 					result[ idx / 3 * 2 + 1 ] = encoded[ 1 ];
 
@@ -101,7 +103,7 @@
 
 				for ( let idx = 0; idx < array.length; idx += 3 ) {
 
-					const encoded = this.EncodingFuncs.anglesEncode( array[ idx ], array[ idx + 1 ], array[ idx + 2 ] );
+					const encoded = EncodingFuncs.anglesEncode( array[ idx ], array[ idx + 1 ], array[ idx + 2 ] );
 					result[ idx / 3 * 2 + 0 ] = encoded[ 0 ];
 					result[ idx / 3 * 2 + 1 ] = encoded[ 1 ];
 
@@ -150,8 +152,7 @@
 
 			}
 
-		},
-
+		}
 		/**
 		 * Make the input mesh.geometry's position attribute encoded and compressed.
 		 * Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the position data.
@@ -159,7 +160,9 @@
 		 * @param {THREE.Mesh} mesh
 		 *
 		 */
-		compressPositions: function ( mesh ) {
+
+
+		static compressPositions( mesh ) {
 
 			if ( ! mesh.geometry ) {
 
@@ -185,7 +188,7 @@
 
 			const array = position.array;
 			const encodingBytes = 2;
-			const result = this.EncodingFuncs.quantizedEncode( array, encodingBytes );
+			const result = EncodingFuncs.quantizedEncode( array, encodingBytes );
 			const quantized = result.quantized;
 			const decodeMat = result.decodeMat; // IMPORTANT: calculate original geometry bounding info first, before updating packed positions
 
@@ -206,8 +209,7 @@
 			mesh.material.uniforms.quantizeMatPos.value = decodeMat;
 			mesh.material.uniforms.quantizeMatPos.needsUpdate = true;
 
-		},
-
+		}
 		/**
 		 * Make the input mesh.geometry's uv attribute encoded and compressed.
 		 * Also will change the mesh.material to `PackedPhongMaterial` which let the vertex shader program decode the uv data.
@@ -215,7 +217,9 @@
 		 * @param {THREE.Mesh} mesh
 		 *
 		 */
-		compressUvs: function ( mesh ) {
+
+
+		static compressUvs( mesh ) {
 
 			if ( ! mesh.geometry ) {
 
@@ -254,7 +258,7 @@
 
 				for ( let i = 0; i < array.length; i += 2 ) {
 
-					const encoded = this.EncodingFuncs.defaultEncode( array[ i ], array[ i + 1 ], 0, 2 );
+					const encoded = EncodingFuncs.defaultEncode( array[ i ], array[ i + 1 ], 0, 2 );
 					result[ i ] = encoded[ 0 ];
 					result[ i + 1 ] = encoded[ 1 ];
 
@@ -276,7 +280,7 @@
 			} else {
 
 				// use quantized encoding method
-				result = this.EncodingFuncs.quantizedEncodeUV( array, 2 );
+				result = EncodingFuncs.quantizedEncodeUV( array, 2 );
 				mesh.geometry.setAttribute( 'uv', new THREE.BufferAttribute( result.quantized, 2 ) );
 				mesh.geometry.attributes.uv.isPacked = true;
 				mesh.geometry.attributes.uv.needsUpdate = true;
@@ -294,295 +298,305 @@
 
 			}
 
-		},
-		EncodingFuncs: {
-			defaultEncode: function ( x, y, z, bytes ) {
+		}
 
-				if ( bytes == 1 ) {
+	}
 
-					const tmpx = Math.round( ( x + 1 ) * 0.5 * 255 );
-					const tmpy = Math.round( ( y + 1 ) * 0.5 * 255 );
-					const tmpz = Math.round( ( z + 1 ) * 0.5 * 255 );
-					return new Uint8Array( [ tmpx, tmpy, tmpz ] );
+	class EncodingFuncs {
 
-				} else if ( bytes == 2 ) {
+		static defaultEncode( x, y, z, bytes ) {
 
-					const tmpx = Math.round( ( x + 1 ) * 0.5 * 65535 );
-					const tmpy = Math.round( ( y + 1 ) * 0.5 * 65535 );
-					const tmpz = Math.round( ( z + 1 ) * 0.5 * 65535 );
-					return new Uint16Array( [ tmpx, tmpy, tmpz ] );
+			if ( bytes == 1 ) {
 
-				} else {
+				const tmpx = Math.round( ( x + 1 ) * 0.5 * 255 );
+				const tmpy = Math.round( ( y + 1 ) * 0.5 * 255 );
+				const tmpz = Math.round( ( z + 1 ) * 0.5 * 255 );
+				return new Uint8Array( [ tmpx, tmpy, tmpz ] );
 
-					console.error( 'number of bytes must be 1 or 2' );
+			} else if ( bytes == 2 ) {
 
-				}
+				const tmpx = Math.round( ( x + 1 ) * 0.5 * 65535 );
+				const tmpy = Math.round( ( y + 1 ) * 0.5 * 65535 );
+				const tmpz = Math.round( ( z + 1 ) * 0.5 * 65535 );
+				return new Uint16Array( [ tmpx, tmpy, tmpz ] );
 
-			},
-			defaultDecode: function ( array, bytes ) {
+			} else {
 
-				if ( bytes == 1 ) {
+				console.error( 'number of bytes must be 1 or 2' );
+
+			}
 
-					return [ array[ 0 ] / 255 * 2.0 - 1.0, array[ 1 ] / 255 * 2.0 - 1.0, array[ 2 ] / 255 * 2.0 - 1.0 ];
+		}
 
-				} else if ( bytes == 2 ) {
+		static defaultDecode( array, bytes ) {
 
-					return [ array[ 0 ] / 65535 * 2.0 - 1.0, array[ 1 ] / 65535 * 2.0 - 1.0, array[ 2 ] / 65535 * 2.0 - 1.0 ];
+			if ( bytes == 1 ) {
 
-				} else {
+				return [ array[ 0 ] / 255 * 2.0 - 1.0, array[ 1 ] / 255 * 2.0 - 1.0, array[ 2 ] / 255 * 2.0 - 1.0 ];
 
-					console.error( 'number of bytes must be 1 or 2' );
+			} else if ( bytes == 2 ) {
 
-				}
+				return [ array[ 0 ] / 65535 * 2.0 - 1.0, array[ 1 ] / 65535 * 2.0 - 1.0, array[ 2 ] / 65535 * 2.0 - 1.0 ];
 
-			},
-			// for `Angles` encoding
-			anglesEncode: function ( x, y, z ) {
+			} else {
 
-				const normal0 = parseInt( 0.5 * ( 1.0 + Math.atan2( y, x ) / Math.PI ) * 65535 );
-				const normal1 = parseInt( 0.5 * ( 1.0 + z ) * 65535 );
-				return new Uint16Array( [ normal0, normal1 ] );
+				console.error( 'number of bytes must be 1 or 2' );
 
-			},
-			// for `Octahedron` encoding
-			octEncodeBest: function ( x, y, z, bytes ) {
+			}
 
-				var oct, dec, best, currentCos, bestCos; // Test various combinations of ceil and floor
-				// to minimize rounding errors
+		} // for `Angles` encoding
 
-				best = oct = octEncodeVec3( x, y, z, 'floor', 'floor' );
-				dec = octDecodeVec2( oct );
-				bestCos = dot( x, y, z, dec );
-				oct = octEncodeVec3( x, y, z, 'ceil', 'floor' );
-				dec = octDecodeVec2( oct );
-				currentCos = dot( x, y, z, dec );
 
-				if ( currentCos > bestCos ) {
+		static anglesEncode( x, y, z ) {
 
-					best = oct;
-					bestCos = currentCos;
+			const normal0 = parseInt( 0.5 * ( 1.0 + Math.atan2( y, x ) / Math.PI ) * 65535 );
+			const normal1 = parseInt( 0.5 * ( 1.0 + z ) * 65535 );
+			return new Uint16Array( [ normal0, normal1 ] );
 
-				}
+		} // for `Octahedron` encoding
 
-				oct = octEncodeVec3( x, y, z, 'floor', 'ceil' );
-				dec = octDecodeVec2( oct );
-				currentCos = dot( x, y, z, dec );
 
-				if ( currentCos > bestCos ) {
+		static octEncodeBest( x, y, z, bytes ) {
 
-					best = oct;
-					bestCos = currentCos;
+			let oct, dec, best, currentCos, bestCos; // Test various combinations of ceil and floor
+			// to minimize rounding errors
 
-				}
+			best = oct = octEncodeVec3( x, y, z, 'floor', 'floor' );
+			dec = octDecodeVec2( oct );
+			bestCos = dot( x, y, z, dec );
+			oct = octEncodeVec3( x, y, z, 'ceil', 'floor' );
+			dec = octDecodeVec2( oct );
+			currentCos = dot( x, y, z, dec );
 
-				oct = octEncodeVec3( x, y, z, 'ceil', 'ceil' );
-				dec = octDecodeVec2( oct );
-				currentCos = dot( x, y, z, dec );
+			if ( currentCos > bestCos ) {
 
-				if ( currentCos > bestCos ) {
+				best = oct;
+				bestCos = currentCos;
 
-					best = oct;
+			}
 
-				}
+			oct = octEncodeVec3( x, y, z, 'floor', 'ceil' );
+			dec = octDecodeVec2( oct );
+			currentCos = dot( x, y, z, dec );
 
-				return best;
+			if ( currentCos > bestCos ) {
 
-				function octEncodeVec3( x0, y0, z0, xfunc, yfunc ) {
+				best = oct;
+				bestCos = currentCos;
 
-					var x = x0 / ( Math.abs( x0 ) + Math.abs( y0 ) + Math.abs( z0 ) );
-					var y = y0 / ( Math.abs( x0 ) + Math.abs( y0 ) + Math.abs( z0 ) );
+			}
 
-					if ( z < 0 ) {
+			oct = octEncodeVec3( x, y, z, 'ceil', 'ceil' );
+			dec = octDecodeVec2( oct );
+			currentCos = dot( x, y, z, dec );
 
-						var tempx = ( 1 - Math.abs( y ) ) * ( x >= 0 ? 1 : - 1 );
-						var tempy = ( 1 - Math.abs( x ) ) * ( y >= 0 ? 1 : - 1 );
-						x = tempx;
-						y = tempy;
-						var diff = 1 - Math.abs( x ) - Math.abs( y );
+			if ( currentCos > bestCos ) {
 
-						if ( diff > 0 ) {
+				best = oct;
 
-							diff += 0.001;
-							x += x > 0 ? diff / 2 : - diff / 2;
-							y += y > 0 ? diff / 2 : - diff / 2;
+			}
 
-						}
+			return best;
 
-					}
+			function octEncodeVec3( x0, y0, z0, xfunc, yfunc ) {
 
-					if ( bytes == 1 ) {
+				let x = x0 / ( Math.abs( x0 ) + Math.abs( y0 ) + Math.abs( z0 ) );
+				let y = y0 / ( Math.abs( x0 ) + Math.abs( y0 ) + Math.abs( z0 ) );
 
-						return new Int8Array( [ Math[ xfunc ]( x * 127.5 + ( x < 0 ? 1 : 0 ) ), Math[ yfunc ]( y * 127.5 + ( y < 0 ? 1 : 0 ) ) ] );
+				if ( z < 0 ) {
 
-					}
+					const tempx = ( 1 - Math.abs( y ) ) * ( x >= 0 ? 1 : - 1 );
+					const tempy = ( 1 - Math.abs( x ) ) * ( y >= 0 ? 1 : - 1 );
+					x = tempx;
+					y = tempy;
+					let diff = 1 - Math.abs( x ) - Math.abs( y );
 
-					if ( bytes == 2 ) {
+					if ( diff > 0 ) {
 
-						return new Int16Array( [ Math[ xfunc ]( x * 32767.5 + ( x < 0 ? 1 : 0 ) ), Math[ yfunc ]( y * 32767.5 + ( y < 0 ? 1 : 0 ) ) ] );
+						diff += 0.001;
+						x += x > 0 ? diff / 2 : - diff / 2;
+						y += y > 0 ? diff / 2 : - diff / 2;
 
 					}
 
 				}
 
-				function octDecodeVec2( oct ) {
+				if ( bytes == 1 ) {
 
-					var x = oct[ 0 ];
-					var y = oct[ 1 ];
+					return new Int8Array( [ Math[ xfunc ]( x * 127.5 + ( x < 0 ? 1 : 0 ) ), Math[ yfunc ]( y * 127.5 + ( y < 0 ? 1 : 0 ) ) ] );
 
-					if ( bytes == 1 ) {
+				}
 
-						x /= x < 0 ? 127 : 128;
-						y /= y < 0 ? 127 : 128;
+				if ( bytes == 2 ) {
 
-					} else if ( bytes == 2 ) {
+					return new Int16Array( [ Math[ xfunc ]( x * 32767.5 + ( x < 0 ? 1 : 0 ) ), Math[ yfunc ]( y * 32767.5 + ( y < 0 ? 1 : 0 ) ) ] );
 
-						x /= x < 0 ? 32767 : 32768;
-						y /= y < 0 ? 32767 : 32768;
+				}
 
-					}
+			}
 
-					var z = 1 - Math.abs( x ) - Math.abs( y );
+			function octDecodeVec2( oct ) {
 
-					if ( z < 0 ) {
+				let x = oct[ 0 ];
+				let y = oct[ 1 ];
 
-						var tmpx = x;
-						x = ( 1 - Math.abs( y ) ) * ( x >= 0 ? 1 : - 1 );
-						y = ( 1 - Math.abs( tmpx ) ) * ( y >= 0 ? 1 : - 1 );
+				if ( bytes == 1 ) {
 
-					}
+					x /= x < 0 ? 127 : 128;
+					y /= y < 0 ? 127 : 128;
 
-					var length = Math.sqrt( x * x + y * y + z * z );
-					return [ x / length, y / length, z / length ];
+				} else if ( bytes == 2 ) {
+
+					x /= x < 0 ? 32767 : 32768;
+					y /= y < 0 ? 32767 : 32768;
 
 				}
 
-				function dot( x, y, z, vec3 ) {
+				const z = 1 - Math.abs( x ) - Math.abs( y );
+
+				if ( z < 0 ) {
 
-					return x * vec3[ 0 ] + y * vec3[ 1 ] + z * vec3[ 2 ];
+					const tmpx = x;
+					x = ( 1 - Math.abs( y ) ) * ( x >= 0 ? 1 : - 1 );
+					y = ( 1 - Math.abs( tmpx ) ) * ( y >= 0 ? 1 : - 1 );
 
 				}
 
-			},
-			quantizedEncode: function ( array, bytes ) {
+				const length = Math.sqrt( x * x + y * y + z * z );
+				return [ x / length, y / length, z / length ];
 
-				let quantized, segments;
+			}
 
-				if ( bytes == 1 ) {
+			function dot( x, y, z, vec3 ) {
 
-					quantized = new Uint8Array( array.length );
-					segments = 255;
+				return x * vec3[ 0 ] + y * vec3[ 1 ] + z * vec3[ 2 ];
 
-				} else if ( bytes == 2 ) {
+			}
+
+		}
 
-					quantized = new Uint16Array( array.length );
-					segments = 65535;
+		static quantizedEncode( array, bytes ) {
 
-				} else {
+			let quantized, segments;
 
-					console.error( 'number of bytes error! ' );
+			if ( bytes == 1 ) {
 
-				}
+				quantized = new Uint8Array( array.length );
+				segments = 255;
 
-				const decodeMat = new THREE.Matrix4();
-				const min = new Float32Array( 3 );
-				const max = new Float32Array( 3 );
-				min[ 0 ] = min[ 1 ] = min[ 2 ] = Number.MAX_VALUE;
-				max[ 0 ] = max[ 1 ] = max[ 2 ] = - Number.MAX_VALUE;
+			} else if ( bytes == 2 ) {
 
-				for ( let i = 0; i < array.length; i += 3 ) {
+				quantized = new Uint16Array( array.length );
+				segments = 65535;
 
-					min[ 0 ] = Math.min( min[ 0 ], array[ i + 0 ] );
-					min[ 1 ] = Math.min( min[ 1 ], array[ i + 1 ] );
-					min[ 2 ] = Math.min( min[ 2 ], array[ i + 2 ] );
-					max[ 0 ] = Math.max( max[ 0 ], array[ i + 0 ] );
-					max[ 1 ] = Math.max( max[ 1 ], array[ i + 1 ] );
-					max[ 2 ] = Math.max( max[ 2 ], array[ i + 2 ] );
+			} else {
 
-				}
+				console.error( 'number of bytes error! ' );
 
-				decodeMat.scale( new THREE.Vector3( ( max[ 0 ] - min[ 0 ] ) / segments, ( max[ 1 ] - min[ 1 ] ) / segments, ( max[ 2 ] - min[ 2 ] ) / segments ) );
-				decodeMat.elements[ 12 ] = min[ 0 ];
-				decodeMat.elements[ 13 ] = min[ 1 ];
-				decodeMat.elements[ 14 ] = min[ 2 ];
-				decodeMat.transpose();
-				const multiplier = new Float32Array( [ max[ 0 ] !== min[ 0 ] ? segments / ( max[ 0 ] - min[ 0 ] ) : 0, max[ 1 ] !== min[ 1 ] ? segments / ( max[ 1 ] - min[ 1 ] ) : 0, max[ 2 ] !== min[ 2 ] ? segments / ( max[ 2 ] - min[ 2 ] ) : 0 ] );
+			}
 
-				for ( let i = 0; i < array.length; i += 3 ) {
+			const decodeMat = new THREE.Matrix4();
+			const min = new Float32Array( 3 );
+			const max = new Float32Array( 3 );
+			min[ 0 ] = min[ 1 ] = min[ 2 ] = Number.MAX_VALUE;
+			max[ 0 ] = max[ 1 ] = max[ 2 ] = - Number.MAX_VALUE;
 
-					quantized[ i + 0 ] = Math.floor( ( array[ i + 0 ] - min[ 0 ] ) * multiplier[ 0 ] );
-					quantized[ i + 1 ] = Math.floor( ( array[ i + 1 ] - min[ 1 ] ) * multiplier[ 1 ] );
-					quantized[ i + 2 ] = Math.floor( ( array[ i + 2 ] - min[ 2 ] ) * multiplier[ 2 ] );
+			for ( let i = 0; i < array.length; i += 3 ) {
 
-				}
+				min[ 0 ] = Math.min( min[ 0 ], array[ i + 0 ] );
+				min[ 1 ] = Math.min( min[ 1 ], array[ i + 1 ] );
+				min[ 2 ] = Math.min( min[ 2 ], array[ i + 2 ] );
+				max[ 0 ] = Math.max( max[ 0 ], array[ i + 0 ] );
+				max[ 1 ] = Math.max( max[ 1 ], array[ i + 1 ] );
+				max[ 2 ] = Math.max( max[ 2 ], array[ i + 2 ] );
 
-				return {
-					quantized: quantized,
-					decodeMat: decodeMat
-				};
+			}
 
-			},
-			quantizedEncodeUV: function ( array, bytes ) {
+			decodeMat.scale( new THREE.Vector3( ( max[ 0 ] - min[ 0 ] ) / segments, ( max[ 1 ] - min[ 1 ] ) / segments, ( max[ 2 ] - min[ 2 ] ) / segments ) );
+			decodeMat.elements[ 12 ] = min[ 0 ];
+			decodeMat.elements[ 13 ] = min[ 1 ];
+			decodeMat.elements[ 14 ] = min[ 2 ];
+			decodeMat.transpose();
+			const multiplier = new Float32Array( [ max[ 0 ] !== min[ 0 ] ? segments / ( max[ 0 ] - min[ 0 ] ) : 0, max[ 1 ] !== min[ 1 ] ? segments / ( max[ 1 ] - min[ 1 ] ) : 0, max[ 2 ] !== min[ 2 ] ? segments / ( max[ 2 ] - min[ 2 ] ) : 0 ] );
 
-				let quantized, segments;
+			for ( let i = 0; i < array.length; i += 3 ) {
 
-				if ( bytes == 1 ) {
+				quantized[ i + 0 ] = Math.floor( ( array[ i + 0 ] - min[ 0 ] ) * multiplier[ 0 ] );
+				quantized[ i + 1 ] = Math.floor( ( array[ i + 1 ] - min[ 1 ] ) * multiplier[ 1 ] );
+				quantized[ i + 2 ] = Math.floor( ( array[ i + 2 ] - min[ 2 ] ) * multiplier[ 2 ] );
 
-					quantized = new Uint8Array( array.length );
-					segments = 255;
+			}
 
-				} else if ( bytes == 2 ) {
+			return {
+				quantized: quantized,
+				decodeMat: decodeMat
+			};
 
-					quantized = new Uint16Array( array.length );
-					segments = 65535;
+		}
 
-				} else {
+		static quantizedEncodeUV( array, bytes ) {
 
-					console.error( 'number of bytes error! ' );
+			let quantized, segments;
 
-				}
+			if ( bytes == 1 ) {
 
-				const decodeMat = new THREE.Matrix3();
-				const min = new Float32Array( 2 );
-				const max = new Float32Array( 2 );
-				min[ 0 ] = min[ 1 ] = Number.MAX_VALUE;
-				max[ 0 ] = max[ 1 ] = - Number.MAX_VALUE;
+				quantized = new Uint8Array( array.length );
+				segments = 255;
 
-				for ( let i = 0; i < array.length; i += 2 ) {
+			} else if ( bytes == 2 ) {
 
-					min[ 0 ] = Math.min( min[ 0 ], array[ i + 0 ] );
-					min[ 1 ] = Math.min( min[ 1 ], array[ i + 1 ] );
-					max[ 0 ] = Math.max( max[ 0 ], array[ i + 0 ] );
-					max[ 1 ] = Math.max( max[ 1 ], array[ i + 1 ] );
+				quantized = new Uint16Array( array.length );
+				segments = 65535;
 
-				}
+			} else {
 
-				decodeMat.scale( ( max[ 0 ] - min[ 0 ] ) / segments, ( max[ 1 ] - min[ 1 ] ) / segments );
-				decodeMat.elements[ 6 ] = min[ 0 ];
-				decodeMat.elements[ 7 ] = min[ 1 ];
-				decodeMat.transpose();
-				const multiplier = new Float32Array( [ max[ 0 ] !== min[ 0 ] ? segments / ( max[ 0 ] - min[ 0 ] ) : 0, max[ 1 ] !== min[ 1 ] ? segments / ( max[ 1 ] - min[ 1 ] ) : 0 ] );
+				console.error( 'number of bytes error! ' );
 
-				for ( let i = 0; i < array.length; i += 2 ) {
+			}
 
-					quantized[ i + 0 ] = Math.floor( ( array[ i + 0 ] - min[ 0 ] ) * multiplier[ 0 ] );
-					quantized[ i + 1 ] = Math.floor( ( array[ i + 1 ] - min[ 1 ] ) * multiplier[ 1 ] );
+			const decodeMat = new THREE.Matrix3();
+			const min = new Float32Array( 2 );
+			const max = new Float32Array( 2 );
+			min[ 0 ] = min[ 1 ] = Number.MAX_VALUE;
+			max[ 0 ] = max[ 1 ] = - Number.MAX_VALUE;
 
-				}
+			for ( let i = 0; i < array.length; i += 2 ) {
+
+				min[ 0 ] = Math.min( min[ 0 ], array[ i + 0 ] );
+				min[ 1 ] = Math.min( min[ 1 ], array[ i + 1 ] );
+				max[ 0 ] = Math.max( max[ 0 ], array[ i + 0 ] );
+				max[ 1 ] = Math.max( max[ 1 ], array[ i + 1 ] );
 
-				return {
-					quantized: quantized,
-					decodeMat: decodeMat
-				};
+			}
+
+			decodeMat.scale( ( max[ 0 ] - min[ 0 ] ) / segments, ( max[ 1 ] - min[ 1 ] ) / segments );
+			decodeMat.elements[ 6 ] = min[ 0 ];
+			decodeMat.elements[ 7 ] = min[ 1 ];
+			decodeMat.transpose();
+			const multiplier = new Float32Array( [ max[ 0 ] !== min[ 0 ] ? segments / ( max[ 0 ] - min[ 0 ] ) : 0, max[ 1 ] !== min[ 1 ] ? segments / ( max[ 1 ] - min[ 1 ] ) : 0 ] );
+
+			for ( let i = 0; i < array.length; i += 2 ) {
+
+				quantized[ i + 0 ] = Math.floor( ( array[ i + 0 ] - min[ 0 ] ) * multiplier[ 0 ] );
+				quantized[ i + 1 ] = Math.floor( ( array[ i + 1 ] - min[ 1 ] ) * multiplier[ 1 ] );
 
 			}
+
+			return {
+				quantized: quantized,
+				decodeMat: decodeMat
+			};
+
 		}
-	};
+
+	}
 	/**
  * `PackedPhongMaterial` inherited from THREE.MeshPhongMaterial
  *
  * @param {Object} parameters
  */
 
+
 	class PackedPhongMaterial extends THREE.MeshPhongMaterial {
 
 		constructor( parameters ) {

+ 34 - 51
examples/js/utils/GeometryUtils.js

@@ -1,7 +1,8 @@
 ( function () {
 
-	var GeometryUtils = {
-	/**
+	class GeometryUtils {
+
+		/**
 	 * Generates 2D-Coordinates in a very fast way.
 	 *
 	 * Based on work by:
@@ -15,23 +16,15 @@
 	 * @param v2				 Corner index +X, +Z.
 	 * @param v3				 Corner index +X, -Z.
 	 */
-		hilbert2D: function ( center, size, iterations, v0, v1, v2, v3 ) {
+		static hilbert2D( center = new THREE.Vector3( 0, 0, 0 ), size = 10, iterations = 1, v0 = 0, v1 = 1, v2 = 2, v3 = 3 ) {
 
-			// Default Vars
-			var center = center !== undefined ? center : new THREE.Vector3( 0, 0, 0 ),
-				size = size !== undefined ? size : 10,
-				half = size / 2,
-				iterations = iterations !== undefined ? iterations : 1,
-				v0 = v0 !== undefined ? v0 : 0,
-				v1 = v1 !== undefined ? v1 : 1,
-				v2 = v2 !== undefined ? v2 : 2,
-				v3 = v3 !== undefined ? v3 : 3;
-			var vec_s = [ new THREE.Vector3( center.x - half, center.y, center.z - half ), new THREE.Vector3( center.x - half, center.y, center.z + half ), new THREE.Vector3( center.x + half, center.y, center.z + half ), new THREE.Vector3( center.x + half, center.y, center.z - half ) ];
-			var vec = [ vec_s[ v0 ], vec_s[ v1 ], vec_s[ v2 ], vec_s[ v3 ] ]; // Recurse iterations
+			const half = size / 2;
+			const vec_s = [ new THREE.Vector3( center.x - half, center.y, center.z - half ), new THREE.Vector3( center.x - half, center.y, center.z + half ), new THREE.Vector3( center.x + half, center.y, center.z + half ), new THREE.Vector3( center.x + half, center.y, center.z - half ) ];
+			const vec = [ vec_s[ v0 ], vec_s[ v1 ], vec_s[ v2 ], vec_s[ v3 ] ]; // Recurse iterations
 
 			if ( 0 <= -- iterations ) {
 
-				var tmp = [];
+				const tmp = [];
 				Array.prototype.push.apply( tmp, GeometryUtils.hilbert2D( vec[ 0 ], half, iterations, v0, v3, v2, v1 ) );
 				Array.prototype.push.apply( tmp, GeometryUtils.hilbert2D( vec[ 1 ], half, iterations, v0, v1, v2, v3 ) );
 				Array.prototype.push.apply( tmp, GeometryUtils.hilbert2D( vec[ 2 ], half, iterations, v0, v1, v2, v3 ) );
@@ -44,8 +37,7 @@
 
 			return vec;
 
-		},
-
+		}
 		/**
 	 * Generates 3D-Coordinates in a very fast way.
 	 *
@@ -64,27 +56,18 @@
 	 * @param v6				 Corner index +X, +Y, +Z.
 	 * @param v7				 Corner index +X, +Y, -Z.
 	 */
-		hilbert3D: function ( center, size, iterations, v0, v1, v2, v3, v4, v5, v6, v7 ) {
+
+
+		static hilbert3D( center = new THREE.Vector3( 0, 0, 0 ), size = 10, iterations = 1, v0 = 0, v1 = 1, v2 = 2, v3 = 3, v4 = 4, v5 = 5, v6 = 6, v7 = 7 ) {
 
 			// Default Vars
-			var center = center !== undefined ? center : new THREE.Vector3( 0, 0, 0 ),
-				size = size !== undefined ? size : 10,
-				half = size / 2,
-				iterations = iterations !== undefined ? iterations : 1,
-				v0 = v0 !== undefined ? v0 : 0,
-				v1 = v1 !== undefined ? v1 : 1,
-				v2 = v2 !== undefined ? v2 : 2,
-				v3 = v3 !== undefined ? v3 : 3,
-				v4 = v4 !== undefined ? v4 : 4,
-				v5 = v5 !== undefined ? v5 : 5,
-				v6 = v6 !== undefined ? v6 : 6,
-				v7 = v7 !== undefined ? v7 : 7;
-			var vec_s = [ new THREE.Vector3( center.x - half, center.y + half, center.z - half ), new THREE.Vector3( center.x - half, center.y + half, center.z + half ), new THREE.Vector3( center.x - half, center.y - half, center.z + half ), new THREE.Vector3( center.x - half, center.y - half, center.z - half ), new THREE.Vector3( center.x + half, center.y - half, center.z - half ), new THREE.Vector3( center.x + half, center.y - half, center.z + half ), new THREE.Vector3( center.x + half, center.y + half, center.z + half ), new THREE.Vector3( center.x + half, center.y + half, center.z - half ) ];
-			var vec = [ vec_s[ v0 ], vec_s[ v1 ], vec_s[ v2 ], vec_s[ v3 ], vec_s[ v4 ], vec_s[ v5 ], vec_s[ v6 ], vec_s[ v7 ] ]; // Recurse iterations
+			const half = size / 2;
+			const vec_s = [ new THREE.Vector3( center.x - half, center.y + half, center.z - half ), new THREE.Vector3( center.x - half, center.y + half, center.z + half ), new THREE.Vector3( center.x - half, center.y - half, center.z + half ), new THREE.Vector3( center.x - half, center.y - half, center.z - half ), new THREE.Vector3( center.x + half, center.y - half, center.z - half ), new THREE.Vector3( center.x + half, center.y - half, center.z + half ), new THREE.Vector3( center.x + half, center.y + half, center.z + half ), new THREE.Vector3( center.x + half, center.y + half, center.z - half ) ];
+			const vec = [ vec_s[ v0 ], vec_s[ v1 ], vec_s[ v2 ], vec_s[ v3 ], vec_s[ v4 ], vec_s[ v5 ], vec_s[ v6 ], vec_s[ v7 ] ]; // Recurse iterations
 
 			if ( -- iterations >= 0 ) {
 
-				var tmp = [];
+				const tmp = [];
 				Array.prototype.push.apply( tmp, GeometryUtils.hilbert3D( vec[ 0 ], half, iterations, v0, v3, v4, v7, v6, v5, v2, v1 ) );
 				Array.prototype.push.apply( tmp, GeometryUtils.hilbert3D( vec[ 1 ], half, iterations, v0, v7, v6, v1, v2, v5, v4, v3 ) );
 				Array.prototype.push.apply( tmp, GeometryUtils.hilbert3D( vec[ 2 ], half, iterations, v0, v7, v6, v1, v2, v5, v4, v3 ) );
@@ -101,8 +84,7 @@
 
 			return vec;
 
-		},
-
+		}
 		/**
 	 * Generates a Gosper curve (lying in the XY plane)
 	 *
@@ -110,22 +92,22 @@
 	 *
 	 * @param size The size of a single gosper island.
 	 */
-		gosper: function ( size ) {
 
-			size = size !== undefined ? size : 1;
+
+		static gosper( size = 1 ) {
 
 			function fractalize( config ) {
 
-				var output;
-				var input = config.axiom;
+				let output;
+				let input = config.axiom;
 
-				for ( var i = 0, il = config.steps; 0 <= il ? i < il : i > il; 0 <= il ? i ++ : i -- ) {
+				for ( let i = 0, il = config.steps; 0 <= il ? i < il : i > il; 0 <= il ? i ++ : i -- ) {
 
 					output = '';
 
-					for ( var j = 0, jl = input.length; j < jl; j ++ ) {
+					for ( let j = 0, jl = input.length; j < jl; j ++ ) {
 
-						var char = input[ j ];
+						const char = input[ j ];
 
 						if ( char in config.rules ) {
 
@@ -149,15 +131,15 @@
 
 			function toPoints( config ) {
 
-				var currX = 0,
+				let currX = 0,
 					currY = 0;
-				var angle = 0;
-				var path = [ 0, 0, 0 ];
-				var fractal = config.fractal;
+				let angle = 0;
+				const path = [ 0, 0, 0 ];
+				const fractal = config.fractal;
 
-				for ( var i = 0, l = fractal.length; i < l; i ++ ) {
+				for ( let i = 0, l = fractal.length; i < l; i ++ ) {
 
-					var char = fractal[ i ];
+					const char = fractal[ i ];
 
 					if ( char === '+' ) {
 
@@ -182,7 +164,7 @@
 			} //
 
 
-			var gosper = fractalize( {
+			const gosper = fractalize( {
 				axiom: 'A',
 				steps: 4,
 				rules: {
@@ -190,7 +172,7 @@
 					B: '-FA+BFBF++BF+FA--FA-B'
 				}
 			} );
-			var points = toPoints( {
+			const points = toPoints( {
 				fractal: gosper,
 				size: size,
 				angle: Math.PI / 3 // 60 degrees
@@ -199,7 +181,8 @@
 			return points;
 
 		}
-	};
+
+	}
 
 	THREE.GeometryUtils = GeometryUtils;
 

+ 22 - 17
examples/js/utils/SceneUtils.js

@@ -1,16 +1,17 @@
 ( function () {
 
-	var SceneUtils = {
-		createMeshesFromInstancedMesh: function ( instancedMesh ) {
+	class SceneUtils {
 
-			var group = new THREE.Group();
-			var count = instancedMesh.count;
-			var geometry = instancedMesh.geometry;
-			var material = instancedMesh.material;
+		static createMeshesFromInstancedMesh( instancedMesh ) {
 
-			for ( var i = 0; i < count; i ++ ) {
+			const group = new THREE.Group();
+			const count = instancedMesh.count;
+			const geometry = instancedMesh.geometry;
+			const material = instancedMesh.material;
 
-				var mesh = new THREE.Mesh( geometry, material );
+			for ( let i = 0; i < count; i ++ ) {
+
+				const mesh = new THREE.Mesh( geometry, material );
 				instancedMesh.getMatrixAt( i, mesh.matrix );
 				mesh.matrix.decompose( mesh.position, mesh.quaternion, mesh.scale );
 				group.add( mesh );
@@ -22,12 +23,13 @@
 
 			return group;
 
-		},
-		createMultiMaterialObject: function ( geometry, materials ) {
+		}
+
+		static createMultiMaterialObject( geometry, materials ) {
 
-			var group = new THREE.Group();
+			const group = new THREE.Group();
 
-			for ( var i = 0, l = materials.length; i < l; i ++ ) {
+			for ( let i = 0, l = materials.length; i < l; i ++ ) {
 
 				group.add( new THREE.Mesh( geometry, materials[ i ] ) );
 
@@ -35,20 +37,23 @@
 
 			return group;
 
-		},
-		detach: function ( child, parent, scene ) {
+		}
+
+		static detach( child, parent, scene ) {
 
 			console.warn( 'THREE.SceneUtils: detach() has been deprecated. Use scene.attach( child ) instead.' );
 			scene.attach( child );
 
-		},
-		attach: function ( child, scene, parent ) {
+		}
+
+		static attach( child, scene, parent ) {
 
 			console.warn( 'THREE.SceneUtils: attach() has been deprecated. Use parent.attach( child ) instead.' );
 			parent.attach( child );
 
 		}
-	};
+
+	}
 
 	THREE.SceneUtils = SceneUtils;
 

+ 117 - 115
examples/js/utils/ShadowMapViewer.js

@@ -9,12 +9,12 @@
  *	1) Import ShadowMapViewer into your app.
  *
  *	2) Create a shadow casting light and name it optionally:
- *		var light = new DirectionalLight( 0xffffff, 1 );
+ *		let light = new DirectionalLight( 0xffffff, 1 );
  *		light.castShadow = true;
  *		light.name = 'Sun';
  *
  *	3) Create a shadow map viewer for that light and set its size and position optionally:
- *		var shadowMapViewer = new ShadowMapViewer( light );
+ *		let shadowMapViewer = new ShadowMapViewer( light );
  *		shadowMapViewer.size.set( 128, 128 );	//width, height	default: 256, 256
  *		shadowMapViewer.position.set( 10, 10 );	//x, y in pixel	 default: 0, 0 (top left corner)
  *
@@ -27,151 +27,153 @@
  *	6) If you set the position or size members directly, you need to call shadowMapViewer.update();
  */
 
-	var ShadowMapViewer = function ( light ) {
-
-		//- Internals
-		var scope = this;
-		var doRenderLabel = light.name !== undefined && light.name !== '';
-		var userAutoClearSetting; //Holds the initial position and dimension of the HUD
-
-		var frame = {
-			x: 10,
-			y: 10,
-			width: 256,
-			height: 256
-		};
-		var camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 10 );
-		camera.position.set( 0, 0, 2 );
-		var scene = new THREE.Scene(); //HUD for shadow map
-
-		var shader = THREE.UnpackDepthRGBAShader;
-		var uniforms = THREE.UniformsUtils.clone( shader.uniforms );
-		var material = new THREE.ShaderMaterial( {
-			uniforms: uniforms,
-			vertexShader: shader.vertexShader,
-			fragmentShader: shader.fragmentShader
-		} );
-		var plane = new THREE.PlaneGeometry( frame.width, frame.height );
-		var mesh = new THREE.Mesh( plane, material );
-		scene.add( mesh ); //Label for light's name
-
-		var labelCanvas, labelMesh;
-
-		if ( doRenderLabel ) {
-
-			labelCanvas = document.createElement( 'canvas' );
-			var context = labelCanvas.getContext( '2d' );
-			context.font = 'Bold 20px Arial';
-			var labelWidth = context.measureText( light.name ).width;
-			labelCanvas.width = labelWidth;
-			labelCanvas.height = 25; //25 to account for g, p, etc.
-
-			context.font = 'Bold 20px Arial';
-			context.fillStyle = 'rgba( 255, 0, 0, 1 )';
-			context.fillText( light.name, 0, 20 );
-			var labelTexture = new THREE.Texture( labelCanvas );
-			labelTexture.magFilter = THREE.LinearFilter;
-			labelTexture.minFilter = THREE.LinearFilter;
-			labelTexture.needsUpdate = true;
-			var labelMaterial = new THREE.MeshBasicMaterial( {
-				map: labelTexture,
-				side: THREE.DoubleSide
+	class ShadowMapViewer {
+
+		constructor( light ) {
+
+			//- Internals
+			const scope = this;
+			const doRenderLabel = light.name !== undefined && light.name !== '';
+			let userAutoClearSetting; //Holds the initial position and dimension of the HUD
+
+			const frame = {
+				x: 10,
+				y: 10,
+				width: 256,
+				height: 256
+			};
+			const camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 10 );
+			camera.position.set( 0, 0, 2 );
+			const scene = new THREE.Scene(); //HUD for shadow map
+
+			const shader = THREE.UnpackDepthRGBAShader;
+			const uniforms = THREE.UniformsUtils.clone( shader.uniforms );
+			const material = new THREE.ShaderMaterial( {
+				uniforms: uniforms,
+				vertexShader: shader.vertexShader,
+				fragmentShader: shader.fragmentShader
 			} );
-			labelMaterial.transparent = true;
-			var labelPlane = new THREE.PlaneGeometry( labelCanvas.width, labelCanvas.height );
-			labelMesh = new THREE.Mesh( labelPlane, labelMaterial );
-			scene.add( labelMesh );
+			const plane = new THREE.PlaneGeometry( frame.width, frame.height );
+			const mesh = new THREE.Mesh( plane, material );
+			scene.add( mesh ); //Label for light's name
+
+			let labelCanvas, labelMesh;
+
+			if ( doRenderLabel ) {
+
+				labelCanvas = document.createElement( 'canvas' );
+				const context = labelCanvas.getContext( '2d' );
+				context.font = 'Bold 20px Arial';
+				const labelWidth = context.measureText( light.name ).width;
+				labelCanvas.width = labelWidth;
+				labelCanvas.height = 25; //25 to account for g, p, etc.
+
+				context.font = 'Bold 20px Arial';
+				context.fillStyle = 'rgba( 255, 0, 0, 1 )';
+				context.fillText( light.name, 0, 20 );
+				const labelTexture = new THREE.Texture( labelCanvas );
+				labelTexture.magFilter = THREE.LinearFilter;
+				labelTexture.minFilter = THREE.LinearFilter;
+				labelTexture.needsUpdate = true;
+				const labelMaterial = new THREE.MeshBasicMaterial( {
+					map: labelTexture,
+					side: THREE.DoubleSide
+				} );
+				labelMaterial.transparent = true;
+				const labelPlane = new THREE.PlaneGeometry( labelCanvas.width, labelCanvas.height );
+				labelMesh = new THREE.Mesh( labelPlane, labelMaterial );
+				scene.add( labelMesh );
 
-		}
+			}
 
-		function resetPosition() {
+			function resetPosition() {
 
-			scope.position.set( scope.position.x, scope.position.y );
+				scope.position.set( scope.position.x, scope.position.y );
 
-		} //- API
-		// Set to false to disable displaying this shadow map
+			} //- API
+			// Set to false to disable displaying this shadow map
 
 
-		this.enabled = true; // Set the size of the displayed shadow map on the HUD
+			this.enabled = true; // Set the size of the displayed shadow map on the HUD
 
-		this.size = {
-			width: frame.width,
-			height: frame.height,
-			set: function ( width, height ) {
+			this.size = {
+				width: frame.width,
+				height: frame.height,
+				set: function ( width, height ) {
 
-				this.width = width;
-				this.height = height;
-				mesh.scale.set( this.width / frame.width, this.height / frame.height, 1 ); //Reset the position as it is off when we scale stuff
+					this.width = width;
+					this.height = height;
+					mesh.scale.set( this.width / frame.width, this.height / frame.height, 1 ); //Reset the position as it is off when we scale stuff
 
-				resetPosition();
+					resetPosition();
 
-			}
-		}; // Set the position of the displayed shadow map on the HUD
+				}
+			}; // Set the position of the displayed shadow map on the HUD
 
-		this.position = {
-			x: frame.x,
-			y: frame.y,
-			set: function ( x, y ) {
+			this.position = {
+				x: frame.x,
+				y: frame.y,
+				set: function ( x, y ) {
 
-				this.x = x;
-				this.y = y;
-				var width = scope.size.width;
-				var height = scope.size.height;
-				mesh.position.set( - window.innerWidth / 2 + width / 2 + this.x, window.innerHeight / 2 - height / 2 - this.y, 0 );
-				if ( doRenderLabel ) labelMesh.position.set( mesh.position.x, mesh.position.y - scope.size.height / 2 + labelCanvas.height / 2, 0 );
+					this.x = x;
+					this.y = y;
+					const width = scope.size.width;
+					const height = scope.size.height;
+					mesh.position.set( - window.innerWidth / 2 + width / 2 + this.x, window.innerHeight / 2 - height / 2 - this.y, 0 );
+					if ( doRenderLabel ) labelMesh.position.set( mesh.position.x, mesh.position.y - scope.size.height / 2 + labelCanvas.height / 2, 0 );
 
-			}
-		};
+				}
+			};
 
-		this.render = function ( renderer ) {
+			this.render = function ( renderer ) {
 
-			if ( this.enabled ) {
+				if ( this.enabled ) {
 
-				//Because a light's .shadowMap is only initialised after the first render pass
-				//we have to make sure the correct map is sent into the shader, otherwise we
-				//always end up with the scene's first added shadow casting light's shadowMap
-				//in the shader
-				//See: https://github.com/mrdoob/three.js/issues/5932
-				uniforms.tDiffuse.value = light.shadow.map.texture;
-				userAutoClearSetting = renderer.autoClear;
-				renderer.autoClear = false; // To allow render overlay
+					//Because a light's .shadowMap is only initialised after the first render pass
+					//we have to make sure the correct map is sent into the shader, otherwise we
+					//always end up with the scene's first added shadow casting light's shadowMap
+					//in the shader
+					//See: https://github.com/mrdoob/three.js/issues/5932
+					uniforms.tDiffuse.value = light.shadow.map.texture;
+					userAutoClearSetting = renderer.autoClear;
+					renderer.autoClear = false; // To allow render overlay
 
-				renderer.clearDepth();
-				renderer.render( scene, camera );
-				renderer.autoClear = userAutoClearSetting; //Restore user's setting
+					renderer.clearDepth();
+					renderer.render( scene, camera );
+					renderer.autoClear = userAutoClearSetting; //Restore user's setting
 
-			}
+				}
 
-		};
+			};
 
-		this.updateForWindowResize = function () {
+			this.updateForWindowResize = function () {
 
-			if ( this.enabled ) {
+				if ( this.enabled ) {
 
-				camera.left = window.innerWidth / - 2;
-				camera.right = window.innerWidth / 2;
-				camera.top = window.innerHeight / 2;
-				camera.bottom = window.innerHeight / - 2;
-				camera.updateProjectionMatrix();
-				this.update();
+					camera.left = window.innerWidth / - 2;
+					camera.right = window.innerWidth / 2;
+					camera.top = window.innerHeight / 2;
+					camera.bottom = window.innerHeight / - 2;
+					camera.updateProjectionMatrix();
+					this.update();
 
-			}
+				}
 
-		};
+			};
 
-		this.update = function () {
+			this.update = function () {
 
-			this.position.set( this.position.x, this.position.y );
-			this.size.set( this.size.width, this.size.height );
+				this.position.set( this.position.x, this.position.y );
+				this.size.set( this.size.width, this.size.height );
 
-		}; //Force an update to set position/size
+			}; //Force an update to set position/size
 
 
-		this.update();
+			this.update();
 
-	};
+		}
 
-	ShadowMapViewer.prototype.constructor = ShadowMapViewer;
+	}
 
 	THREE.ShadowMapViewer = ShadowMapViewer;
 

+ 187 - 200
examples/js/utils/SkeletonUtils.js

@@ -1,184 +1,175 @@
 ( function () {
 
-	var SkeletonUtils = {
-		retarget: function () {
+	class SkeletonUtils {
 
-			var pos = new THREE.Vector3(),
+		static retarget( target, source, options = {} ) {
+
+			const pos = new THREE.Vector3(),
 				quat = new THREE.Quaternion(),
 				scale = new THREE.Vector3(),
 				bindBoneMatrix = new THREE.Matrix4(),
 				relativeMatrix = new THREE.Matrix4(),
 				globalMatrix = new THREE.Matrix4();
-			return function ( target, source, options ) {
-
-				options = options || {};
-				options.preserveMatrix = options.preserveMatrix !== undefined ? options.preserveMatrix : true;
-				options.preservePosition = options.preservePosition !== undefined ? options.preservePosition : true;
-				options.preserveHipPosition = options.preserveHipPosition !== undefined ? options.preserveHipPosition : false;
-				options.useTargetMatrix = options.useTargetMatrix !== undefined ? options.useTargetMatrix : false;
-				options.hip = options.hip !== undefined ? options.hip : 'hip';
-				options.names = options.names || {};
-				var sourceBones = source.isObject3D ? source.skeleton.bones : this.getBones( source ),
-					bones = target.isObject3D ? target.skeleton.bones : this.getBones( target ),
-					bindBones,
-					bone,
-					name,
-					boneTo,
-					bonesPosition,
-					i; // reset bones
-
-				if ( target.isObject3D ) {
-
-					target.skeleton.pose();
+			options.preserveMatrix = options.preserveMatrix !== undefined ? options.preserveMatrix : true;
+			options.preservePosition = options.preservePosition !== undefined ? options.preservePosition : true;
+			options.preserveHipPosition = options.preserveHipPosition !== undefined ? options.preserveHipPosition : false;
+			options.useTargetMatrix = options.useTargetMatrix !== undefined ? options.useTargetMatrix : false;
+			options.hip = options.hip !== undefined ? options.hip : 'hip';
+			options.names = options.names || {};
+			const sourceBones = source.isObject3D ? source.skeleton.bones : this.getBones( source ),
+				bones = target.isObject3D ? target.skeleton.bones : this.getBones( target );
+			let bindBones, bone, name, boneTo, bonesPosition; // reset bones
+
+			if ( target.isObject3D ) {
 
-				} else {
+				target.skeleton.pose();
 
-					options.useTargetMatrix = true;
-					options.preserveMatrix = false;
+			} else {
 
-				}
+				options.useTargetMatrix = true;
+				options.preserveMatrix = false;
 
-				if ( options.preservePosition ) {
+			}
 
-					bonesPosition = [];
+			if ( options.preservePosition ) {
 
-					for ( i = 0; i < bones.length; i ++ ) {
+				bonesPosition = [];
 
-						bonesPosition.push( bones[ i ].position.clone() );
+				for ( let i = 0; i < bones.length; i ++ ) {
 
-					}
+					bonesPosition.push( bones[ i ].position.clone() );
 
 				}
 
-				if ( options.preserveMatrix ) {
+			}
 
-					// reset matrix
-					target.updateMatrixWorld();
-					target.matrixWorld.identity(); // reset children matrix
+			if ( options.preserveMatrix ) {
 
-					for ( i = 0; i < target.children.length; ++ i ) {
+				// reset matrix
+				target.updateMatrixWorld();
+				target.matrixWorld.identity(); // reset children matrix
 
-						target.children[ i ].updateMatrixWorld( true );
+				for ( let i = 0; i < target.children.length; ++ i ) {
 
-					}
+					target.children[ i ].updateMatrixWorld( true );
 
 				}
 
-				if ( options.offsets ) {
-
-					bindBones = [];
+			}
 
-					for ( i = 0; i < bones.length; ++ i ) {
+			if ( options.offsets ) {
 
-						bone = bones[ i ];
-						name = options.names[ bone.name ] || bone.name;
+				bindBones = [];
 
-						if ( options.offsets && options.offsets[ name ] ) {
+				for ( let i = 0; i < bones.length; ++ i ) {
 
-							bone.matrix.multiply( options.offsets[ name ] );
-							bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
-							bone.updateMatrixWorld();
+					bone = bones[ i ];
+					name = options.names[ bone.name ] || bone.name;
 
-						}
+					if ( options.offsets && options.offsets[ name ] ) {
 
-						bindBones.push( bone.matrixWorld.clone() );
+						bone.matrix.multiply( options.offsets[ name ] );
+						bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
+						bone.updateMatrixWorld();
 
 					}
 
+					bindBones.push( bone.matrixWorld.clone() );
+
 				}
 
-				for ( i = 0; i < bones.length; ++ i ) {
+			}
 
-					bone = bones[ i ];
-					name = options.names[ bone.name ] || bone.name;
-					boneTo = this.getBoneByName( name, sourceBones );
-					globalMatrix.copy( bone.matrixWorld );
+			for ( let i = 0; i < bones.length; ++ i ) {
 
-					if ( boneTo ) {
+				bone = bones[ i ];
+				name = options.names[ bone.name ] || bone.name;
+				boneTo = this.getBoneByName( name, sourceBones );
+				globalMatrix.copy( bone.matrixWorld );
 
-						boneTo.updateMatrixWorld();
+				if ( boneTo ) {
 
-						if ( options.useTargetMatrix ) {
+					boneTo.updateMatrixWorld();
 
-							relativeMatrix.copy( boneTo.matrixWorld );
+					if ( options.useTargetMatrix ) {
 
-						} else {
+						relativeMatrix.copy( boneTo.matrixWorld );
 
-							relativeMatrix.copy( target.matrixWorld ).invert();
-							relativeMatrix.multiply( boneTo.matrixWorld );
-
-						} // ignore scale to extract rotation
+					} else {
 
+						relativeMatrix.copy( target.matrixWorld ).invert();
+						relativeMatrix.multiply( boneTo.matrixWorld );
 
-						scale.setFromMatrixScale( relativeMatrix );
-						relativeMatrix.scale( scale.set( 1 / scale.x, 1 / scale.y, 1 / scale.z ) ); // apply to global matrix
+					} // ignore scale to extract rotation
 
-						globalMatrix.makeRotationFromQuaternion( quat.setFromRotationMatrix( relativeMatrix ) );
 
-						if ( target.isObject3D ) {
+					scale.setFromMatrixScale( relativeMatrix );
+					relativeMatrix.scale( scale.set( 1 / scale.x, 1 / scale.y, 1 / scale.z ) ); // apply to global matrix
 
-							var boneIndex = bones.indexOf( bone ),
-								wBindMatrix = bindBones ? bindBones[ boneIndex ] : bindBoneMatrix.copy( target.skeleton.boneInverses[ boneIndex ] ).invert();
-							globalMatrix.multiply( wBindMatrix );
+					globalMatrix.makeRotationFromQuaternion( quat.setFromRotationMatrix( relativeMatrix ) );
 
-						}
+					if ( target.isObject3D ) {
 
-						globalMatrix.copyPosition( relativeMatrix );
+						const boneIndex = bones.indexOf( bone ),
+							wBindMatrix = bindBones ? bindBones[ boneIndex ] : bindBoneMatrix.copy( target.skeleton.boneInverses[ boneIndex ] ).invert();
+						globalMatrix.multiply( wBindMatrix );
 
 					}
 
-					if ( bone.parent && bone.parent.isBone ) {
+					globalMatrix.copyPosition( relativeMatrix );
 
-						bone.matrix.copy( bone.parent.matrixWorld ).invert();
-						bone.matrix.multiply( globalMatrix );
+				}
 
-					} else {
+				if ( bone.parent && bone.parent.isBone ) {
 
-						bone.matrix.copy( globalMatrix );
+					bone.matrix.copy( bone.parent.matrixWorld ).invert();
+					bone.matrix.multiply( globalMatrix );
 
-					}
+				} else {
 
-					if ( options.preserveHipPosition && name === options.hip ) {
+					bone.matrix.copy( globalMatrix );
 
-						bone.matrix.setPosition( pos.set( 0, bone.position.y, 0 ) );
+				}
 
-					}
+				if ( options.preserveHipPosition && name === options.hip ) {
 
-					bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
-					bone.updateMatrixWorld();
+					bone.matrix.setPosition( pos.set( 0, bone.position.y, 0 ) );
 
 				}
 
-				if ( options.preservePosition ) {
+				bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
+				bone.updateMatrixWorld();
 
-					for ( i = 0; i < bones.length; ++ i ) {
+			}
 
-						bone = bones[ i ];
-						name = options.names[ bone.name ] || bone.name;
+			if ( options.preservePosition ) {
 
-						if ( name !== options.hip ) {
+				for ( let i = 0; i < bones.length; ++ i ) {
 
-							bone.position.copy( bonesPosition[ i ] );
+					bone = bones[ i ];
+					name = options.names[ bone.name ] || bone.name;
 
-						}
+					if ( name !== options.hip ) {
+
+						bone.position.copy( bonesPosition[ i ] );
 
 					}
 
 				}
 
-				if ( options.preserveMatrix ) {
+			}
+
+			if ( options.preserveMatrix ) {
 
-					// restore matrix
-					target.updateMatrixWorld( true );
+				// restore matrix
+				target.updateMatrixWorld( true );
 
-				}
+			}
 
-			};
+		}
 
-		}(),
-		retargetClip: function ( target, source, clip, options ) {
+		static retargetClip( target, source, clip, options = {} ) {
 
-			options = options || {};
 			options.useFirstFramePosition = options.useFirstFramePosition !== undefined ? options.useFirstFramePosition : false;
 			options.fps = options.fps !== undefined ? options.fps : 30;
 			options.names = options.names || [];
@@ -189,29 +180,23 @@
 
 			}
 
-			var numFrames = Math.round( clip.duration * ( options.fps / 1000 ) * 1000 ),
+			const numFrames = Math.round( clip.duration * ( options.fps / 1000 ) * 1000 ),
 				delta = 1 / options.fps,
 				convertedTracks = [],
 				mixer = new THREE.AnimationMixer( source ),
 				bones = this.getBones( target.skeleton ),
-				boneDatas = [],
-				positionOffset,
-				bone,
-				boneTo,
-				boneData,
-				name,
-				i,
-				j;
+				boneDatas = [];
+			let positionOffset, bone, boneTo, boneData, name;
 			mixer.clipAction( clip ).play();
 			mixer.update( 0 );
 			source.updateMatrixWorld();
 
-			for ( i = 0; i < numFrames; ++ i ) {
+			for ( let i = 0; i < numFrames; ++ i ) {
 
-				var time = i * delta;
+				const time = i * delta;
 				this.retarget( target, source, options );
 
-				for ( j = 0; j < bones.length; ++ j ) {
+				for ( let j = 0; j < bones.length; ++ j ) {
 
 					name = options.names[ bones[ j ].name ] || bones[ j ].name;
 					boneTo = this.getBoneByName( name, source.skeleton );
@@ -272,7 +257,7 @@
 
 			}
 
-			for ( i = 0; i < boneDatas.length; ++ i ) {
+			for ( let i = 0; i < boneDatas.length; ++ i ) {
 
 				boneData = boneDatas[ i ];
 
@@ -293,86 +278,81 @@
 			mixer.uncacheAction( clip );
 			return new THREE.AnimationClip( clip.name, - 1, convertedTracks );
 
-		},
-		getHelperFromSkeleton: function ( skeleton ) {
+		}
 
-			var source = new THREE.SkeletonHelper( skeleton.bones[ 0 ] );
+		static getHelperFromSkeleton( skeleton ) {
+
+			const source = new THREE.SkeletonHelper( skeleton.bones[ 0 ] );
 			source.skeleton = skeleton;
 			return source;
 
-		},
-		getSkeletonOffsets: function () {
+		}
+
+		static getSkeletonOffsets( target, source, options = {} ) {
 
-			var targetParentPos = new THREE.Vector3(),
+			const targetParentPos = new THREE.Vector3(),
 				targetPos = new THREE.Vector3(),
 				sourceParentPos = new THREE.Vector3(),
 				sourcePos = new THREE.Vector3(),
 				targetDir = new THREE.Vector2(),
 				sourceDir = new THREE.Vector2();
-			return function ( target, source, options ) {
-
-				options = options || {};
-				options.hip = options.hip !== undefined ? options.hip : 'hip';
-				options.names = options.names || {};
-
-				if ( ! source.isObject3D ) {
-
-					source = this.getHelperFromSkeleton( source );
-
-				}
+			options.hip = options.hip !== undefined ? options.hip : 'hip';
+			options.names = options.names || {};
 
-				var nameKeys = Object.keys( options.names ),
-					nameValues = Object.values( options.names ),
-					sourceBones = source.isObject3D ? source.skeleton.bones : this.getBones( source ),
-					bones = target.isObject3D ? target.skeleton.bones : this.getBones( target ),
-					offsets = [],
-					bone,
-					boneTo,
-					name,
-					i;
-				target.skeleton.pose();
+			if ( ! source.isObject3D ) {
 
-				for ( i = 0; i < bones.length; ++ i ) {
+				source = this.getHelperFromSkeleton( source );
 
-					bone = bones[ i ];
-					name = options.names[ bone.name ] || bone.name;
-					boneTo = this.getBoneByName( name, sourceBones );
-
-					if ( boneTo && name !== options.hip ) {
-
-						var boneParent = this.getNearestBone( bone.parent, nameKeys ),
-							boneToParent = this.getNearestBone( boneTo.parent, nameValues );
-						boneParent.updateMatrixWorld();
-						boneToParent.updateMatrixWorld();
-						targetParentPos.setFromMatrixPosition( boneParent.matrixWorld );
-						targetPos.setFromMatrixPosition( bone.matrixWorld );
-						sourceParentPos.setFromMatrixPosition( boneToParent.matrixWorld );
-						sourcePos.setFromMatrixPosition( boneTo.matrixWorld );
-						targetDir.subVectors( new THREE.Vector2( targetPos.x, targetPos.y ), new THREE.Vector2( targetParentPos.x, targetParentPos.y ) ).normalize();
-						sourceDir.subVectors( new THREE.Vector2( sourcePos.x, sourcePos.y ), new THREE.Vector2( sourceParentPos.x, sourceParentPos.y ) ).normalize();
-						var laterialAngle = targetDir.angle() - sourceDir.angle();
-						var offset = new THREE.Matrix4().makeRotationFromEuler( new THREE.Euler( 0, 0, laterialAngle ) );
-						bone.matrix.multiply( offset );
-						bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
-						bone.updateMatrixWorld();
-						offsets[ name ] = offset;
+			}
 
-					}
+			const nameKeys = Object.keys( options.names ),
+				nameValues = Object.values( options.names ),
+				sourceBones = source.isObject3D ? source.skeleton.bones : this.getBones( source ),
+				bones = target.isObject3D ? target.skeleton.bones : this.getBones( target ),
+				offsets = [];
+			let bone, boneTo, name, i;
+			target.skeleton.pose();
+
+			for ( i = 0; i < bones.length; ++ i ) {
+
+				bone = bones[ i ];
+				name = options.names[ bone.name ] || bone.name;
+				boneTo = this.getBoneByName( name, sourceBones );
+
+				if ( boneTo && name !== options.hip ) {
+
+					const boneParent = this.getNearestBone( bone.parent, nameKeys ),
+						boneToParent = this.getNearestBone( boneTo.parent, nameValues );
+					boneParent.updateMatrixWorld();
+					boneToParent.updateMatrixWorld();
+					targetParentPos.setFromMatrixPosition( boneParent.matrixWorld );
+					targetPos.setFromMatrixPosition( bone.matrixWorld );
+					sourceParentPos.setFromMatrixPosition( boneToParent.matrixWorld );
+					sourcePos.setFromMatrixPosition( boneTo.matrixWorld );
+					targetDir.subVectors( new THREE.Vector2( targetPos.x, targetPos.y ), new THREE.Vector2( targetParentPos.x, targetParentPos.y ) ).normalize();
+					sourceDir.subVectors( new THREE.Vector2( sourcePos.x, sourcePos.y ), new THREE.Vector2( sourceParentPos.x, sourceParentPos.y ) ).normalize();
+					const laterialAngle = targetDir.angle() - sourceDir.angle();
+					const offset = new THREE.Matrix4().makeRotationFromEuler( new THREE.Euler( 0, 0, laterialAngle ) );
+					bone.matrix.multiply( offset );
+					bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
+					bone.updateMatrixWorld();
+					offsets[ name ] = offset;
 
 				}
 
-				return offsets;
+			}
 
-			};
+			return offsets;
+
+		}
 
-		}(),
-		renameBones: function ( skeleton, names ) {
+		static renameBones( skeleton, names ) {
 
-			var bones = this.getBones( skeleton );
+			const bones = this.getBones( skeleton );
 
-			for ( var i = 0; i < bones.length; ++ i ) {
+			for ( let i = 0; i < bones.length; ++ i ) {
 
-				var bone = bones[ i ];
+				const bone = bones[ i ];
 
 				if ( names[ bone.name ] ) {
 
@@ -384,22 +364,25 @@
 
 			return this;
 
-		},
-		getBones: function ( skeleton ) {
+		}
+
+		static getBones( skeleton ) {
 
 			return Array.isArray( skeleton ) ? skeleton : skeleton.bones;
 
-		},
-		getBoneByName: function ( name, skeleton ) {
+		}
 
-			for ( var i = 0, bones = this.getBones( skeleton ); i < bones.length; i ++ ) {
+		static getBoneByName( name, skeleton ) {
+
+			for ( let i = 0, bones = this.getBones( skeleton ); i < bones.length; i ++ ) {
 
 				if ( name === bones[ i ].name ) return bones[ i ];
 
 			}
 
-		},
-		getNearestBone: function ( bone, names ) {
+		}
+
+		static getNearestBone( bone, names ) {
 
 			while ( bone.isBone ) {
 
@@ -413,19 +396,20 @@
 
 			}
 
-		},
-		findBoneTrackData: function ( name, tracks ) {
+		}
+
+		static findBoneTrackData( name, tracks ) {
 
-			var regexp = /\[(.*)\]\.(.*)/,
+			const regexp = /\[(.*)\]\.(.*)/,
 				result = {
 					name: name
 				};
 
-			for ( var i = 0; i < tracks.length; ++ i ) {
+			for ( let i = 0; i < tracks.length; ++ i ) {
 
 				// 1 is track name
 				// 2 is track type
-				var trackData = regexp.exec( tracks[ i ].name );
+				const trackData = regexp.exec( tracks[ i ].name );
 
 				if ( trackData && name === trackData[ 1 ] ) {
 
@@ -437,18 +421,19 @@
 
 			return result;
 
-		},
-		getEqualsBonesNames: function ( skeleton, targetSkeleton ) {
+		}
+
+		static getEqualsBonesNames( skeleton, targetSkeleton ) {
 
-			var sourceBones = this.getBones( skeleton ),
+			const sourceBones = this.getBones( skeleton ),
 				targetBones = this.getBones( targetSkeleton ),
 				bones = [];
 
-			search: for ( var i = 0; i < sourceBones.length; i ++ ) {
+			search: for ( let i = 0; i < sourceBones.length; i ++ ) {
 
-				var boneName = sourceBones[ i ].name;
+				const boneName = sourceBones[ i ].name;
 
-				for ( var j = 0; j < targetBones.length; j ++ ) {
+				for ( let j = 0; j < targetBones.length; j ++ ) {
 
 					if ( boneName === targetBones[ j ].name ) {
 
@@ -463,12 +448,13 @@
 
 			return bones;
 
-		},
-		clone: function ( source ) {
+		}
+
+		static clone( source ) {
 
-			var sourceLookup = new Map();
-			var cloneLookup = new Map();
-			var clone = source.clone();
+			const sourceLookup = new Map();
+			const cloneLookup = new Map();
+			const clone = source.clone();
 			parallelTraverse( source, clone, function ( sourceNode, clonedNode ) {
 
 				sourceLookup.set( clonedNode, sourceNode );
@@ -478,9 +464,9 @@
 			clone.traverse( function ( node ) {
 
 				if ( ! node.isSkinnedMesh ) return;
-				var clonedMesh = node;
-				var sourceMesh = sourceLookup.get( node );
-				var sourceBones = sourceMesh.skeleton.bones;
+				const clonedMesh = node;
+				const sourceMesh = sourceLookup.get( node );
+				const sourceBones = sourceMesh.skeleton.bones;
 				clonedMesh.skeleton = sourceMesh.skeleton.clone();
 				clonedMesh.bindMatrix.copy( sourceMesh.bindMatrix );
 				clonedMesh.skeleton.bones = sourceBones.map( function ( bone ) {
@@ -494,13 +480,14 @@
 			return clone;
 
 		}
-	};
+
+	}
 
 	function parallelTraverse( a, b, callback ) {
 
 		callback( a, b );
 
-		for ( var i = 0; i < a.children.length; i ++ ) {
+		for ( let i = 0; i < a.children.length; i ++ ) {
 
 			parallelTraverse( a.children[ i ], b.children[ i ], callback );
 

+ 21 - 21
examples/js/utils/UVsDebug.js

@@ -8,21 +8,21 @@
  *
  */
 
-	var UVsDebug = function ( geometry, size ) {
+	function UVsDebug( geometry, size = 1024 ) {
 
 		// handles wrapping of uv.x > 1 only
-		var abc = 'abc';
-		var a = new THREE.Vector2();
-		var b = new THREE.Vector2();
-		var uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ];
-		var face = [];
-		var canvas = document.createElement( 'canvas' );
-		var width = size || 1024; // power of 2 required for wrapping
-
-		var height = size || 1024;
+		const abc = 'abc';
+		const a = new THREE.Vector2();
+		const b = new THREE.Vector2();
+		const uvs = [ new THREE.Vector2(), new THREE.Vector2(), new THREE.Vector2() ];
+		const face = [];
+		const canvas = document.createElement( 'canvas' );
+		const width = size; // power of 2 required for wrapping
+
+		const height = size;
 		canvas.width = width;
 		canvas.height = height;
-		var ctx = canvas.getContext( '2d' );
+		const ctx = canvas.getContext( '2d' );
 		ctx.lineWidth = 1;
 		ctx.strokeStyle = 'rgb( 63, 63, 63 )';
 		ctx.textAlign = 'center'; // paint background white
@@ -37,13 +37,13 @@
 
 		} else {
 
-			var index = geometry.index;
-			var uvAttribute = geometry.attributes.uv;
+			const index = geometry.index;
+			const uvAttribute = geometry.attributes.uv;
 
 			if ( index ) {
 
 				// indexed geometry
-				for ( var i = 0, il = index.count; i < il; i += 3 ) {
+				for ( let i = 0, il = index.count; i < il; i += 3 ) {
 
 					face[ 0 ] = index.getX( i );
 					face[ 1 ] = index.getX( i + 1 );
@@ -58,7 +58,7 @@
 			} else {
 
 				// non-indexed geometry
-				for ( var i = 0, il = uvAttribute.count; i < il; i += 3 ) {
+				for ( let i = 0, il = uvAttribute.count; i < il; i += 3 ) {
 
 					face[ 0 ] = i;
 					face[ 1 ] = i + 1;
@@ -82,9 +82,9 @@
 			ctx.beginPath();
 			a.set( 0, 0 );
 
-			for ( var j = 0, jl = uvs.length; j < jl; j ++ ) {
+			for ( let j = 0, jl = uvs.length; j < jl; j ++ ) {
 
-				var uv = uvs[ j ];
+				const uv = uvs[ j ];
 				a.x += uv.x;
 				a.y += uv.y;
 
@@ -120,11 +120,11 @@
 			ctx.font = '12px Arial';
 			ctx.fillStyle = 'rgb( 191, 191, 191 )'; // label uv edge orders
 
-			for ( j = 0, jl = uvs.length; j < jl; j ++ ) {
+			for ( let j = 0, jl = uvs.length; j < jl; j ++ ) {
 
-				var uv = uvs[ j ];
+				const uv = uvs[ j ];
 				b.addVectors( a, uv ).divideScalar( 2 );
-				var vnum = face[ j ];
+				const vnum = face[ j ];
 				ctx.fillText( abc[ j ] + vnum, b.x * width, ( 1 - b.y ) * height );
 
 				if ( b.x > 0.95 ) {
@@ -138,7 +138,7 @@
 
 		}
 
-	};
+	}
 
 	THREE.UVsDebug = UVsDebug;
 

+ 158 - 158
examples/jsm/utils/BufferGeometryUtils.js

@@ -10,40 +10,40 @@ import {
 	Vector3
 } from '../../../build/three.module.js';
 
-var BufferGeometryUtils = {
+class BufferGeometryUtils {
 
-	computeTangents: function ( geometry ) {
+	static computeTangents( geometry ) {
 
 		geometry.computeTangents();
 		console.warn( 'THREE.BufferGeometryUtils: .computeTangents() has been removed. Use BufferGeometry.computeTangents() instead.' );
 
-	},
+	}
 
 	/**
 	 * @param  {Array<BufferGeometry>} geometries
 	 * @param  {Boolean} useGroups
 	 * @return {BufferGeometry}
 	 */
-	mergeBufferGeometries: function ( geometries, useGroups ) {
+	static mergeBufferGeometries( geometries, useGroups = false ) {
 
-		var isIndexed = geometries[ 0 ].index !== null;
+		const isIndexed = geometries[ 0 ].index !== null;
 
-		var attributesUsed = new Set( Object.keys( geometries[ 0 ].attributes ) );
-		var morphAttributesUsed = new Set( Object.keys( geometries[ 0 ].morphAttributes ) );
+		const attributesUsed = new Set( Object.keys( geometries[ 0 ].attributes ) );
+		const morphAttributesUsed = new Set( Object.keys( geometries[ 0 ].morphAttributes ) );
 
-		var attributes = {};
-		var morphAttributes = {};
+		const attributes = {};
+		const morphAttributes = {};
 
-		var morphTargetsRelative = geometries[ 0 ].morphTargetsRelative;
+		const morphTargetsRelative = geometries[ 0 ].morphTargetsRelative;
 
-		var mergedGeometry = new BufferGeometry();
+		const mergedGeometry = new BufferGeometry();
 
-		var offset = 0;
+		let offset = 0;
 
-		for ( var i = 0; i < geometries.length; ++ i ) {
+		for ( let i = 0; i < geometries.length; ++ i ) {
 
-			var geometry = geometries[ i ];
-			var attributesCount = 0;
+			const geometry = geometries[ i ];
+			let attributesCount = 0;
 
 			// ensure that all geometries are indexed, or none
 
@@ -56,7 +56,7 @@ var BufferGeometryUtils = {
 
 			// gather attributes, exit early if they're different
 
-			for ( var name in geometry.attributes ) {
+			for ( const name in geometry.attributes ) {
 
 				if ( ! attributesUsed.has( name ) ) {
 
@@ -91,7 +91,7 @@ var BufferGeometryUtils = {
 
 			}
 
-			for ( var name in geometry.morphAttributes ) {
+			for ( const name in geometry.morphAttributes ) {
 
 				if ( ! morphAttributesUsed.has( name ) ) {
 
@@ -113,7 +113,7 @@ var BufferGeometryUtils = {
 
 			if ( useGroups ) {
 
-				var count;
+				let count;
 
 				if ( isIndexed ) {
 
@@ -142,14 +142,14 @@ var BufferGeometryUtils = {
 
 		if ( isIndexed ) {
 
-			var indexOffset = 0;
-			var mergedIndex = [];
+			let indexOffset = 0;
+			const mergedIndex = [];
 
-			for ( var i = 0; i < geometries.length; ++ i ) {
+			for ( let i = 0; i < geometries.length; ++ i ) {
 
-				var index = geometries[ i ].index;
+				const index = geometries[ i ].index;
 
-				for ( var j = 0; j < index.count; ++ j ) {
+				for ( let j = 0; j < index.count; ++ j ) {
 
 					mergedIndex.push( index.getX( j ) + indexOffset );
 
@@ -165,9 +165,9 @@ var BufferGeometryUtils = {
 
 		// merge attributes
 
-		for ( var name in attributes ) {
+		for ( const name in attributes ) {
 
-			var mergedAttribute = this.mergeBufferAttributes( attributes[ name ] );
+			const mergedAttribute = this.mergeBufferAttributes( attributes[ name ] );
 
 			if ( ! mergedAttribute ) {
 
@@ -182,26 +182,26 @@ var BufferGeometryUtils = {
 
 		// merge morph attributes
 
-		for ( var name in morphAttributes ) {
+		for ( const name in morphAttributes ) {
 
-			var numMorphTargets = morphAttributes[ name ][ 0 ].length;
+			const numMorphTargets = morphAttributes[ name ][ 0 ].length;
 
 			if ( numMorphTargets === 0 ) break;
 
 			mergedGeometry.morphAttributes = mergedGeometry.morphAttributes || {};
 			mergedGeometry.morphAttributes[ name ] = [];
 
-			for ( var i = 0; i < numMorphTargets; ++ i ) {
+			for ( let i = 0; i < numMorphTargets; ++ i ) {
 
-				var morphAttributesToMerge = [];
+				const morphAttributesToMerge = [];
 
-				for ( var j = 0; j < morphAttributes[ name ].length; ++ j ) {
+				for ( let j = 0; j < morphAttributes[ name ].length; ++ j ) {
 
 					morphAttributesToMerge.push( morphAttributes[ name ][ j ][ i ] );
 
 				}
 
-				var mergedMorphAttribute = this.mergeBufferAttributes( morphAttributesToMerge );
+				const mergedMorphAttribute = this.mergeBufferAttributes( morphAttributesToMerge );
 
 				if ( ! mergedMorphAttribute ) {
 
@@ -218,22 +218,22 @@ var BufferGeometryUtils = {
 
 		return mergedGeometry;
 
-	},
+	}
 
 	/**
 	 * @param {Array<BufferAttribute>} attributes
 	 * @return {BufferAttribute}
 	 */
-	mergeBufferAttributes: function ( attributes ) {
+	static mergeBufferAttributes( attributes ) {
 
-		var TypedArray;
-		var itemSize;
-		var normalized;
-		var arrayLength = 0;
+		let TypedArray;
+		let itemSize;
+		let normalized;
+		let arrayLength = 0;
 
-		for ( var i = 0; i < attributes.length; ++ i ) {
+		for ( let i = 0; i < attributes.length; ++ i ) {
 
-			var attribute = attributes[ i ];
+			const attribute = attributes[ i ];
 
 			if ( attribute.isInterleavedBufferAttribute ) {
 
@@ -270,10 +270,10 @@ var BufferGeometryUtils = {
 
 		}
 
-		var array = new TypedArray( arrayLength );
-		var offset = 0;
+		const array = new TypedArray( arrayLength );
+		let offset = 0;
 
-		for ( var i = 0; i < attributes.length; ++ i ) {
+		for ( let i = 0; i < attributes.length; ++ i ) {
 
 			array.set( attributes[ i ].array, offset );
 
@@ -283,24 +283,24 @@ var BufferGeometryUtils = {
 
 		return new BufferAttribute( array, itemSize, normalized );
 
-	},
+	}
 
 	/**
 	 * @param {Array<BufferAttribute>} attributes
 	 * @return {Array<InterleavedBufferAttribute>}
 	 */
-	interleaveAttributes: function ( attributes ) {
+	static interleaveAttributes( attributes ) {
 
 		// Interleaves the provided attributes into an InterleavedBuffer and returns
 		// a set of InterleavedBufferAttributes for each attribute
-		var TypedArray;
-		var arrayLength = 0;
-		var stride = 0;
+		let TypedArray;
+		let arrayLength = 0;
+		let stride = 0;
 
 		// calculate the the length and type of the interleavedBuffer
-		for ( var i = 0, l = attributes.length; i < l; ++ i ) {
+		for ( let i = 0, l = attributes.length; i < l; ++ i ) {
 
-			var attribute = attributes[ i ];
+			const attribute = attributes[ i ];
 
 			if ( TypedArray === undefined ) TypedArray = attribute.array.constructor;
 			if ( TypedArray !== attribute.array.constructor ) {
@@ -316,27 +316,27 @@ var BufferGeometryUtils = {
 		}
 
 		// Create the set of buffer attributes
-		var interleavedBuffer = new InterleavedBuffer( new TypedArray( arrayLength ), stride );
-		var offset = 0;
-		var res = [];
-		var getters = [ 'getX', 'getY', 'getZ', 'getW' ];
-		var setters = [ 'setX', 'setY', 'setZ', 'setW' ];
-
-		for ( var j = 0, l = attributes.length; j < l; j ++ ) {
-
-			var attribute = attributes[ j ];
-			var itemSize = attribute.itemSize;
-			var count = attribute.count;
-			var iba = new InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, attribute.normalized );
+		const interleavedBuffer = new InterleavedBuffer( new TypedArray( arrayLength ), stride );
+		let offset = 0;
+		const res = [];
+		const getters = [ 'getX', 'getY', 'getZ', 'getW' ];
+		const setters = [ 'setX', 'setY', 'setZ', 'setW' ];
+
+		for ( let j = 0, l = attributes.length; j < l; j ++ ) {
+
+			const attribute = attributes[ j ];
+			const itemSize = attribute.itemSize;
+			const count = attribute.count;
+			const iba = new InterleavedBufferAttribute( interleavedBuffer, itemSize, offset, attribute.normalized );
 			res.push( iba );
 
 			offset += itemSize;
 
 			// Move the data for each attribute into the new interleavedBuffer
 			// at the appropriate offset
-			for ( var c = 0; c < count; c ++ ) {
+			for ( let c = 0; c < count; c ++ ) {
 
-				for ( var k = 0; k < itemSize; k ++ ) {
+				for ( let k = 0; k < itemSize; k ++ ) {
 
 					iba[ setters[ k ] ]( c, attribute[ getters[ k ] ]( c ) );
 
@@ -348,65 +348,65 @@ var BufferGeometryUtils = {
 
 		return res;
 
-	},
+	}
 
 	/**
 	 * @param {Array<BufferGeometry>} geometry
 	 * @return {number}
 	 */
-	estimateBytesUsed: function ( geometry ) {
+	static estimateBytesUsed( geometry ) {
 
 		// Return the estimated memory used by this geometry in bytes
 		// Calculate using itemSize, count, and BYTES_PER_ELEMENT to account
 		// for InterleavedBufferAttributes.
-		var mem = 0;
-		for ( var name in geometry.attributes ) {
+		let mem = 0;
+		for ( const name in geometry.attributes ) {
 
-			var attr = geometry.getAttribute( name );
+			const attr = geometry.getAttribute( name );
 			mem += attr.count * attr.itemSize * attr.array.BYTES_PER_ELEMENT;
 
 		}
 
-		var indices = geometry.getIndex();
+		const indices = geometry.getIndex();
 		mem += indices ? indices.count * indices.itemSize * indices.array.BYTES_PER_ELEMENT : 0;
 		return mem;
 
-	},
+	}
 
 	/**
 	 * @param {BufferGeometry} geometry
 	 * @param {number} tolerance
 	 * @return {BufferGeometry>}
 	 */
-	mergeVertices: function ( geometry, tolerance = 1e-4 ) {
+	static mergeVertices( geometry, tolerance = 1e-4 ) {
 
 		tolerance = Math.max( tolerance, Number.EPSILON );
 
 		// Generate an index buffer if the geometry doesn't have one, or optimize it
 		// if it's already available.
-		var hashToIndex = {};
-		var indices = geometry.getIndex();
-		var positions = geometry.getAttribute( 'position' );
-		var vertexCount = indices ? indices.count : positions.count;
+		const hashToIndex = {};
+		const indices = geometry.getIndex();
+		const positions = geometry.getAttribute( 'position' );
+		const vertexCount = indices ? indices.count : positions.count;
 
 		// next value for triangle indices
-		var nextIndex = 0;
+		let nextIndex = 0;
 
 		// attributes and new attribute arrays
-		var attributeNames = Object.keys( geometry.attributes );
-		var attrArrays = {};
-		var morphAttrsArrays = {};
-		var newIndices = [];
-		var getters = [ 'getX', 'getY', 'getZ', 'getW' ];
+		const attributeNames = Object.keys( geometry.attributes );
+		const attrArrays = {};
+		const morphAttrsArrays = {};
+		const newIndices = [];
+		const getters = [ 'getX', 'getY', 'getZ', 'getW' ];
 
 		// initialize the arrays
-		for ( var i = 0, l = attributeNames.length; i < l; i ++ ) {
+		for ( let i = 0, l = attributeNames.length; i < l; i ++ ) {
 
-			var name = attributeNames[ i ];
+			const name = attributeNames[ i ];
 
 			attrArrays[ name ] = [];
 
-			var morphAttr = geometry.morphAttributes[ name ];
+			const morphAttr = geometry.morphAttributes[ name ];
 			if ( morphAttr ) {
 
 				morphAttrsArrays[ name ] = new Array( morphAttr.length ).fill().map( () => [] );
@@ -416,21 +416,21 @@ var BufferGeometryUtils = {
 		}
 
 		// convert the error tolerance to an amount of decimal places to truncate to
-		var decimalShift = Math.log10( 1 / tolerance );
-		var shiftMultiplier = Math.pow( 10, decimalShift );
-		for ( var i = 0; i < vertexCount; i ++ ) {
+		const decimalShift = Math.log10( 1 / tolerance );
+		const shiftMultiplier = Math.pow( 10, decimalShift );
+		for ( let i = 0; i < vertexCount; i ++ ) {
 
-			var index = indices ? indices.getX( i ) : i;
+			const index = indices ? indices.getX( i ) : i;
 
 			// Generate a hash for the vertex attributes at the current index 'i'
-			var hash = '';
-			for ( var j = 0, l = attributeNames.length; j < l; j ++ ) {
+			let hash = '';
+			for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
 
-				var name = attributeNames[ j ];
-				var attribute = geometry.getAttribute( name );
-				var itemSize = attribute.itemSize;
+				const name = attributeNames[ j ];
+				const attribute = geometry.getAttribute( name );
+				const itemSize = attribute.itemSize;
 
-				for ( var k = 0; k < itemSize; k ++ ) {
+				for ( let k = 0; k < itemSize; k ++ ) {
 
 					// double tilde truncates the decimal value
 					hash += `${ ~ ~ ( attribute[ getters[ k ] ]( index ) * shiftMultiplier ) },`;
@@ -448,23 +448,23 @@ var BufferGeometryUtils = {
 			} else {
 
 				// copy data to the new index in the attribute arrays
-				for ( var j = 0, l = attributeNames.length; j < l; j ++ ) {
+				for ( let j = 0, l = attributeNames.length; j < l; j ++ ) {
 
-					var name = attributeNames[ j ];
-					var attribute = geometry.getAttribute( name );
-					var morphAttr = geometry.morphAttributes[ name ];
-					var itemSize = attribute.itemSize;
-					var newarray = attrArrays[ name ];
-					var newMorphArrays = morphAttrsArrays[ name ];
+					const name = attributeNames[ j ];
+					const attribute = geometry.getAttribute( name );
+					const morphAttr = geometry.morphAttributes[ name ];
+					const itemSize = attribute.itemSize;
+					const newarray = attrArrays[ name ];
+					const newMorphArrays = morphAttrsArrays[ name ];
 
-					for ( var k = 0; k < itemSize; k ++ ) {
+					for ( let k = 0; k < itemSize; k ++ ) {
 
-						var getterFunc = getters[ k ];
+						const getterFunc = getters[ k ];
 						newarray.push( attribute[ getterFunc ]( index ) );
 
 						if ( morphAttr ) {
 
-							for ( var m = 0, ml = morphAttr.length; m < ml; m ++ ) {
+							for ( let m = 0, ml = morphAttr.length; m < ml; m ++ ) {
 
 								newMorphArrays[ m ].push( morphAttr[ m ][ getterFunc ]( index ) );
 
@@ -487,25 +487,25 @@ var BufferGeometryUtils = {
 		// Generate typed arrays from new attribute arrays and update
 		// the attributeBuffers
 		const result = geometry.clone();
-		for ( var i = 0, l = attributeNames.length; i < l; i ++ ) {
+		for ( let i = 0, l = attributeNames.length; i < l; i ++ ) {
 
-			var name = attributeNames[ i ];
-			var oldAttribute = geometry.getAttribute( name );
+			const name = attributeNames[ i ];
+			const oldAttribute = geometry.getAttribute( name );
 
-			var buffer = new oldAttribute.array.constructor( attrArrays[ name ] );
-			var attribute = new BufferAttribute( buffer, oldAttribute.itemSize, oldAttribute.normalized );
+			const buffer = new oldAttribute.array.constructor( attrArrays[ name ] );
+			const attribute = new BufferAttribute( buffer, oldAttribute.itemSize, oldAttribute.normalized );
 
 			result.setAttribute( name, attribute );
 
 			// Update the attribute arrays
 			if ( name in morphAttrsArrays ) {
 
-				for ( var j = 0; j < morphAttrsArrays[ name ].length; j ++ ) {
+				for ( let j = 0; j < morphAttrsArrays[ name ].length; j ++ ) {
 
-					var oldMorphAttribute = geometry.morphAttributes[ name ][ j ];
+					const oldMorphAttribute = geometry.morphAttributes[ name ][ j ];
 
-					var buffer = new oldMorphAttribute.array.constructor( morphAttrsArrays[ name ][ j ] );
-					var morphAttribute = new BufferAttribute( buffer, oldMorphAttribute.itemSize, oldMorphAttribute.normalized );
+					const buffer = new oldMorphAttribute.array.constructor( morphAttrsArrays[ name ][ j ] );
+					const morphAttribute = new BufferAttribute( buffer, oldMorphAttribute.itemSize, oldMorphAttribute.normalized );
 					result.morphAttributes[ name ][ j ] = morphAttribute;
 
 				}
@@ -520,14 +520,14 @@ var BufferGeometryUtils = {
 
 		return result;
 
-	},
+	}
 
 	/**
 	 * @param {BufferGeometry} geometry
 	 * @param {number} drawMode
 	 * @return {BufferGeometry>}
 	 */
-	toTrianglesDrawMode: function ( geometry, drawMode ) {
+	static toTrianglesDrawMode( geometry, drawMode ) {
 
 		if ( drawMode === TrianglesDrawMode ) {
 
@@ -538,19 +538,19 @@ var BufferGeometryUtils = {
 
 		if ( drawMode === TriangleFanDrawMode || drawMode === TriangleStripDrawMode ) {
 
-			var index = geometry.getIndex();
+			let index = geometry.getIndex();
 
 			// generate index if not present
 
 			if ( index === null ) {
 
-				var indices = [];
+				const indices = [];
 
-				var position = geometry.getAttribute( 'position' );
+				const position = geometry.getAttribute( 'position' );
 
 				if ( position !== undefined ) {
 
-					for ( var i = 0; i < position.count; i ++ ) {
+					for ( let i = 0; i < position.count; i ++ ) {
 
 						indices.push( i );
 
@@ -570,14 +570,14 @@ var BufferGeometryUtils = {
 
 			//
 
-			var numberOfTriangles = index.count - 2;
-			var newIndices = [];
+			const numberOfTriangles = index.count - 2;
+			const newIndices = [];
 
 			if ( drawMode === TriangleFanDrawMode ) {
 
 				// gl.TRIANGLE_FAN
 
-				for ( var i = 1; i <= numberOfTriangles; i ++ ) {
+				for ( let i = 1; i <= numberOfTriangles; i ++ ) {
 
 					newIndices.push( index.getX( 0 ) );
 					newIndices.push( index.getX( i ) );
@@ -589,7 +589,7 @@ var BufferGeometryUtils = {
 
 				// gl.TRIANGLE_STRIP
 
-				for ( var i = 0; i < numberOfTriangles; i ++ ) {
+				for ( let i = 0; i < numberOfTriangles; i ++ ) {
 
 					if ( i % 2 === 0 ) {
 
@@ -617,7 +617,7 @@ var BufferGeometryUtils = {
 
 			// build final geometry
 
-			var newGeometry = geometry.clone();
+			const newGeometry = geometry.clone();
 			newGeometry.setIndex( newIndices );
 			newGeometry.clearGroups();
 
@@ -630,7 +630,7 @@ var BufferGeometryUtils = {
 
 		}
 
-	},
+	}
 
 	/**
 	 * Calculates the morphed attributes of a morphed/skinned BufferGeometry.
@@ -638,7 +638,7 @@ var BufferGeometryUtils = {
 	 * @param {Mesh | Line | Points} object An instance of Mesh, Line or Points.
 	 * @return {Object} An Object with original position/normal attributes and morphed ones.
 	 */
-	computeMorphedAttributes: function ( object ) {
+	static computeMorphedAttributes( object ) {
 
 		if ( object.geometry.isBufferGeometry !== true ) {
 
@@ -647,17 +647,17 @@ var BufferGeometryUtils = {
 
 		}
 
-		var _vA = new Vector3();
-		var _vB = new Vector3();
-		var _vC = new Vector3();
+		const _vA = new Vector3();
+		const _vB = new Vector3();
+		const _vC = new Vector3();
 
-		var _tempA = new Vector3();
-		var _tempB = new Vector3();
-		var _tempC = new Vector3();
+		const _tempA = new Vector3();
+		const _tempB = new Vector3();
+		const _tempC = new Vector3();
 
-		var _morphA = new Vector3();
-		var _morphB = new Vector3();
-		var _morphC = new Vector3();
+		const _morphA = new Vector3();
+		const _morphB = new Vector3();
+		const _morphC = new Vector3();
 
 		function _calculateMorphedAttributeData(
 			object,
@@ -675,7 +675,7 @@ var BufferGeometryUtils = {
 			_vB.fromBufferAttribute( attribute, b );
 			_vC.fromBufferAttribute( attribute, c );
 
-			var morphInfluences = object.morphTargetInfluences;
+			const morphInfluences = object.morphTargetInfluences;
 
 			if ( material.morphTargets && morphAttribute && morphInfluences ) {
 
@@ -683,10 +683,10 @@ var BufferGeometryUtils = {
 				_morphB.set( 0, 0, 0 );
 				_morphC.set( 0, 0, 0 );
 
-				for ( var i = 0, il = morphAttribute.length; i < il; i ++ ) {
+				for ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {
 
-					var influence = morphInfluences[ i ];
-					var morph = morphAttribute[ i ];
+					const influence = morphInfluences[ i ];
+					const morph = morphAttribute[ i ];
 
 					if ( influence === 0 ) continue;
 
@@ -736,25 +736,25 @@ var BufferGeometryUtils = {
 
 		}
 
-		var geometry = object.geometry;
-		var material = object.material;
+		const geometry = object.geometry;
+		const material = object.material;
 
-		var a, b, c;
-		var index = geometry.index;
-		var positionAttribute = geometry.attributes.position;
-		var morphPosition = geometry.morphAttributes.position;
-		var morphTargetsRelative = geometry.morphTargetsRelative;
-		var normalAttribute = geometry.attributes.normal;
-		var morphNormal = geometry.morphAttributes.position;
+		let a, b, c;
+		const index = geometry.index;
+		const positionAttribute = geometry.attributes.position;
+		const morphPosition = geometry.morphAttributes.position;
+		const morphTargetsRelative = geometry.morphTargetsRelative;
+		const normalAttribute = geometry.attributes.normal;
+		const morphNormal = geometry.morphAttributes.position;
 
-		var groups = geometry.groups;
-		var drawRange = geometry.drawRange;
-		var i, j, il, jl;
-		var group, groupMaterial;
-		var start, end;
+		const groups = geometry.groups;
+		const drawRange = geometry.drawRange;
+		let i, j, il, jl;
+		let group, groupMaterial;
+		let start, end;
 
-		var modifiedPosition = new Float32Array( positionAttribute.count * positionAttribute.itemSize );
-		var modifiedNormal = new Float32Array( normalAttribute.count * normalAttribute.itemSize );
+		const modifiedPosition = new Float32Array( positionAttribute.count * positionAttribute.itemSize );
+		const modifiedNormal = new Float32Array( normalAttribute.count * normalAttribute.itemSize );
 
 		if ( index !== null ) {
 
@@ -916,8 +916,8 @@ var BufferGeometryUtils = {
 
 		}
 
-		var morphedPositionAttribute = new Float32BufferAttribute( modifiedPosition, 3 );
-		var morphedNormalAttribute = new Float32BufferAttribute( modifiedNormal, 3 );
+		const morphedPositionAttribute = new Float32BufferAttribute( modifiedPosition, 3 );
+		const morphedNormalAttribute = new Float32BufferAttribute( modifiedNormal, 3 );
 
 		return {
 
@@ -930,6 +930,6 @@ var BufferGeometryUtils = {
 
 	}
 
-};
+}
 
 export { BufferGeometryUtils };

+ 225 - 226
examples/jsm/utils/GeometryCompressionUtils.js

@@ -16,7 +16,7 @@ import {
 	Vector3
 } from '../../../build/three.module.js';
 
-var GeometryCompressionUtils = {
+class GeometryCompressionUtils {
 
 	/**
 		 * Make the input mesh.geometry's normal attribute encoded and compressed by 3 different methods.
@@ -26,7 +26,7 @@ var GeometryCompressionUtils = {
 		 * @param {String} encodeMethod		"DEFAULT" || "OCT1Byte" || "OCT2Byte" || "ANGLES"
 		 *
 		 */
-	compressNormals: function ( mesh, encodeMethod ) {
+	static compressNormals( mesh, encodeMethod ) {
 
 		if ( ! mesh.geometry ) {
 
@@ -61,7 +61,7 @@ var GeometryCompressionUtils = {
 
 			for ( let idx = 0; idx < array.length; idx += 3 ) {
 
-				const encoded = this.EncodingFuncs.defaultEncode( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 1 );
+				const encoded = EncodingFuncs.defaultEncode( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 1 );
 
 				result[ idx + 0 ] = encoded[ 0 ];
 				result[ idx + 1 ] = encoded[ 1 ];
@@ -84,7 +84,7 @@ var GeometryCompressionUtils = {
 
 			for ( let idx = 0; idx < array.length; idx += 3 ) {
 
-				const encoded = this.EncodingFuncs.octEncodeBest( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 1 );
+				const encoded = EncodingFuncs.octEncodeBest( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 1 );
 
 				result[ idx / 3 * 2 + 0 ] = encoded[ 0 ];
 				result[ idx / 3 * 2 + 1 ] = encoded[ 1 ];
@@ -100,7 +100,7 @@ var GeometryCompressionUtils = {
 
 			for ( let idx = 0; idx < array.length; idx += 3 ) {
 
-				const encoded = this.EncodingFuncs.octEncodeBest( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 2 );
+				const encoded = EncodingFuncs.octEncodeBest( array[ idx ], array[ idx + 1 ], array[ idx + 2 ], 2 );
 
 				result[ idx / 3 * 2 + 0 ] = encoded[ 0 ];
 				result[ idx / 3 * 2 + 1 ] = encoded[ 1 ];
@@ -116,7 +116,7 @@ var GeometryCompressionUtils = {
 
 			for ( let idx = 0; idx < array.length; idx += 3 ) {
 
-				const encoded = this.EncodingFuncs.anglesEncode( array[ idx ], array[ idx + 1 ], array[ idx + 2 ] );
+				const encoded = EncodingFuncs.anglesEncode( array[ idx ], array[ idx + 1 ], array[ idx + 2 ] );
 
 				result[ idx / 3 * 2 + 0 ] = encoded[ 0 ];
 				result[ idx / 3 * 2 + 1 ] = encoded[ 1 ];
@@ -167,7 +167,7 @@ var GeometryCompressionUtils = {
 
 		}
 
-	},
+	}
 
 
 	/**
@@ -177,7 +177,7 @@ var GeometryCompressionUtils = {
 		 * @param {THREE.Mesh} mesh
 		 *
 		 */
-	compressPositions: function ( mesh ) {
+	static compressPositions( mesh ) {
 
 		if ( ! mesh.geometry ) {
 
@@ -204,7 +204,7 @@ var GeometryCompressionUtils = {
 		const array = position.array;
 		const encodingBytes = 2;
 
-		const result = this.EncodingFuncs.quantizedEncode( array, encodingBytes );
+		const result = EncodingFuncs.quantizedEncode( array, encodingBytes );
 
 		const quantized = result.quantized;
 		const decodeMat = result.decodeMat;
@@ -230,7 +230,7 @@ var GeometryCompressionUtils = {
 		mesh.material.uniforms.quantizeMatPos.value = decodeMat;
 		mesh.material.uniforms.quantizeMatPos.needsUpdate = true;
 
-	},
+	}
 
 	/**
 		 * Make the input mesh.geometry's uv attribute encoded and compressed.
@@ -239,7 +239,7 @@ var GeometryCompressionUtils = {
 		 * @param {THREE.Mesh} mesh
 		 *
 		 */
-	compressUvs: function ( mesh ) {
+	static compressUvs( mesh ) {
 
 		if ( ! mesh.geometry ) {
 
@@ -277,7 +277,7 @@ var GeometryCompressionUtils = {
 
 			for ( let i = 0; i < array.length; i += 2 ) {
 
-				const encoded = this.EncodingFuncs.defaultEncode( array[ i ], array[ i + 1 ], 0, 2 );
+				const encoded = EncodingFuncs.defaultEncode( array[ i ], array[ i + 1 ], 0, 2 );
 
 				result[ i ] = encoded[ 0 ];
 				result[ i + 1 ] = encoded[ 1 ];
@@ -300,7 +300,7 @@ var GeometryCompressionUtils = {
 		} else {
 
 			// use quantized encoding method
-			result = this.EncodingFuncs.quantizedEncodeUV( array, 2 );
+			result = EncodingFuncs.quantizedEncodeUV( array, 2 );
 
 			mesh.geometry.setAttribute( 'uv', new BufferAttribute( result.quantized, 2 ) );
 			mesh.geometry.attributes.uv.isPacked = true;
@@ -320,348 +320,347 @@ var GeometryCompressionUtils = {
 
 		}
 
-	},
+	}
 
-	EncodingFuncs: {
+}
 
-		defaultEncode: function ( x, y, z, bytes ) {
+class EncodingFuncs {
 
-			if ( bytes == 1 ) {
+	static defaultEncode( x, y, z, bytes ) {
 
-				const tmpx = Math.round( ( x + 1 ) * 0.5 * 255 );
-				const tmpy = Math.round( ( y + 1 ) * 0.5 * 255 );
-				const tmpz = Math.round( ( z + 1 ) * 0.5 * 255 );
-				return new Uint8Array( [ tmpx, tmpy, tmpz ] );
+		if ( bytes == 1 ) {
 
-			} else if ( bytes == 2 ) {
+			const tmpx = Math.round( ( x + 1 ) * 0.5 * 255 );
+			const tmpy = Math.round( ( y + 1 ) * 0.5 * 255 );
+			const tmpz = Math.round( ( z + 1 ) * 0.5 * 255 );
+			return new Uint8Array( [ tmpx, tmpy, tmpz ] );
 
-				const tmpx = Math.round( ( x + 1 ) * 0.5 * 65535 );
-				const tmpy = Math.round( ( y + 1 ) * 0.5 * 65535 );
-				const tmpz = Math.round( ( z + 1 ) * 0.5 * 65535 );
-				return new Uint16Array( [ tmpx, tmpy, tmpz ] );
+		} else if ( bytes == 2 ) {
 
-			} else {
+			const tmpx = Math.round( ( x + 1 ) * 0.5 * 65535 );
+			const tmpy = Math.round( ( y + 1 ) * 0.5 * 65535 );
+			const tmpz = Math.round( ( z + 1 ) * 0.5 * 65535 );
+			return new Uint16Array( [ tmpx, tmpy, tmpz ] );
 
-				console.error( 'number of bytes must be 1 or 2' );
+		} else {
 
-			}
+			console.error( 'number of bytes must be 1 or 2' );
 
-		},
+		}
 
-		defaultDecode: function ( array, bytes ) {
+	}
 
-			if ( bytes == 1 ) {
+	static defaultDecode( array, bytes ) {
 
-				return [
-					( ( array[ 0 ] / 255 ) * 2.0 ) - 1.0,
-					( ( array[ 1 ] / 255 ) * 2.0 ) - 1.0,
-					( ( array[ 2 ] / 255 ) * 2.0 ) - 1.0,
-				];
+		if ( bytes == 1 ) {
 
-			} else if ( bytes == 2 ) {
+			return [
+				( ( array[ 0 ] / 255 ) * 2.0 ) - 1.0,
+				( ( array[ 1 ] / 255 ) * 2.0 ) - 1.0,
+				( ( array[ 2 ] / 255 ) * 2.0 ) - 1.0,
+			];
 
-				return [
-					( ( array[ 0 ] / 65535 ) * 2.0 ) - 1.0,
-					( ( array[ 1 ] / 65535 ) * 2.0 ) - 1.0,
-					( ( array[ 2 ] / 65535 ) * 2.0 ) - 1.0,
-				];
+		} else if ( bytes == 2 ) {
 
-			} else {
+			return [
+				( ( array[ 0 ] / 65535 ) * 2.0 ) - 1.0,
+				( ( array[ 1 ] / 65535 ) * 2.0 ) - 1.0,
+				( ( array[ 2 ] / 65535 ) * 2.0 ) - 1.0,
+			];
 
-				console.error( 'number of bytes must be 1 or 2' );
+		} else {
 
-			}
+			console.error( 'number of bytes must be 1 or 2' );
 
-		},
+		}
 
-		// for `Angles` encoding
-		anglesEncode: function ( x, y, z ) {
+	}
 
-			const normal0 = parseInt( 0.5 * ( 1.0 + Math.atan2( y, x ) / Math.PI ) * 65535 );
-			const normal1 = parseInt( 0.5 * ( 1.0 + z ) * 65535 );
-			return new Uint16Array( [ normal0, normal1 ] );
+	// for `Angles` encoding
+	static anglesEncode( x, y, z ) {
 
-		},
+		const normal0 = parseInt( 0.5 * ( 1.0 + Math.atan2( y, x ) / Math.PI ) * 65535 );
+		const normal1 = parseInt( 0.5 * ( 1.0 + z ) * 65535 );
+		return new Uint16Array( [ normal0, normal1 ] );
 
-		// for `Octahedron` encoding
-		octEncodeBest: function ( x, y, z, bytes ) {
+	}
 
-			var oct, dec, best, currentCos, bestCos;
+	// for `Octahedron` encoding
+	static octEncodeBest( x, y, z, bytes ) {
 
-			// Test various combinations of ceil and floor
-			// to minimize rounding errors
-			best = oct = octEncodeVec3( x, y, z, 'floor', 'floor' );
-			dec = octDecodeVec2( oct );
-			bestCos = dot( x, y, z, dec );
+		let oct, dec, best, currentCos, bestCos;
 
-			oct = octEncodeVec3( x, y, z, 'ceil', 'floor' );
-			dec = octDecodeVec2( oct );
-			currentCos = dot( x, y, z, dec );
+		// Test various combinations of ceil and floor
+		// to minimize rounding errors
+		best = oct = octEncodeVec3( x, y, z, 'floor', 'floor' );
+		dec = octDecodeVec2( oct );
+		bestCos = dot( x, y, z, dec );
 
-			if ( currentCos > bestCos ) {
+		oct = octEncodeVec3( x, y, z, 'ceil', 'floor' );
+		dec = octDecodeVec2( oct );
+		currentCos = dot( x, y, z, dec );
 
-				best = oct;
-				bestCos = currentCos;
+		if ( currentCos > bestCos ) {
 
-			}
+			best = oct;
+			bestCos = currentCos;
 
-			oct = octEncodeVec3( x, y, z, 'floor', 'ceil' );
-			dec = octDecodeVec2( oct );
-			currentCos = dot( x, y, z, dec );
+		}
 
-			if ( currentCos > bestCos ) {
+		oct = octEncodeVec3( x, y, z, 'floor', 'ceil' );
+		dec = octDecodeVec2( oct );
+		currentCos = dot( x, y, z, dec );
 
-				best = oct;
-				bestCos = currentCos;
+		if ( currentCos > bestCos ) {
 
-			}
+			best = oct;
+			bestCos = currentCos;
 
-			oct = octEncodeVec3( x, y, z, 'ceil', 'ceil' );
-			dec = octDecodeVec2( oct );
-			currentCos = dot( x, y, z, dec );
+		}
 
-			if ( currentCos > bestCos ) {
+		oct = octEncodeVec3( x, y, z, 'ceil', 'ceil' );
+		dec = octDecodeVec2( oct );
+		currentCos = dot( x, y, z, dec );
 
-				best = oct;
+		if ( currentCos > bestCos ) {
 
-			}
+			best = oct;
 
-			return best;
+		}
 
-			function octEncodeVec3( x0, y0, z0, xfunc, yfunc ) {
+		return best;
 
-				var x = x0 / ( Math.abs( x0 ) + Math.abs( y0 ) + Math.abs( z0 ) );
-				var y = y0 / ( Math.abs( x0 ) + Math.abs( y0 ) + Math.abs( z0 ) );
+		function octEncodeVec3( x0, y0, z0, xfunc, yfunc ) {
 
-				if ( z < 0 ) {
+			let x = x0 / ( Math.abs( x0 ) + Math.abs( y0 ) + Math.abs( z0 ) );
+			let y = y0 / ( Math.abs( x0 ) + Math.abs( y0 ) + Math.abs( z0 ) );
 
-					var tempx = ( 1 - Math.abs( y ) ) * ( x >= 0 ? 1 : - 1 );
-					var tempy = ( 1 - Math.abs( x ) ) * ( y >= 0 ? 1 : - 1 );
+			if ( z < 0 ) {
 
-					x = tempx;
-					y = tempy;
+				const tempx = ( 1 - Math.abs( y ) ) * ( x >= 0 ? 1 : - 1 );
+				const tempy = ( 1 - Math.abs( x ) ) * ( y >= 0 ? 1 : - 1 );
 
-					var diff = 1 - Math.abs( x ) - Math.abs( y );
-					if ( diff > 0 ) {
+				x = tempx;
+				y = tempy;
 
-						diff += 0.001;
-						x += x > 0 ? diff / 2 : - diff / 2;
-						y += y > 0 ? diff / 2 : - diff / 2;
+				let diff = 1 - Math.abs( x ) - Math.abs( y );
+				if ( diff > 0 ) {
 
-					}
+					diff += 0.001;
+					x += x > 0 ? diff / 2 : - diff / 2;
+					y += y > 0 ? diff / 2 : - diff / 2;
 
 				}
 
-				if ( bytes == 1 ) {
-
-					return new Int8Array( [
-						Math[ xfunc ]( x * 127.5 + ( x < 0 ? 1 : 0 ) ),
-						Math[ yfunc ]( y * 127.5 + ( y < 0 ? 1 : 0 ) )
-					] );
+			}
 
-				}
+			if ( bytes == 1 ) {
 
-				if ( bytes == 2 ) {
+				return new Int8Array( [
+					Math[ xfunc ]( x * 127.5 + ( x < 0 ? 1 : 0 ) ),
+					Math[ yfunc ]( y * 127.5 + ( y < 0 ? 1 : 0 ) )
+				] );
 
-					return new Int16Array( [
-						Math[ xfunc ]( x * 32767.5 + ( x < 0 ? 1 : 0 ) ),
-						Math[ yfunc ]( y * 32767.5 + ( y < 0 ? 1 : 0 ) )
-					] );
+			}
 
-				}
+			if ( bytes == 2 ) {
 
+				return new Int16Array( [
+					Math[ xfunc ]( x * 32767.5 + ( x < 0 ? 1 : 0 ) ),
+					Math[ yfunc ]( y * 32767.5 + ( y < 0 ? 1 : 0 ) )
+				] );
 
 			}
 
-			function octDecodeVec2( oct ) {
-
-				var x = oct[ 0 ];
-				var y = oct[ 1 ];
 
-				if ( bytes == 1 ) {
+		}
 
-					x /= x < 0 ? 127 : 128;
-					y /= y < 0 ? 127 : 128;
+		function octDecodeVec2( oct ) {
 
-				} else if ( bytes == 2 ) {
+			let x = oct[ 0 ];
+			let y = oct[ 1 ];
 
-					x /= x < 0 ? 32767 : 32768;
-					y /= y < 0 ? 32767 : 32768;
+			if ( bytes == 1 ) {
 
-				}
+				x /= x < 0 ? 127 : 128;
+				y /= y < 0 ? 127 : 128;
 
+			} else if ( bytes == 2 ) {
 
-				var z = 1 - Math.abs( x ) - Math.abs( y );
+				x /= x < 0 ? 32767 : 32768;
+				y /= y < 0 ? 32767 : 32768;
 
-				if ( z < 0 ) {
+			}
 
-					var tmpx = x;
-					x = ( 1 - Math.abs( y ) ) * ( x >= 0 ? 1 : - 1 );
-					y = ( 1 - Math.abs( tmpx ) ) * ( y >= 0 ? 1 : - 1 );
 
-				}
+			const z = 1 - Math.abs( x ) - Math.abs( y );
 
-				var length = Math.sqrt( x * x + y * y + z * z );
+			if ( z < 0 ) {
 
-				return [
-					x / length,
-					y / length,
-					z / length
-				];
+				const tmpx = x;
+				x = ( 1 - Math.abs( y ) ) * ( x >= 0 ? 1 : - 1 );
+				y = ( 1 - Math.abs( tmpx ) ) * ( y >= 0 ? 1 : - 1 );
 
 			}
 
-			function dot( x, y, z, vec3 ) {
+			const length = Math.sqrt( x * x + y * y + z * z );
 
-				return x * vec3[ 0 ] + y * vec3[ 1 ] + z * vec3[ 2 ];
+			return [
+				x / length,
+				y / length,
+				z / length
+			];
 
-			}
+		}
 
-		},
+		function dot( x, y, z, vec3 ) {
 
-		quantizedEncode: function ( array, bytes ) {
+			return x * vec3[ 0 ] + y * vec3[ 1 ] + z * vec3[ 2 ];
 
-			let quantized, segments;
+		}
 
-			if ( bytes == 1 ) {
+	}
 
-				quantized = new Uint8Array( array.length );
-				segments = 255;
+	static quantizedEncode( array, bytes ) {
 
-			} else if ( bytes == 2 ) {
+		let quantized, segments;
 
-				quantized = new Uint16Array( array.length );
-				segments = 65535;
+		if ( bytes == 1 ) {
 
-			} else {
+			quantized = new Uint8Array( array.length );
+			segments = 255;
 
-				console.error( 'number of bytes error! ' );
+		} else if ( bytes == 2 ) {
 
-			}
+			quantized = new Uint16Array( array.length );
+			segments = 65535;
 
-			const decodeMat = new Matrix4();
+		} else {
 
-			const min = new Float32Array( 3 );
-			const max = new Float32Array( 3 );
+			console.error( 'number of bytes error! ' );
 
-			min[ 0 ] = min[ 1 ] = min[ 2 ] = Number.MAX_VALUE;
-			max[ 0 ] = max[ 1 ] = max[ 2 ] = - Number.MAX_VALUE;
+		}
 
-			for ( let i = 0; i < array.length; i += 3 ) {
+		const decodeMat = new Matrix4();
 
-				min[ 0 ] = Math.min( min[ 0 ], array[ i + 0 ] );
-				min[ 1 ] = Math.min( min[ 1 ], array[ i + 1 ] );
-				min[ 2 ] = Math.min( min[ 2 ], array[ i + 2 ] );
-				max[ 0 ] = Math.max( max[ 0 ], array[ i + 0 ] );
-				max[ 1 ] = Math.max( max[ 1 ], array[ i + 1 ] );
-				max[ 2 ] = Math.max( max[ 2 ], array[ i + 2 ] );
+		const min = new Float32Array( 3 );
+		const max = new Float32Array( 3 );
 
-			}
+		min[ 0 ] = min[ 1 ] = min[ 2 ] = Number.MAX_VALUE;
+		max[ 0 ] = max[ 1 ] = max[ 2 ] = - Number.MAX_VALUE;
 
-			decodeMat.scale( new Vector3(
-				( max[ 0 ] - min[ 0 ] ) / segments,
-				( max[ 1 ] - min[ 1 ] ) / segments,
-				( max[ 2 ] - min[ 2 ] ) / segments
-			) );
+		for ( let i = 0; i < array.length; i += 3 ) {
 
-			decodeMat.elements[ 12 ] = min[ 0 ];
-			decodeMat.elements[ 13 ] = min[ 1 ];
-			decodeMat.elements[ 14 ] = min[ 2 ];
+			min[ 0 ] = Math.min( min[ 0 ], array[ i + 0 ] );
+			min[ 1 ] = Math.min( min[ 1 ], array[ i + 1 ] );
+			min[ 2 ] = Math.min( min[ 2 ], array[ i + 2 ] );
+			max[ 0 ] = Math.max( max[ 0 ], array[ i + 0 ] );
+			max[ 1 ] = Math.max( max[ 1 ], array[ i + 1 ] );
+			max[ 2 ] = Math.max( max[ 2 ], array[ i + 2 ] );
 
-			decodeMat.transpose();
+		}
 
+		decodeMat.scale( new Vector3(
+			( max[ 0 ] - min[ 0 ] ) / segments,
+			( max[ 1 ] - min[ 1 ] ) / segments,
+			( max[ 2 ] - min[ 2 ] ) / segments
+		) );
 
-			const multiplier = new Float32Array( [
-				max[ 0 ] !== min[ 0 ] ? segments / ( max[ 0 ] - min[ 0 ] ) : 0,
-				max[ 1 ] !== min[ 1 ] ? segments / ( max[ 1 ] - min[ 1 ] ) : 0,
-				max[ 2 ] !== min[ 2 ] ? segments / ( max[ 2 ] - min[ 2 ] ) : 0
-			] );
+		decodeMat.elements[ 12 ] = min[ 0 ];
+		decodeMat.elements[ 13 ] = min[ 1 ];
+		decodeMat.elements[ 14 ] = min[ 2 ];
 
-			for ( let i = 0; i < array.length; i += 3 ) {
+		decodeMat.transpose();
 
-				quantized[ i + 0 ] = Math.floor( ( array[ i + 0 ] - min[ 0 ] ) * multiplier[ 0 ] );
-				quantized[ i + 1 ] = Math.floor( ( array[ i + 1 ] - min[ 1 ] ) * multiplier[ 1 ] );
-				quantized[ i + 2 ] = Math.floor( ( array[ i + 2 ] - min[ 2 ] ) * multiplier[ 2 ] );
 
-			}
+		const multiplier = new Float32Array( [
+			max[ 0 ] !== min[ 0 ] ? segments / ( max[ 0 ] - min[ 0 ] ) : 0,
+			max[ 1 ] !== min[ 1 ] ? segments / ( max[ 1 ] - min[ 1 ] ) : 0,
+			max[ 2 ] !== min[ 2 ] ? segments / ( max[ 2 ] - min[ 2 ] ) : 0
+		] );
 
-			return {
-				quantized: quantized,
-				decodeMat: decodeMat
-			};
+		for ( let i = 0; i < array.length; i += 3 ) {
 
-		},
+			quantized[ i + 0 ] = Math.floor( ( array[ i + 0 ] - min[ 0 ] ) * multiplier[ 0 ] );
+			quantized[ i + 1 ] = Math.floor( ( array[ i + 1 ] - min[ 1 ] ) * multiplier[ 1 ] );
+			quantized[ i + 2 ] = Math.floor( ( array[ i + 2 ] - min[ 2 ] ) * multiplier[ 2 ] );
 
+		}
 
-		quantizedEncodeUV: function ( array, bytes ) {
+		return {
+			quantized: quantized,
+			decodeMat: decodeMat
+		};
 
-			let quantized, segments;
+	}
 
-			if ( bytes == 1 ) {
+	static quantizedEncodeUV( array, bytes ) {
 
-				quantized = new Uint8Array( array.length );
-				segments = 255;
+		let quantized, segments;
 
-			} else if ( bytes == 2 ) {
+		if ( bytes == 1 ) {
 
-				quantized = new Uint16Array( array.length );
-				segments = 65535;
+			quantized = new Uint8Array( array.length );
+			segments = 255;
 
-			} else {
+		} else if ( bytes == 2 ) {
 
-				console.error( 'number of bytes error! ' );
+			quantized = new Uint16Array( array.length );
+			segments = 65535;
 
-			}
+		} else {
 
-			const decodeMat = new Matrix3();
+			console.error( 'number of bytes error! ' );
 
-			const min = new Float32Array( 2 );
-			const max = new Float32Array( 2 );
+		}
 
-			min[ 0 ] = min[ 1 ] = Number.MAX_VALUE;
-			max[ 0 ] = max[ 1 ] = - Number.MAX_VALUE;
+		const decodeMat = new Matrix3();
 
-			for ( let i = 0; i < array.length; i += 2 ) {
+		const min = new Float32Array( 2 );
+		const max = new Float32Array( 2 );
 
-				min[ 0 ] = Math.min( min[ 0 ], array[ i + 0 ] );
-				min[ 1 ] = Math.min( min[ 1 ], array[ i + 1 ] );
-				max[ 0 ] = Math.max( max[ 0 ], array[ i + 0 ] );
-				max[ 1 ] = Math.max( max[ 1 ], array[ i + 1 ] );
+		min[ 0 ] = min[ 1 ] = Number.MAX_VALUE;
+		max[ 0 ] = max[ 1 ] = - Number.MAX_VALUE;
 
-			}
+		for ( let i = 0; i < array.length; i += 2 ) {
 
-			decodeMat.scale(
-				( max[ 0 ] - min[ 0 ] ) / segments,
-				( max[ 1 ] - min[ 1 ] ) / segments
-			);
+			min[ 0 ] = Math.min( min[ 0 ], array[ i + 0 ] );
+			min[ 1 ] = Math.min( min[ 1 ], array[ i + 1 ] );
+			max[ 0 ] = Math.max( max[ 0 ], array[ i + 0 ] );
+			max[ 1 ] = Math.max( max[ 1 ], array[ i + 1 ] );
 
-			decodeMat.elements[ 6 ] = min[ 0 ];
-			decodeMat.elements[ 7 ] = min[ 1 ];
+		}
 
-			decodeMat.transpose();
+		decodeMat.scale(
+			( max[ 0 ] - min[ 0 ] ) / segments,
+			( max[ 1 ] - min[ 1 ] ) / segments
+		);
 
-			const multiplier = new Float32Array( [
-				max[ 0 ] !== min[ 0 ] ? segments / ( max[ 0 ] - min[ 0 ] ) : 0,
-				max[ 1 ] !== min[ 1 ] ? segments / ( max[ 1 ] - min[ 1 ] ) : 0
-			] );
+		decodeMat.elements[ 6 ] = min[ 0 ];
+		decodeMat.elements[ 7 ] = min[ 1 ];
 
-			for ( let i = 0; i < array.length; i += 2 ) {
+		decodeMat.transpose();
 
-				quantized[ i + 0 ] = Math.floor( ( array[ i + 0 ] - min[ 0 ] ) * multiplier[ 0 ] );
-				quantized[ i + 1 ] = Math.floor( ( array[ i + 1 ] - min[ 1 ] ) * multiplier[ 1 ] );
+		const multiplier = new Float32Array( [
+			max[ 0 ] !== min[ 0 ] ? segments / ( max[ 0 ] - min[ 0 ] ) : 0,
+			max[ 1 ] !== min[ 1 ] ? segments / ( max[ 1 ] - min[ 1 ] ) : 0
+		] );
 
-			}
+		for ( let i = 0; i < array.length; i += 2 ) {
 
-			return {
-				quantized: quantized,
-				decodeMat: decodeMat
-			};
+			quantized[ i + 0 ] = Math.floor( ( array[ i + 0 ] - min[ 0 ] ) * multiplier[ 0 ] );
+			quantized[ i + 1 ] = Math.floor( ( array[ i + 1 ] - min[ 1 ] ) * multiplier[ 1 ] );
 
 		}
 
+		return {
+			quantized: quantized,
+			decodeMat: decodeMat
+		};
+
 	}
 
-};
+}
 
 
 

+ 30 - 53
examples/jsm/utils/GeometryUtils.js

@@ -2,7 +2,7 @@ import {
 	Vector3
 } from '../../../build/three.module.js';
 
-var GeometryUtils = {
+class GeometryUtils {
 
 	/**
 	 * Generates 2D-Coordinates in a very fast way.
@@ -18,27 +18,18 @@ var GeometryUtils = {
 	 * @param v2         Corner index +X, +Z.
 	 * @param v3         Corner index +X, -Z.
 	 */
-	hilbert2D: function ( center, size, iterations, v0, v1, v2, v3 ) {
+	static hilbert2D( center = new Vector3( 0, 0, 0 ), size = 10, iterations = 1, v0 = 0, v1 = 1, v2 = 2, v3 = 3 ) {
 
-		// Default Vars
-		var center = center !== undefined ? center : new Vector3( 0, 0, 0 ),
-			size = size !== undefined ? size : 10,
-			half = size / 2,
-			iterations = iterations !== undefined ? iterations : 1,
-			v0 = v0 !== undefined ? v0 : 0,
-			v1 = v1 !== undefined ? v1 : 1,
-			v2 = v2 !== undefined ? v2 : 2,
-			v3 = v3 !== undefined ? v3 : 3
-		;
-
-		var vec_s = [
+		const half = size / 2;
+
+		const vec_s = [
 			new Vector3( center.x - half, center.y, center.z - half ),
 			new Vector3( center.x - half, center.y, center.z + half ),
 			new Vector3( center.x + half, center.y, center.z + half ),
 			new Vector3( center.x + half, center.y, center.z - half )
 		];
 
-		var vec = [
+		const vec = [
 			vec_s[ v0 ],
 			vec_s[ v1 ],
 			vec_s[ v2 ],
@@ -48,7 +39,7 @@ var GeometryUtils = {
 		// Recurse iterations
 		if ( 0 <= -- iterations ) {
 
-			var tmp = [];
+			const tmp = [];
 
 			Array.prototype.push.apply( tmp, GeometryUtils.hilbert2D( vec[ 0 ], half, iterations, v0, v3, v2, v1 ) );
 			Array.prototype.push.apply( tmp, GeometryUtils.hilbert2D( vec[ 1 ], half, iterations, v0, v1, v2, v3 ) );
@@ -63,7 +54,7 @@ var GeometryUtils = {
 		// Return complete Hilbert Curve.
 		return vec;
 
-	},
+	}
 
 	/**
 	 * Generates 3D-Coordinates in a very fast way.
@@ -83,24 +74,12 @@ var GeometryUtils = {
 	 * @param v6         Corner index +X, +Y, +Z.
 	 * @param v7         Corner index +X, +Y, -Z.
 	 */
-	hilbert3D: function ( center, size, iterations, v0, v1, v2, v3, v4, v5, v6, v7 ) {
+	static hilbert3D( center = new Vector3( 0, 0, 0 ), size = 10, iterations = 1, v0 = 0, v1 = 1, v2 = 2, v3 = 3, v4 = 4, v5 = 5, v6 = 6, v7 = 7 ) {
 
 		// Default Vars
-		var center = center !== undefined ? center : new Vector3( 0, 0, 0 ),
-			size = size !== undefined ? size : 10,
-			half = size / 2,
-			iterations = iterations !== undefined ? iterations : 1,
-			v0 = v0 !== undefined ? v0 : 0,
-			v1 = v1 !== undefined ? v1 : 1,
-			v2 = v2 !== undefined ? v2 : 2,
-			v3 = v3 !== undefined ? v3 : 3,
-			v4 = v4 !== undefined ? v4 : 4,
-			v5 = v5 !== undefined ? v5 : 5,
-			v6 = v6 !== undefined ? v6 : 6,
-			v7 = v7 !== undefined ? v7 : 7
-		;
-
-		var vec_s = [
+		const half = size / 2;
+
+		const vec_s = [
 			new Vector3( center.x - half, center.y + half, center.z - half ),
 			new Vector3( center.x - half, center.y + half, center.z + half ),
 			new Vector3( center.x - half, center.y - half, center.z + half ),
@@ -111,7 +90,7 @@ var GeometryUtils = {
 			new Vector3( center.x + half, center.y + half, center.z - half )
 		];
 
-		var vec = [
+		const vec = [
 			vec_s[ v0 ],
 			vec_s[ v1 ],
 			vec_s[ v2 ],
@@ -125,7 +104,7 @@ var GeometryUtils = {
 		// Recurse iterations
 		if ( -- iterations >= 0 ) {
 
-			var tmp = [];
+			const tmp = [];
 
 			Array.prototype.push.apply( tmp, GeometryUtils.hilbert3D( vec[ 0 ], half, iterations, v0, v3, v4, v7, v6, v5, v2, v1 ) );
 			Array.prototype.push.apply( tmp, GeometryUtils.hilbert3D( vec[ 1 ], half, iterations, v0, v7, v6, v1, v2, v5, v4, v3 ) );
@@ -144,7 +123,7 @@ var GeometryUtils = {
 		// Return complete Hilbert Curve.
 		return vec;
 
-	},
+	}
 
 	/**
 	 * Generates a Gosper curve (lying in the XY plane)
@@ -153,22 +132,20 @@ var GeometryUtils = {
 	 *
 	 * @param size The size of a single gosper island.
 	 */
-	gosper: function ( size ) {
-
-		size = ( size !== undefined ) ? size : 1;
+	static gosper( size = 1 ) {
 
 		function fractalize( config ) {
 
-			var output;
-			var input = config.axiom;
+			let output;
+			let input = config.axiom;
 
-			for ( var i = 0, il = config.steps; 0 <= il ? i < il : i > il; 0 <= il ? i ++ : i -- ) {
+			for ( let i = 0, il = config.steps; 0 <= il ? i < il : i > il; 0 <= il ? i ++ : i -- ) {
 
 				output = '';
 
-				for ( var j = 0, jl = input.length; j < jl; j ++ ) {
+				for ( let j = 0, jl = input.length; j < jl; j ++ ) {
 
-					var char = input[ j ];
+					const char = input[ j ];
 
 					if ( char in config.rules ) {
 
@@ -192,14 +169,14 @@ var GeometryUtils = {
 
 		function toPoints( config ) {
 
-			var currX = 0, currY = 0;
-			var angle = 0;
-			var path = [ 0, 0, 0 ];
-			var fractal = config.fractal;
+			let currX = 0, currY = 0;
+			let angle = 0;
+			const path = [ 0, 0, 0 ];
+			const fractal = config.fractal;
 
-			for ( var i = 0, l = fractal.length; i < l; i ++ ) {
+			for ( let i = 0, l = fractal.length; i < l; i ++ ) {
 
-				var char = fractal[ i ];
+				const char = fractal[ i ];
 
 				if ( char === '+' ) {
 
@@ -225,7 +202,7 @@ var GeometryUtils = {
 
 		//
 
-		var gosper = fractalize( {
+		const gosper = fractalize( {
 			axiom: 'A',
 			steps: 4,
 			rules: {
@@ -234,7 +211,7 @@ var GeometryUtils = {
 			}
 		} );
 
-		var points = toPoints( {
+		const points = toPoints( {
 			fractal: gosper,
 			size: size,
 			angle: Math.PI / 3 // 60 degrees
@@ -244,6 +221,6 @@ var GeometryUtils = {
 
 	}
 
-};
+}
 
 export { GeometryUtils };

+ 17 - 17
examples/jsm/utils/SceneUtils.js

@@ -3,19 +3,19 @@ import {
 	Mesh
 } from '../../../build/three.module.js';
 
-var SceneUtils = {
+class SceneUtils {
 
-	createMeshesFromInstancedMesh: function ( instancedMesh ) {
+	static createMeshesFromInstancedMesh( instancedMesh ) {
 
-		var group = new Group();
+		const group = new Group();
 
-		var count = instancedMesh.count;
-		var geometry = instancedMesh.geometry;
-		var material = instancedMesh.material;
+		const count = instancedMesh.count;
+		const geometry = instancedMesh.geometry;
+		const material = instancedMesh.material;
 
-		for ( var i = 0; i < count; i ++ ) {
+		for ( let i = 0; i < count; i ++ ) {
 
-			var mesh = new Mesh( geometry, material );
+			const mesh = new Mesh( geometry, material );
 
 			instancedMesh.getMatrixAt( i, mesh.matrix );
 			mesh.matrix.decompose( mesh.position, mesh.quaternion, mesh.scale );
@@ -29,13 +29,13 @@ var SceneUtils = {
 
 		return group;
 
-	},
+	}
 
-	createMultiMaterialObject: function ( geometry, materials ) {
+	static createMultiMaterialObject( geometry, materials ) {
 
-		var group = new Group();
+		const group = new Group();
 
-		for ( var i = 0, l = materials.length; i < l; i ++ ) {
+		for ( let i = 0, l = materials.length; i < l; i ++ ) {
 
 			group.add( new Mesh( geometry, materials[ i ] ) );
 
@@ -43,17 +43,17 @@ var SceneUtils = {
 
 		return group;
 
-	},
+	}
 
-	detach: function ( child, parent, scene ) {
+	static detach( child, parent, scene ) {
 
 		console.warn( 'THREE.SceneUtils: detach() has been deprecated. Use scene.attach( child ) instead.' );
 
 		scene.attach( child );
 
-	},
+	}
 
-	attach: function ( child, scene, parent ) {
+	static attach( child, scene, parent ) {
 
 		console.warn( 'THREE.SceneUtils: attach() has been deprecated. Use parent.attach( child ) instead.' );
 
@@ -61,6 +61,6 @@ var SceneUtils = {
 
 	}
 
-};
+}
 
 export { SceneUtils };

+ 117 - 114
examples/jsm/utils/ShadowMapViewer.js

@@ -21,12 +21,12 @@ import { UnpackDepthRGBAShader } from '../shaders/UnpackDepthRGBAShader.js';
  *	1) Import ShadowMapViewer into your app.
  *
  *	2) Create a shadow casting light and name it optionally:
- *		var light = new DirectionalLight( 0xffffff, 1 );
+ *		let light = new DirectionalLight( 0xffffff, 1 );
  *		light.castShadow = true;
  *		light.name = 'Sun';
  *
  *	3) Create a shadow map viewer for that light and set its size and position optionally:
- *		var shadowMapViewer = new ShadowMapViewer( light );
+ *		let shadowMapViewer = new ShadowMapViewer( light );
  *		shadowMapViewer.size.set( 128, 128 );	//width, height  default: 256, 256
  *		shadowMapViewer.position.set( 10, 10 );	//x, y in pixel	 default: 0, 0 (top left corner)
  *
@@ -39,169 +39,172 @@ import { UnpackDepthRGBAShader } from '../shaders/UnpackDepthRGBAShader.js';
  *	6) If you set the position or size members directly, you need to call shadowMapViewer.update();
  */
 
-var ShadowMapViewer = function ( light ) {
+class ShadowMapViewer {
 
-	//- Internals
-	var scope = this;
-	var doRenderLabel = ( light.name !== undefined && light.name !== '' );
-	var userAutoClearSetting;
+	constructor( light ) {
 
-	//Holds the initial position and dimension of the HUD
-	var frame = {
-		x: 10,
-		y: 10,
-		width: 256,
-		height: 256
-	};
+		//- Internals
+		const scope = this;
+		const doRenderLabel = ( light.name !== undefined && light.name !== '' );
+		let userAutoClearSetting;
 
-	var camera = new OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 10 );
-	camera.position.set( 0, 0, 2 );
-	var scene = new Scene();
+		//Holds the initial position and dimension of the HUD
+		const frame = {
+			x: 10,
+			y: 10,
+			width: 256,
+			height: 256
+		};
 
-	//HUD for shadow map
-	var shader = UnpackDepthRGBAShader;
+		const camera = new OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, 1, 10 );
+		camera.position.set( 0, 0, 2 );
+		const scene = new Scene();
 
-	var uniforms = UniformsUtils.clone( shader.uniforms );
-	var material = new ShaderMaterial( {
-		uniforms: uniforms,
-		vertexShader: shader.vertexShader,
-		fragmentShader: shader.fragmentShader
-	} );
-	var plane = new PlaneGeometry( frame.width, frame.height );
-	var mesh = new Mesh( plane, material );
+		//HUD for shadow map
+		const shader = UnpackDepthRGBAShader;
 
-	scene.add( mesh );
+		const uniforms = UniformsUtils.clone( shader.uniforms );
+		const material = new ShaderMaterial( {
+			uniforms: uniforms,
+			vertexShader: shader.vertexShader,
+			fragmentShader: shader.fragmentShader
+		} );
+		const plane = new PlaneGeometry( frame.width, frame.height );
+		const mesh = new Mesh( plane, material );
 
+		scene.add( mesh );
 
-	//Label for light's name
-	var labelCanvas, labelMesh;
 
-	if ( doRenderLabel ) {
+		//Label for light's name
+		let labelCanvas, labelMesh;
 
-		labelCanvas = document.createElement( 'canvas' );
+		if ( doRenderLabel ) {
 
-		var context = labelCanvas.getContext( '2d' );
-		context.font = 'Bold 20px Arial';
+			labelCanvas = document.createElement( 'canvas' );
 
-		var labelWidth = context.measureText( light.name ).width;
-		labelCanvas.width = labelWidth;
-		labelCanvas.height = 25;	//25 to account for g, p, etc.
+			const context = labelCanvas.getContext( '2d' );
+			context.font = 'Bold 20px Arial';
 
-		context.font = 'Bold 20px Arial';
-		context.fillStyle = 'rgba( 255, 0, 0, 1 )';
-		context.fillText( light.name, 0, 20 );
+			const labelWidth = context.measureText( light.name ).width;
+			labelCanvas.width = labelWidth;
+			labelCanvas.height = 25;	//25 to account for g, p, etc.
 
-		var labelTexture = new Texture( labelCanvas );
-		labelTexture.magFilter = LinearFilter;
-		labelTexture.minFilter = LinearFilter;
-		labelTexture.needsUpdate = true;
+			context.font = 'Bold 20px Arial';
+			context.fillStyle = 'rgba( 255, 0, 0, 1 )';
+			context.fillText( light.name, 0, 20 );
 
-		var labelMaterial = new MeshBasicMaterial( { map: labelTexture, side: DoubleSide } );
-		labelMaterial.transparent = true;
+			const labelTexture = new Texture( labelCanvas );
+			labelTexture.magFilter = LinearFilter;
+			labelTexture.minFilter = LinearFilter;
+			labelTexture.needsUpdate = true;
 
-		var labelPlane = new PlaneGeometry( labelCanvas.width, labelCanvas.height );
-		labelMesh = new Mesh( labelPlane, labelMaterial );
+			const labelMaterial = new MeshBasicMaterial( { map: labelTexture, side: DoubleSide } );
+			labelMaterial.transparent = true;
 
-		scene.add( labelMesh );
+			const labelPlane = new PlaneGeometry( labelCanvas.width, labelCanvas.height );
+			labelMesh = new Mesh( labelPlane, labelMaterial );
 
-	}
+			scene.add( labelMesh );
 
+		}
 
-	function resetPosition() {
 
-		scope.position.set( scope.position.x, scope.position.y );
+		function resetPosition() {
 
-	}
+			scope.position.set( scope.position.x, scope.position.y );
 
-	//- API
-	// Set to false to disable displaying this shadow map
-	this.enabled = true;
+		}
 
-	// Set the size of the displayed shadow map on the HUD
-	this.size = {
-		width: frame.width,
-		height: frame.height,
-		set: function ( width, height ) {
+		//- API
+		// Set to false to disable displaying this shadow map
+		this.enabled = true;
 
-			this.width = width;
-			this.height = height;
+		// Set the size of the displayed shadow map on the HUD
+		this.size = {
+			width: frame.width,
+			height: frame.height,
+			set: function ( width, height ) {
 
-			mesh.scale.set( this.width / frame.width, this.height / frame.height, 1 );
+				this.width = width;
+				this.height = height;
 
-			//Reset the position as it is off when we scale stuff
-			resetPosition();
+				mesh.scale.set( this.width / frame.width, this.height / frame.height, 1 );
 
-		}
-	};
+				//Reset the position as it is off when we scale stuff
+				resetPosition();
 
-	// Set the position of the displayed shadow map on the HUD
-	this.position = {
-		x: frame.x,
-		y: frame.y,
-		set: function ( x, y ) {
+			}
+		};
 
-			this.x = x;
-			this.y = y;
+		// Set the position of the displayed shadow map on the HUD
+		this.position = {
+			x: frame.x,
+			y: frame.y,
+			set: function ( x, y ) {
 
-			var width = scope.size.width;
-			var height = scope.size.height;
+				this.x = x;
+				this.y = y;
 
-			mesh.position.set( - window.innerWidth / 2 + width / 2 + this.x, window.innerHeight / 2 - height / 2 - this.y, 0 );
+				const width = scope.size.width;
+				const height = scope.size.height;
 
-			if ( doRenderLabel ) labelMesh.position.set( mesh.position.x, mesh.position.y - scope.size.height / 2 + labelCanvas.height / 2, 0 );
+				mesh.position.set( - window.innerWidth / 2 + width / 2 + this.x, window.innerHeight / 2 - height / 2 - this.y, 0 );
 
-		}
-	};
+				if ( doRenderLabel ) labelMesh.position.set( mesh.position.x, mesh.position.y - scope.size.height / 2 + labelCanvas.height / 2, 0 );
 
-	this.render = function ( renderer ) {
+			}
+		};
 
-		if ( this.enabled ) {
+		this.render = function ( renderer ) {
 
-			//Because a light's .shadowMap is only initialised after the first render pass
-			//we have to make sure the correct map is sent into the shader, otherwise we
-			//always end up with the scene's first added shadow casting light's shadowMap
-			//in the shader
-			//See: https://github.com/mrdoob/three.js/issues/5932
-			uniforms.tDiffuse.value = light.shadow.map.texture;
+			if ( this.enabled ) {
 
-			userAutoClearSetting = renderer.autoClear;
-			renderer.autoClear = false; // To allow render overlay
-			renderer.clearDepth();
-			renderer.render( scene, camera );
-			renderer.autoClear = userAutoClearSetting;	//Restore user's setting
+				//Because a light's .shadowMap is only initialised after the first render pass
+				//we have to make sure the correct map is sent into the shader, otherwise we
+				//always end up with the scene's first added shadow casting light's shadowMap
+				//in the shader
+				//See: https://github.com/mrdoob/three.js/issues/5932
+				uniforms.tDiffuse.value = light.shadow.map.texture;
 
-		}
+				userAutoClearSetting = renderer.autoClear;
+				renderer.autoClear = false; // To allow render overlay
+				renderer.clearDepth();
+				renderer.render( scene, camera );
+				renderer.autoClear = userAutoClearSetting;	//Restore user's setting
 
-	};
+			}
 
-	this.updateForWindowResize = function () {
+		};
 
-		if ( this.enabled ) {
+		this.updateForWindowResize = function () {
 
-			 camera.left = window.innerWidth / - 2;
-			 camera.right = window.innerWidth / 2;
-			 camera.top = window.innerHeight / 2;
-			 camera.bottom = window.innerHeight / - 2;
-			 camera.updateProjectionMatrix();
+			if ( this.enabled ) {
 
-			 this.update();
+				 camera.left = window.innerWidth / - 2;
+				 camera.right = window.innerWidth / 2;
+				 camera.top = window.innerHeight / 2;
+				 camera.bottom = window.innerHeight / - 2;
+				 camera.updateProjectionMatrix();
 
-		}
+				 this.update();
+
+			}
 
-	};
+		};
 
-	this.update = function () {
+		this.update = function () {
 
-		this.position.set( this.position.x, this.position.y );
-		this.size.set( this.size.width, this.size.height );
+			this.position.set( this.position.x, this.position.y );
+			this.size.set( this.size.width, this.size.height );
 
-	};
+		};
 
-	//Force an update to set position/size
-	this.update();
+		//Force an update to set position/size
+		this.update();
+
+	}
 
-};
+}
 
-ShadowMapViewer.prototype.constructor = ShadowMapViewer;
 
 export { ShadowMapViewer };

+ 191 - 200
examples/jsm/utils/SkeletonUtils.js

@@ -11,202 +11,197 @@ import {
 	VectorKeyframeTrack
 } from '../../../build/three.module.js';
 
-var SkeletonUtils = {
+class SkeletonUtils {
 
-	retarget: function () {
+	static retarget( target, source, options = {} ) {
 
-		var pos = new Vector3(),
+		const pos = new Vector3(),
 			quat = new Quaternion(),
 			scale = new Vector3(),
 			bindBoneMatrix = new Matrix4(),
 			relativeMatrix = new Matrix4(),
 			globalMatrix = new Matrix4();
 
-		return function ( target, source, options ) {
+		options.preserveMatrix = options.preserveMatrix !== undefined ? options.preserveMatrix : true;
+		options.preservePosition = options.preservePosition !== undefined ? options.preservePosition : true;
+		options.preserveHipPosition = options.preserveHipPosition !== undefined ? options.preserveHipPosition : false;
+		options.useTargetMatrix = options.useTargetMatrix !== undefined ? options.useTargetMatrix : false;
+		options.hip = options.hip !== undefined ? options.hip : 'hip';
+		options.names = options.names || {};
 
-			options = options || {};
-			options.preserveMatrix = options.preserveMatrix !== undefined ? options.preserveMatrix : true;
-			options.preservePosition = options.preservePosition !== undefined ? options.preservePosition : true;
-			options.preserveHipPosition = options.preserveHipPosition !== undefined ? options.preserveHipPosition : false;
-			options.useTargetMatrix = options.useTargetMatrix !== undefined ? options.useTargetMatrix : false;
-			options.hip = options.hip !== undefined ? options.hip : 'hip';
-			options.names = options.names || {};
+		const sourceBones = source.isObject3D ? source.skeleton.bones : this.getBones( source ),
+			bones = target.isObject3D ? target.skeleton.bones : this.getBones( target );
 
-			var sourceBones = source.isObject3D ? source.skeleton.bones : this.getBones( source ),
-				bones = target.isObject3D ? target.skeleton.bones : this.getBones( target ),
-				bindBones,
-				bone, name, boneTo,
-				bonesPosition, i;
+		let bindBones,
+			bone, name, boneTo,
+			bonesPosition;
 
-			// reset bones
+		// reset bones
 
-			if ( target.isObject3D ) {
+		if ( target.isObject3D ) {
 
-				target.skeleton.pose();
+			target.skeleton.pose();
 
-			} else {
+		} else {
 
-				options.useTargetMatrix = true;
-				options.preserveMatrix = false;
+			options.useTargetMatrix = true;
+			options.preserveMatrix = false;
 
-			}
+		}
 
-			if ( options.preservePosition ) {
+		if ( options.preservePosition ) {
 
-				bonesPosition = [];
+			bonesPosition = [];
 
-				for ( i = 0; i < bones.length; i ++ ) {
+			for ( let i = 0; i < bones.length; i ++ ) {
 
-					bonesPosition.push( bones[ i ].position.clone() );
-
-				}
+				bonesPosition.push( bones[ i ].position.clone() );
 
 			}
 
-			if ( options.preserveMatrix ) {
+		}
 
-				// reset matrix
+		if ( options.preserveMatrix ) {
 
-				target.updateMatrixWorld();
+			// reset matrix
 
-				target.matrixWorld.identity();
+			target.updateMatrixWorld();
 
-				// reset children matrix
+			target.matrixWorld.identity();
 
-				for ( i = 0; i < target.children.length; ++ i ) {
+			// reset children matrix
 
-					target.children[ i ].updateMatrixWorld( true );
+			for ( let i = 0; i < target.children.length; ++ i ) {
 
-				}
+				target.children[ i ].updateMatrixWorld( true );
 
 			}
 
-			if ( options.offsets ) {
-
-				bindBones = [];
+		}
 
-				for ( i = 0; i < bones.length; ++ i ) {
+		if ( options.offsets ) {
 
-					bone = bones[ i ];
-					name = options.names[ bone.name ] || bone.name;
+			bindBones = [];
 
-					if ( options.offsets && options.offsets[ name ] ) {
+			for ( let i = 0; i < bones.length; ++ i ) {
 
-						bone.matrix.multiply( options.offsets[ name ] );
+				bone = bones[ i ];
+				name = options.names[ bone.name ] || bone.name;
 
-						bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
+				if ( options.offsets && options.offsets[ name ] ) {
 
-						bone.updateMatrixWorld();
+					bone.matrix.multiply( options.offsets[ name ] );
 
-					}
+					bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
 
-					bindBones.push( bone.matrixWorld.clone() );
+					bone.updateMatrixWorld();
 
 				}
 
-			}
+				bindBones.push( bone.matrixWorld.clone() );
 
-			for ( i = 0; i < bones.length; ++ i ) {
+			}
 
-				bone = bones[ i ];
-				name = options.names[ bone.name ] || bone.name;
+		}
 
-				boneTo = this.getBoneByName( name, sourceBones );
+		for ( let i = 0; i < bones.length; ++ i ) {
 
-				globalMatrix.copy( bone.matrixWorld );
+			bone = bones[ i ];
+			name = options.names[ bone.name ] || bone.name;
 
-				if ( boneTo ) {
+			boneTo = this.getBoneByName( name, sourceBones );
 
-					boneTo.updateMatrixWorld();
+			globalMatrix.copy( bone.matrixWorld );
 
-					if ( options.useTargetMatrix ) {
+			if ( boneTo ) {
 
-						relativeMatrix.copy( boneTo.matrixWorld );
+				boneTo.updateMatrixWorld();
 
-					} else {
+				if ( options.useTargetMatrix ) {
 
-						relativeMatrix.copy( target.matrixWorld ).invert();
-						relativeMatrix.multiply( boneTo.matrixWorld );
+					relativeMatrix.copy( boneTo.matrixWorld );
 
-					}
+				} else {
 
-					// ignore scale to extract rotation
+					relativeMatrix.copy( target.matrixWorld ).invert();
+					relativeMatrix.multiply( boneTo.matrixWorld );
 
-					scale.setFromMatrixScale( relativeMatrix );
-					relativeMatrix.scale( scale.set( 1 / scale.x, 1 / scale.y, 1 / scale.z ) );
+				}
 
-					// apply to global matrix
+				// ignore scale to extract rotation
 
-					globalMatrix.makeRotationFromQuaternion( quat.setFromRotationMatrix( relativeMatrix ) );
+				scale.setFromMatrixScale( relativeMatrix );
+				relativeMatrix.scale( scale.set( 1 / scale.x, 1 / scale.y, 1 / scale.z ) );
 
-					if ( target.isObject3D ) {
+				// apply to global matrix
 
-						var boneIndex = bones.indexOf( bone ),
-							wBindMatrix = bindBones ? bindBones[ boneIndex ] : bindBoneMatrix.copy( target.skeleton.boneInverses[ boneIndex ] ).invert();
+				globalMatrix.makeRotationFromQuaternion( quat.setFromRotationMatrix( relativeMatrix ) );
 
-						globalMatrix.multiply( wBindMatrix );
+				if ( target.isObject3D ) {
 
-					}
+					const boneIndex = bones.indexOf( bone ),
+						wBindMatrix = bindBones ? bindBones[ boneIndex ] : bindBoneMatrix.copy( target.skeleton.boneInverses[ boneIndex ] ).invert();
 
-					globalMatrix.copyPosition( relativeMatrix );
+					globalMatrix.multiply( wBindMatrix );
 
 				}
 
-				if ( bone.parent && bone.parent.isBone ) {
-
-					bone.matrix.copy( bone.parent.matrixWorld ).invert();
-					bone.matrix.multiply( globalMatrix );
+				globalMatrix.copyPosition( relativeMatrix );
 
-				} else {
+			}
 
-					bone.matrix.copy( globalMatrix );
+			if ( bone.parent && bone.parent.isBone ) {
 
-				}
+				bone.matrix.copy( bone.parent.matrixWorld ).invert();
+				bone.matrix.multiply( globalMatrix );
 
-				if ( options.preserveHipPosition && name === options.hip ) {
+			} else {
 
-					bone.matrix.setPosition( pos.set( 0, bone.position.y, 0 ) );
+				bone.matrix.copy( globalMatrix );
 
-				}
+			}
 
-				bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
+			if ( options.preserveHipPosition && name === options.hip ) {
 
-				bone.updateMatrixWorld();
+				bone.matrix.setPosition( pos.set( 0, bone.position.y, 0 ) );
 
 			}
 
-			if ( options.preservePosition ) {
+			bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
 
-				for ( i = 0; i < bones.length; ++ i ) {
+			bone.updateMatrixWorld();
 
-					bone = bones[ i ];
-					name = options.names[ bone.name ] || bone.name;
+		}
 
-					if ( name !== options.hip ) {
+		if ( options.preservePosition ) {
 
-						bone.position.copy( bonesPosition[ i ] );
+			for ( let i = 0; i < bones.length; ++ i ) {
 
-					}
+				bone = bones[ i ];
+				name = options.names[ bone.name ] || bone.name;
+
+				if ( name !== options.hip ) {
+
+					bone.position.copy( bonesPosition[ i ] );
 
 				}
 
 			}
 
-			if ( options.preserveMatrix ) {
+		}
 
-				// restore matrix
+		if ( options.preserveMatrix ) {
 
-				target.updateMatrixWorld( true );
+			// restore matrix
 
-			}
+			target.updateMatrixWorld( true );
 
-		};
+		}
 
-	}(),
+	}
 
-	retargetClip: function ( target, source, clip, options ) {
+	static retargetClip( target, source, clip, options = {} ) {
 
-		options = options || {};
 		options.useFirstFramePosition = options.useFirstFramePosition !== undefined ? options.useFirstFramePosition : false;
 		options.fps = options.fps !== undefined ? options.fps : 30;
 		options.names = options.names || [];
@@ -217,28 +212,28 @@ var SkeletonUtils = {
 
 		}
 
-		var numFrames = Math.round( clip.duration * ( options.fps / 1000 ) * 1000 ),
+		const numFrames = Math.round( clip.duration * ( options.fps / 1000 ) * 1000 ),
 			delta = 1 / options.fps,
 			convertedTracks = [],
 			mixer = new AnimationMixer( source ),
 			bones = this.getBones( target.skeleton ),
-			boneDatas = [],
-			positionOffset,
+			boneDatas = [];
+		let positionOffset,
 			bone, boneTo, boneData,
-			name, i, j;
+			name;
 
 		mixer.clipAction( clip ).play();
 		mixer.update( 0 );
 
 		source.updateMatrixWorld();
 
-		for ( i = 0; i < numFrames; ++ i ) {
+		for ( let i = 0; i < numFrames; ++ i ) {
 
-			var time = i * delta;
+			const time = i * delta;
 
 			this.retarget( target, source, options );
 
-			for ( j = 0; j < bones.length; ++ j ) {
+			for ( let j = 0; j < bones.length; ++ j ) {
 
 				name = options.names[ bones[ j ].name ] || bones[ j ].name;
 
@@ -301,7 +296,7 @@ var SkeletonUtils = {
 
 		}
 
-		for ( i = 0; i < boneDatas.length; ++ i ) {
+		for ( let i = 0; i < boneDatas.length; ++ i ) {
 
 			boneData = boneDatas[ i ];
 
@@ -331,114 +326,110 @@ var SkeletonUtils = {
 
 		return new AnimationClip( clip.name, - 1, convertedTracks );
 
-	},
+	}
 
-	getHelperFromSkeleton: function ( skeleton ) {
+	static getHelperFromSkeleton( skeleton ) {
 
-		var source = new SkeletonHelper( skeleton.bones[ 0 ] );
+		const source = new SkeletonHelper( skeleton.bones[ 0 ] );
 		source.skeleton = skeleton;
 
 		return source;
 
-	},
+	}
 
-	getSkeletonOffsets: function () {
+	static getSkeletonOffsets( target, source, options = {} ) {
 
-		var targetParentPos = new Vector3(),
+		const targetParentPos = new Vector3(),
 			targetPos = new Vector3(),
 			sourceParentPos = new Vector3(),
 			sourcePos = new Vector3(),
 			targetDir = new Vector2(),
 			sourceDir = new Vector2();
 
-		return function ( target, source, options ) {
-
-			options = options || {};
-			options.hip = options.hip !== undefined ? options.hip : 'hip';
-			options.names = options.names || {};
+		options.hip = options.hip !== undefined ? options.hip : 'hip';
+		options.names = options.names || {};
 
-			if ( ! source.isObject3D ) {
+		if ( ! source.isObject3D ) {
 
-				source = this.getHelperFromSkeleton( source );
+			source = this.getHelperFromSkeleton( source );
 
-			}
+		}
 
-			var nameKeys = Object.keys( options.names ),
-				nameValues = Object.values( options.names ),
-				sourceBones = source.isObject3D ? source.skeleton.bones : this.getBones( source ),
-				bones = target.isObject3D ? target.skeleton.bones : this.getBones( target ),
-				offsets = [],
-				bone, boneTo,
-				name, i;
+		const nameKeys = Object.keys( options.names ),
+			nameValues = Object.values( options.names ),
+			sourceBones = source.isObject3D ? source.skeleton.bones : this.getBones( source ),
+			bones = target.isObject3D ? target.skeleton.bones : this.getBones( target ),
+			offsets = [];
 
-			target.skeleton.pose();
+		let bone, boneTo,
+			name, i;
 
-			for ( i = 0; i < bones.length; ++ i ) {
+		target.skeleton.pose();
 
-				bone = bones[ i ];
-				name = options.names[ bone.name ] || bone.name;
+		for ( i = 0; i < bones.length; ++ i ) {
 
-				boneTo = this.getBoneByName( name, sourceBones );
+			bone = bones[ i ];
+			name = options.names[ bone.name ] || bone.name;
 
-				if ( boneTo && name !== options.hip ) {
+			boneTo = this.getBoneByName( name, sourceBones );
 
-					var boneParent = this.getNearestBone( bone.parent, nameKeys ),
-						boneToParent = this.getNearestBone( boneTo.parent, nameValues );
+			if ( boneTo && name !== options.hip ) {
 
-					boneParent.updateMatrixWorld();
-					boneToParent.updateMatrixWorld();
+				const boneParent = this.getNearestBone( bone.parent, nameKeys ),
+					boneToParent = this.getNearestBone( boneTo.parent, nameValues );
 
-					targetParentPos.setFromMatrixPosition( boneParent.matrixWorld );
-					targetPos.setFromMatrixPosition( bone.matrixWorld );
+				boneParent.updateMatrixWorld();
+				boneToParent.updateMatrixWorld();
 
-					sourceParentPos.setFromMatrixPosition( boneToParent.matrixWorld );
-					sourcePos.setFromMatrixPosition( boneTo.matrixWorld );
+				targetParentPos.setFromMatrixPosition( boneParent.matrixWorld );
+				targetPos.setFromMatrixPosition( bone.matrixWorld );
 
-					targetDir.subVectors(
-						new Vector2( targetPos.x, targetPos.y ),
-						new Vector2( targetParentPos.x, targetParentPos.y )
-					).normalize();
+				sourceParentPos.setFromMatrixPosition( boneToParent.matrixWorld );
+				sourcePos.setFromMatrixPosition( boneTo.matrixWorld );
 
-					sourceDir.subVectors(
-						new Vector2( sourcePos.x, sourcePos.y ),
-						new Vector2( sourceParentPos.x, sourceParentPos.y )
-					).normalize();
+				targetDir.subVectors(
+					new Vector2( targetPos.x, targetPos.y ),
+					new Vector2( targetParentPos.x, targetParentPos.y )
+				).normalize();
 
-					var laterialAngle = targetDir.angle() - sourceDir.angle();
+				sourceDir.subVectors(
+					new Vector2( sourcePos.x, sourcePos.y ),
+					new Vector2( sourceParentPos.x, sourceParentPos.y )
+				).normalize();
 
-					var offset = new Matrix4().makeRotationFromEuler(
-						new Euler(
-							0,
-							0,
-							laterialAngle
-						)
-					);
+				const laterialAngle = targetDir.angle() - sourceDir.angle();
 
-					bone.matrix.multiply( offset );
+				const offset = new Matrix4().makeRotationFromEuler(
+					new Euler(
+						0,
+						0,
+						laterialAngle
+					)
+				);
 
-					bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
+				bone.matrix.multiply( offset );
 
-					bone.updateMatrixWorld();
+				bone.matrix.decompose( bone.position, bone.quaternion, bone.scale );
 
-					offsets[ name ] = offset;
+				bone.updateMatrixWorld();
 
-				}
+				offsets[ name ] = offset;
 
 			}
 
-			return offsets;
+		}
 
-		};
+		return offsets;
 
-	}(),
+	}
 
-	renameBones: function ( skeleton, names ) {
+	static renameBones( skeleton, names ) {
 
-		var bones = this.getBones( skeleton );
+		const bones = this.getBones( skeleton );
 
-		for ( var i = 0; i < bones.length; ++ i ) {
+		for ( let i = 0; i < bones.length; ++ i ) {
 
-			var bone = bones[ i ];
+			const bone = bones[ i ];
 
 			if ( names[ bone.name ] ) {
 
@@ -450,17 +441,17 @@ var SkeletonUtils = {
 
 		return this;
 
-	},
+	}
 
-	getBones: function ( skeleton ) {
+	static getBones( skeleton ) {
 
 		return Array.isArray( skeleton ) ? skeleton : skeleton.bones;
 
-	},
+	}
 
-	getBoneByName: function ( name, skeleton ) {
+	static getBoneByName( name, skeleton ) {
 
-		for ( var i = 0, bones = this.getBones( skeleton ); i < bones.length; i ++ ) {
+		for ( let i = 0, bones = this.getBones( skeleton ); i < bones.length; i ++ ) {
 
 			if ( name === bones[ i ].name )
 
@@ -468,9 +459,9 @@ var SkeletonUtils = {
 
 		}
 
-	},
+	}
 
-	getNearestBone: function ( bone, names ) {
+	static getNearestBone( bone, names ) {
 
 		while ( bone.isBone ) {
 
@@ -484,18 +475,18 @@ var SkeletonUtils = {
 
 		}
 
-	},
+	}
 
-	findBoneTrackData: function ( name, tracks ) {
+	static findBoneTrackData( name, tracks ) {
 
-		var regexp = /\[(.*)\]\.(.*)/,
+		const regexp = /\[(.*)\]\.(.*)/,
 			result = { name: name };
 
-		for ( var i = 0; i < tracks.length; ++ i ) {
+		for ( let i = 0; i < tracks.length; ++ i ) {
 
 			// 1 is track name
 			// 2 is track type
-			var trackData = regexp.exec( tracks[ i ].name );
+			const trackData = regexp.exec( tracks[ i ].name );
 
 			if ( trackData && name === trackData[ 1 ] ) {
 
@@ -507,19 +498,19 @@ var SkeletonUtils = {
 
 		return result;
 
-	},
+	}
 
-	getEqualsBonesNames: function ( skeleton, targetSkeleton ) {
+	static getEqualsBonesNames( skeleton, targetSkeleton ) {
 
-		var sourceBones = this.getBones( skeleton ),
+		const sourceBones = this.getBones( skeleton ),
 			targetBones = this.getBones( targetSkeleton ),
 			bones = [];
 
-		search : for ( var i = 0; i < sourceBones.length; i ++ ) {
+		search : for ( let i = 0; i < sourceBones.length; i ++ ) {
 
-			var boneName = sourceBones[ i ].name;
+			const boneName = sourceBones[ i ].name;
 
-			for ( var j = 0; j < targetBones.length; j ++ ) {
+			for ( let j = 0; j < targetBones.length; j ++ ) {
 
 				if ( boneName === targetBones[ j ].name ) {
 
@@ -535,14 +526,14 @@ var SkeletonUtils = {
 
 		return bones;
 
-	},
+	}
 
-	clone: function ( source ) {
+	static clone( source ) {
 
-		var sourceLookup = new Map();
-		var cloneLookup = new Map();
+		const sourceLookup = new Map();
+		const cloneLookup = new Map();
 
-		var clone = source.clone();
+		const clone = source.clone();
 
 		parallelTraverse( source, clone, function ( sourceNode, clonedNode ) {
 
@@ -555,9 +546,9 @@ var SkeletonUtils = {
 
 			if ( ! node.isSkinnedMesh ) return;
 
-			var clonedMesh = node;
-			var sourceMesh = sourceLookup.get( node );
-			var sourceBones = sourceMesh.skeleton.bones;
+			const clonedMesh = node;
+			const sourceMesh = sourceLookup.get( node );
+			const sourceBones = sourceMesh.skeleton.bones;
 
 			clonedMesh.skeleton = sourceMesh.skeleton.clone();
 			clonedMesh.bindMatrix.copy( sourceMesh.bindMatrix );
@@ -576,14 +567,14 @@ var SkeletonUtils = {
 
 	}
 
-};
+}
 
 
 function parallelTraverse( a, b, callback ) {
 
 	callback( a, b );
 
-	for ( var i = 0; i < a.children.length; i ++ ) {
+	for ( let i = 0; i < a.children.length; i ++ ) {
 
 		parallelTraverse( a.children[ i ], b.children[ i ], callback );
 

+ 20 - 20
examples/jsm/utils/UVsDebug.js

@@ -10,29 +10,29 @@ import {
  *
  */
 
-var UVsDebug = function ( geometry, size ) {
+function UVsDebug( geometry, size = 1024 ) {
 
 	// handles wrapping of uv.x > 1 only
 
-	var abc = 'abc';
-	var a = new Vector2();
-	var b = new Vector2();
+	const abc = 'abc';
+	const a = new Vector2();
+	const b = new Vector2();
 
-	var uvs = [
+	const uvs = [
 		new Vector2(),
 		new Vector2(),
 		new Vector2()
 	];
 
-	var face = [];
+	const face = [];
 
-	var canvas = document.createElement( 'canvas' );
-	var width = size || 1024; // power of 2 required for wrapping
-	var height = size || 1024;
+	const canvas = document.createElement( 'canvas' );
+	const width = size; // power of 2 required for wrapping
+	const height = size;
 	canvas.width = width;
 	canvas.height = height;
 
-	var ctx = canvas.getContext( '2d' );
+	const ctx = canvas.getContext( '2d' );
 	ctx.lineWidth = 1;
 	ctx.strokeStyle = 'rgb( 63, 63, 63 )';
 	ctx.textAlign = 'center';
@@ -49,14 +49,14 @@ var UVsDebug = function ( geometry, size ) {
 
 	} else {
 
-		var index = geometry.index;
-		var uvAttribute = geometry.attributes.uv;
+		const index = geometry.index;
+		const uvAttribute = geometry.attributes.uv;
 
 		if ( index ) {
 
 			// indexed geometry
 
-			for ( var i = 0, il = index.count; i < il; i += 3 ) {
+			for ( let i = 0, il = index.count; i < il; i += 3 ) {
 
 				face[ 0 ] = index.getX( i );
 				face[ 1 ] = index.getX( i + 1 );
@@ -74,7 +74,7 @@ var UVsDebug = function ( geometry, size ) {
 
 			// non-indexed geometry
 
-			for ( var i = 0, il = uvAttribute.count; i < il; i += 3 ) {
+			for ( let i = 0, il = uvAttribute.count; i < il; i += 3 ) {
 
 				face[ 0 ] = i;
 				face[ 1 ] = i + 1;
@@ -102,9 +102,9 @@ var UVsDebug = function ( geometry, size ) {
 
 		a.set( 0, 0 );
 
-		for ( var j = 0, jl = uvs.length; j < jl; j ++ ) {
+		for ( let j = 0, jl = uvs.length; j < jl; j ++ ) {
 
-			var uv = uvs[ j ];
+			const uv = uvs[ j ];
 
 			a.x += uv.x;
 			a.y += uv.y;
@@ -149,12 +149,12 @@ var UVsDebug = function ( geometry, size ) {
 
 		// label uv edge orders
 
-		for ( j = 0, jl = uvs.length; j < jl; j ++ ) {
+		for ( let j = 0, jl = uvs.length; j < jl; j ++ ) {
 
-			var uv = uvs[ j ];
+			const uv = uvs[ j ];
 			b.addVectors( a, uv ).divideScalar( 2 );
 
-			var vnum = face[ j ];
+			const vnum = face[ j ];
 			ctx.fillText( abc[ j ] + vnum, b.x * width, ( 1 - b.y ) * height );
 
 			if ( b.x > 0.95 ) {
@@ -169,6 +169,6 @@ var UVsDebug = function ( geometry, size ) {
 
 	}
 
-};
+}
 
 export { UVsDebug };