Răsfoiți Sursa

Merge branch 'dev' of https://github.com/mrdoob/three.js into zh_doc_20200806

gogoend 5 ani în urmă
părinte
comite
ab06bfe828
100 a modificat fișierele cu 4583 adăugiri și 4332 ștergeri
  1. 455 479
      build/three.js
  2. 474 480
      build/three.min.js
  3. 188 194
      build/three.module.js
  4. 4 4
      docs/api/en/core/Object3D.html
  5. 0 2
      docs/api/en/helpers/ArrowHelper.html
  6. 0 5
      docs/api/en/scenes/Scene.html
  7. 6 4
      docs/api/zh/core/Object3D.html
  8. 0 2
      docs/api/zh/helpers/ArrowHelper.html
  9. 0 7
      docs/manual/en/introduction/How-to-dispose-of-objects.html
  10. 0 7
      docs/manual/zh/introduction/How-to-dispose-of-objects.html
  11. 1 0
      examples/files.js
  12. 12 27
      examples/js/loaders/GLTFLoader.js
  13. 0 3
      examples/js/loaders/MMDLoader.js
  14. 0 0
      examples/jsm/libs/chevrotain.module.min.js
  15. 12 28
      examples/jsm/loaders/GLTFLoader.js
  16. 0 3
      examples/jsm/loaders/MMDLoader.js
  17. 4 4
      examples/jsm/nodes/core/NodeBuilder.d.ts
  18. 37 36
      examples/jsm/physics/CannonPhysics.js
  19. BIN
      examples/models/vox/menger.vox
  20. BIN
      examples/models/vox/monu10.vox
  21. 9 24
      examples/physics_cannon_instancing.html
  22. BIN
      examples/screenshots/physics_cannon_instancing.jpg
  23. BIN
      examples/screenshots/webgl2_volume_instancing.jpg
  24. BIN
      examples/screenshots/webgl_instancing_raycast.jpg
  25. BIN
      examples/screenshots/webgl_loader_3ds.jpg
  26. BIN
      examples/screenshots/webgl_loader_vox.jpg
  27. BIN
      examples/screenshots/webgl_materials_variations_toon.jpg
  28. 258 0
      examples/webgl2_volume_instancing.html
  29. 2 2
      examples/webgl2_volume_perlin.html
  30. 18 16
      examples/webgl_buffergeometry_compression.html
  31. 11 14
      examples/webgl_instancing_raycast.html
  32. 2 0
      examples/webgl_loader_3ds.html
  33. 54 7
      examples/webgl_loader_vox.html
  34. 2 6
      examples/webgl_materials_variations_toon.html
  35. 7 0
      package.json
  36. 13 0
      src/Three.Legacy.js
  37. 108 107
      src/animation/AnimationAction.js
  38. 2 2
      src/animation/AnimationMixer.js
  39. 3 3
      src/animation/AnimationObjectGroup.js
  40. 5 5
      src/animation/PropertyBinding.js
  41. 74 76
      src/audio/Audio.js
  42. 12 11
      src/audio/AudioAnalyser.js
  43. 27 29
      src/audio/AudioListener.js
  44. 30 33
      src/audio/PositionalAudio.js
  45. 6 6
      src/cameras/PerspectiveCamera.js
  46. 1 1
      src/constants.js
  47. 16 17
      src/core/Clock.js
  48. 25 25
      src/core/DirectGeometry.js
  49. 15 15
      src/core/Face3.js
  50. 6 5
      src/core/Geometry.js
  51. 18 18
      src/core/Layers.js
  52. 14 10
      src/core/Uniform.js
  53. 22 24
      src/extras/Earcut.js
  54. 39 41
      src/extras/PMREMGenerator.js
  55. 2 1
      src/extras/core/Curve.js
  56. 2 1
      src/extras/core/ShapePath.js
  57. 3 3
      src/extras/curves/CatmullRomCurve3.js
  58. 65 64
      src/geometries/CircleGeometry.js
  59. 30 30
      src/geometries/ConeGeometry.js
  60. 175 178
      src/geometries/CylinderGeometry.js
  61. 55 54
      src/geometries/DodecahedronGeometry.js
  62. 56 55
      src/geometries/EdgesGeometry.js
  63. 382 381
      src/geometries/ExtrudeGeometry.js
  64. 36 34
      src/geometries/IcosahedronGeometry.js
  65. 99 97
      src/geometries/LatheGeometry.js
  66. 33 31
      src/geometries/OctahedronGeometry.js
  67. 68 67
      src/geometries/PlaneGeometry.js
  68. 175 173
      src/geometries/PolyhedronGeometry.js
  69. 85 83
      src/geometries/RingGeometry.js
  70. 97 97
      src/geometries/ShapeGeometry.js
  71. 91 91
      src/geometries/SphereGeometry.js
  72. 29 27
      src/geometries/TetrahedronGeometry.js
  73. 32 30
      src/geometries/TextGeometry.js
  74. 78 77
      src/geometries/TorusGeometry.js
  75. 111 110
      src/geometries/TorusKnotGeometry.js
  76. 123 122
      src/geometries/TubeGeometry.js
  77. 83 83
      src/geometries/WireframeGeometry.js
  78. 59 58
      src/helpers/ArrowHelper.js
  79. 22 21
      src/helpers/AxesHelper.js
  80. 22 24
      src/helpers/Box3Helper.js
  81. 63 62
      src/helpers/BoxHelper.js
  82. 106 104
      src/helpers/CameraHelper.js
  83. 48 48
      src/helpers/DirectionalLightHelper.js
  84. 28 26
      src/helpers/GridHelper.js
  85. 38 38
      src/helpers/HemisphereLightHelper.js
  86. 27 28
      src/helpers/PlaneHelper.js
  87. 36 34
      src/helpers/PointLightHelper.js
  88. 48 46
      src/helpers/PolarGridHelper.js
  89. 61 59
      src/helpers/SkeletonHelper.js
  90. 47 47
      src/helpers/SpotLightHelper.js
  91. 2 2
      src/materials/MeshPhysicalMaterial.d.ts
  92. 2 3
      src/math/Interpolant.js
  93. 2 2
      src/math/Matrix4.js
  94. 2 4
      src/math/Quaternion.js
  95. 45 45
      src/math/Ray.js
  96. 2 2
      src/math/interpolants/CubicInterpolant.js
  97. 13 0
      src/objects/InstancedMesh.js
  98. 2 2
      src/renderers/WebGLRenderer.js
  99. 5 5
      src/renderers/shaders/ShaderChunk/bsdfs.glsl.js
  100. 1 1
      src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl.js

Fișier diff suprimat deoarece este prea mare
+ 455 - 479
build/three.js


Fișier diff suprimat deoarece este prea mare
+ 474 - 480
build/three.min.js


Fișier diff suprimat deoarece este prea mare
+ 188 - 194
build/three.module.js


+ 4 - 4
docs/api/en/core/Object3D.html

@@ -286,9 +286,9 @@
 
 		<h3>[method:Vector3 localToWorld]( [param:Vector3 vector] )</h3>
 		<p>
-		vector - A vector representing a position in local (object) space.<br /><br />
+		vector - A vector representing a position in this object's local space.<br /><br />
 
-		Converts the vector from local space to world space.
+		Converts the vector from this object's local space to world space.
 		</p>
 
 		<h3>[method:null lookAt]( [param:Vector3 vector] )<br />
@@ -447,9 +447,9 @@
 
 		<h3>[method:Vector3 worldToLocal]( [param:Vector3 vector] )</h3>
 		<p>
-		vector - A world vector.<br /><br />
+		vector - A vector representing a position in world space.<br /><br />
 
-		Updates the vector from world space to local space.
+		Converts the vector from world space to this object's local space.
 		</p>
 
 		<h2>Source</h2>

+ 0 - 2
docs/api/en/helpers/ArrowHelper.html

@@ -33,8 +33,6 @@
 		<h2>Examples</h2>
 
 		<p>
-			[example:webgl_geometries WebGL / geometries]<br/>
-			[example:webgl_geometry_normals WebGL / geometry / normals]<br/>
 			[example:webgl_shadowmesh WebGL / shadowmesh]
 		</p>
 

+ 0 - 5
docs/api/en/scenes/Scene.html

@@ -52,11 +52,6 @@
 
 		<h2>Methods</h2>
 
-		<h3>[method:null dispose]()</h3>
-		<p>
-		Clears scene related data internally cached by [page:WebGLRenderer].
-		</p>
-
 		<h3>[method:Object toJSON]( [param:Object meta] )</h3>
 		<p>
 		meta -- object containing metadata such as textures or images for the scene.<br />

+ 6 - 4
docs/api/zh/core/Object3D.html

@@ -270,8 +270,9 @@
 
 	<h3>[method:Vector3 localToWorld]( [param:Vector3 vector] )</h3>
 	<p>
-		vector - 一个表示局部(物体)空间中位置的向量。 <br /><br />
-		将局部空间向量转换为世界空间向量。
+		vector - A vector representing a position in this object's local space.<br /><br />
+
+		Converts the vector from this object's local space to world space.
 	</p>
 
 	<h3>[method:null lookAt]( [param:Vector3 vector] )<br />
@@ -422,8 +423,9 @@
 
 	<h3>[method:Vector3 worldToLocal]( [param:Vector3 vector] )</h3>
 	<p>
-		vector - 一个世界向量.<br /><br />
-		将世界空间中的向量转换为局部空间向量。
+		vector - A vector representing a position in world space.<br /><br />
+
+		Converts the vector from world space to this object's local space.
 	</p>
 
 	<h2>源代码</h2>

+ 0 - 2
docs/api/zh/helpers/ArrowHelper.html

@@ -33,8 +33,6 @@
 		<h2>例子</h2>
 
 		<p>
-			[example:webgl_geometries WebGL / geometries]<br/>
-			[example:webgl_geometry_normals WebGL / geometry / normals]<br/>
 			[example:webgl_shadowmesh WebGL / shadowmesh]
 		</p>
 

+ 0 - 7
docs/manual/en/introduction/How-to-dispose-of-objects.html

@@ -53,13 +53,6 @@
 		for realizing custom rendering destinations. These objects are only deallocated by executing [page:WebGLRenderTarget.dispose]().
 	</p>
 
-	<h2>Scenes</h2>
-
-	<p>
-		The renderer maintains for scenes special data structures for sorting and rendering. If for some reasons a scene object becomes obsolete in an application,
-		call [page:Scene.dispose]() in order to free these resources.
-	</p>
-
 	<h2>Miscellaneous</h2>
 
 	<p>

+ 0 - 7
docs/manual/zh/introduction/How-to-dispose-of-objects.html

@@ -53,13 +53,6 @@
 		这些对象仅能通过执行[page:WebGLRenderTarget.dispose]()来解除分配。
 	</p>
 
-	<h2>Scenes</h2>
-
-	<p>
-		The renderer maintains for scenes special data structures for sorting and rendering. If for some reasons a scene object becomes obsolete in an application,
-		call [page:Scene.dispose]() in order to free these resources.
-	</p>
-
 	<h2>杂项</h2>
 
 	<p>

+ 1 - 0
examples/files.js

@@ -315,6 +315,7 @@ var files = {
 		"webgl2_materials_texture2darray",
 		"webgl2_materials_texture3d",
 		"webgl2_multisampled_renderbuffers",
+		"webgl2_volume_instancing",
 		"webgl2_volume_perlin"
 	],
 	"webaudio": [

+ 12 - 27
examples/js/loaders/GLTFLoader.js

@@ -1308,11 +1308,6 @@ THREE.GLTFLoader = ( function () {
 		BLEND: 'BLEND'
 	};
 
-	var MIME_TYPE_FORMATS = {
-		'image/png': THREE.RGBAFormat,
-		'image/jpeg': THREE.RGBFormat
-	};
-
 	/* UTILITY FUNCTIONS */
 
 	function resolveURL( url, path ) {
@@ -2153,6 +2148,9 @@ THREE.GLTFLoader = ( function () {
 
 		var sourceURI = source.uri;
 		var isObjectURL = false;
+		var hasAlpha = true;
+
+		if ( source.mimeType === 'image/jpeg' ) hasAlpha = false;
 
 		if ( source.bufferView !== undefined ) {
 
@@ -2160,6 +2158,13 @@ THREE.GLTFLoader = ( function () {
 
 			sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) {
 
+				if ( source.mimeType === 'image/png' ) {
+
+					// https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header
+					hasAlpha = new DataView( bufferView, 25, 1 ).getUint8( 0, false ) === 6;
+
+				}
+
 				isObjectURL = true;
 				var blob = new Blob( [ bufferView ], { type: source.mimeType } );
 				sourceURI = URL.createObjectURL( blob );
@@ -2203,12 +2208,8 @@ THREE.GLTFLoader = ( function () {
 
 			if ( textureDef.name ) texture.name = textureDef.name;
 
-			// Ignore unknown mime types, like DDS files.
-			if ( source.mimeType in MIME_TYPE_FORMATS ) {
-
-				texture.format = MIME_TYPE_FORMATS[ source.mimeType ];
-
-			}
+			// When there is definitely no alpha channel in the texture, set RGBFormat to save space.
+			if ( ! hasAlpha ) texture.format = THREE.RGBFormat;
 
 			var samplers = json.samplers || {};
 			var sampler = samplers[ textureDef.sampler ] || {};
@@ -2242,22 +2243,6 @@ THREE.GLTFLoader = ( function () {
 
 		return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
 
-			if ( ! texture.isCompressedTexture ) {
-
-				switch ( mapName ) {
-
-					case 'aoMap':
-					case 'emissiveMap':
-					case 'metalnessMap':
-					case 'normalMap':
-					case 'roughnessMap':
-						texture.format = THREE.RGBFormat;
-						break;
-
-				}
-
-			}
-
 			// Materials sample aoMap from UV set 1 and other maps from UV set 0 - this can't be configured
 			// However, we will copy UV set 0 to UV set 1 on demand for aoMap
 			if ( mapDef.texCoord !== undefined && mapDef.texCoord != 0 && ! ( mapName === 'aoMap' && mapDef.texCoord == 1 ) ) {

+ 0 - 3
examples/js/loaders/MMDLoader.js

@@ -1018,7 +1018,6 @@ THREE.MMDLoader = ( function () {
 				 *
 				 * MMD         MeshToonMaterial
 				 * diffuse  -  color
-				 * specular -  specular
 				 * ambient  -  emissive * a
 				 *               (a = 1.0 without map texture or 0.2 with map texture)
 				 *
@@ -1027,9 +1026,7 @@ THREE.MMDLoader = ( function () {
 				 */
 				params.color = new THREE.Color().fromArray( material.diffuse );
 				params.opacity = material.diffuse[ 3 ];
-				params.specular = new THREE.Color().fromArray( material.specular );
 				params.emissive = new THREE.Color().fromArray( material.ambient );
-				params.shininess = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
 				params.transparent = params.opacity !== 1.0;
 
 				//

Fișier diff suprimat deoarece este prea mare
+ 0 - 0
examples/jsm/libs/chevrotain.module.min.js


+ 12 - 28
examples/jsm/loaders/GLTFLoader.js

@@ -47,7 +47,6 @@ import {
 	PointsMaterial,
 	PropertyBinding,
 	QuaternionKeyframeTrack,
-	RGBAFormat,
 	RGBFormat,
 	RepeatWrapping,
 	Skeleton,
@@ -1372,11 +1371,6 @@ var GLTFLoader = ( function () {
 		BLEND: 'BLEND'
 	};
 
-	var MIME_TYPE_FORMATS = {
-		'image/png': RGBAFormat,
-		'image/jpeg': RGBFormat
-	};
-
 	/* UTILITY FUNCTIONS */
 
 	function resolveURL( url, path ) {
@@ -2217,6 +2211,9 @@ var GLTFLoader = ( function () {
 
 		var sourceURI = source.uri;
 		var isObjectURL = false;
+		var hasAlpha = true;
+
+		if ( source.mimeType === 'image/jpeg' ) hasAlpha = false;
 
 		if ( source.bufferView !== undefined ) {
 
@@ -2224,6 +2221,13 @@ var GLTFLoader = ( function () {
 
 			sourceURI = parser.getDependency( 'bufferView', source.bufferView ).then( function ( bufferView ) {
 
+				if ( source.mimeType === 'image/png' ) {
+
+					// https://en.wikipedia.org/wiki/Portable_Network_Graphics#File_header
+					hasAlpha = new DataView( bufferView, 25, 1 ).getUint8( 0, false ) === 6;
+
+				}
+
 				isObjectURL = true;
 				var blob = new Blob( [ bufferView ], { type: source.mimeType } );
 				sourceURI = URL.createObjectURL( blob );
@@ -2267,12 +2271,8 @@ var GLTFLoader = ( function () {
 
 			if ( textureDef.name ) texture.name = textureDef.name;
 
-			// Ignore unknown mime types, like DDS files.
-			if ( source.mimeType in MIME_TYPE_FORMATS ) {
-
-				texture.format = MIME_TYPE_FORMATS[ source.mimeType ];
-
-			}
+			// When there is definitely no alpha channel in the texture, set RGBFormat to save space.
+			if ( ! hasAlpha ) texture.format = RGBFormat;
 
 			var samplers = json.samplers || {};
 			var sampler = samplers[ textureDef.sampler ] || {};
@@ -2306,22 +2306,6 @@ var GLTFLoader = ( function () {
 
 		return this.getDependency( 'texture', mapDef.index ).then( function ( texture ) {
 
-			if ( ! texture.isCompressedTexture ) {
-
-				switch ( mapName ) {
-
-					case 'aoMap':
-					case 'emissiveMap':
-					case 'metalnessMap':
-					case 'normalMap':
-					case 'roughnessMap':
-						texture.format = RGBFormat;
-						break;
-
-				}
-
-			}
-
 			// Materials sample aoMap from UV set 1 and other maps from UV set 0 - this can't be configured
 			// However, we will copy UV set 0 to UV set 1 on demand for aoMap
 			if ( mapDef.texCoord !== undefined && mapDef.texCoord != 0 && ! ( mapName === 'aoMap' && mapDef.texCoord == 1 ) ) {

+ 0 - 3
examples/jsm/loaders/MMDLoader.js

@@ -1051,7 +1051,6 @@ var MMDLoader = ( function () {
 				 *
 				 * MMD         MeshToonMaterial
 				 * diffuse  -  color
-				 * specular -  specular
 				 * ambient  -  emissive * a
 				 *               (a = 1.0 without map texture or 0.2 with map texture)
 				 *
@@ -1060,9 +1059,7 @@ var MMDLoader = ( function () {
 				 */
 				params.color = new Color().fromArray( material.diffuse );
 				params.opacity = material.diffuse[ 3 ];
-				params.specular = new Color().fromArray( material.specular );
 				params.emissive = new Color().fromArray( material.ambient );
-				params.shininess = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )
 				params.transparent = params.opacity !== 1.0;
 
 				//

+ 4 - 4
examples/jsm/nodes/core/NodeBuilder.d.ts

@@ -96,19 +96,19 @@ export class NodeBuilder {
 	removeSlot(): this;
 	addVertexCode( code: string ): void;
 	addFragmentCode( code: string ): void;
-	addCode( code: string, shader: string ): void;
+	addCode( code: string, shader?: string ): void;
 	addVertexNodeCode( code: string ): void;
 	addFragmentNodeCode( code: string ): void;
-	addNodeCode( code: string, shader: string ): void;
+	addNodeCode( code: string, shader?: string ): void;
 	clearNodeCode( shader: string ): string;
 	clearVertexNodeCode(): string;
 	clearFragmentNodeCode(): string;
 	addVertexFinalCode( code: string ): void;
 	addFragmentFinalCode( code: string ): void;
-	addFinalCode( code: string, shader: string ): void;
+	addFinalCode( code: string, shader?: string ): void;
 	addVertexParsCode( code: string ): void;
 	addFragmentParsCode( code: string ): void;
-	addParsCode( code: string, shader: string ): void;
+	addParsCode( code: string, shader?: string ): void;
 	addVaryCode( code: string ): void;
 	isCache( name: string ): boolean;
 	isSlot( name: string ): boolean;

+ 37 - 36
examples/jsm/physics/CannonPhysics.js

@@ -1,12 +1,13 @@
 import CANNON from "../libs/cannon.module.min.js";
+// import * as CANNON from "https://unpkg.com/cannon-es/dist/cannon-es.js";
 
 function compose( position, quaternion, array, index ) {
 
-	var x = quaternion.x, y = quaternion.y, z = quaternion.z, w = quaternion.w;
-	var x2 = x + x,	y2 = y + y, z2 = z + z;
-	var xx = x * x2, xy = x * y2, xz = x * z2;
-	var yy = y * y2, yz = y * z2, zz = z * z2;
-	var wx = w * x2, wy = w * y2, wz = w * z2;
+	const x = quaternion.x, y = quaternion.y, z = quaternion.z, w = quaternion.w;
+	const x2 = x + x,	y2 = y + y, z2 = z + z;
+	const xx = x * x2, xy = x * y2, xz = x * z2;
+	const yy = y * y2, yz = y * z2, zz = z * z2;
+	const wx = w * x2, wy = w * y2, wz = w * z2;
 
 	array[ index + 0 ] = ( 1 - ( yy + zz ) );
 	array[ index + 1 ] = ( xy + wz );
@@ -32,10 +33,10 @@ function compose( position, quaternion, array, index ) {
 
 function CannonPhysics() {
 
-	var frameRate = 60;
-	var frameTime = 1 / frameRate;
+	const frameRate = 60;
+	const frameTime = 1 / frameRate;
 
-	var world = new CANNON.World();
+	const world = new CANNON.World();
 	world.gravity.set( 0, - 9.8, 0 );
 	world.broadphase = new CANNON.SAPBroadphase( world );
 	// world.solver.iterations = 20;
@@ -46,14 +47,14 @@ function CannonPhysics() {
 
 	function getShape( geometry ) {
 
-		var parameters = geometry.parameters;
+		const parameters = geometry.parameters;
 
 		// TODO change type to is*
 
 		switch ( geometry.type ) {
 
 			case 'BoxBufferGeometry':
-				var halfExtents = new CANNON.Vec3();
+				const halfExtents = new CANNON.Vec3();
 				halfExtents.x = parameters.width !== undefined ? parameters.width / 2 : 0.5;
 				halfExtents.y = parameters.height !== undefined ? parameters.height / 2 : 0.5;
 				halfExtents.z = parameters.depth !== undefined ? parameters.depth / 2 : 0.5;
@@ -63,7 +64,7 @@ function CannonPhysics() {
 				return new CANNON.Plane();
 
 			case 'SphereBufferGeometry':
-				var radius = parameters.radius;
+				const radius = parameters.radius;
 				return new CANNON.Sphere( radius );
 
 		}
@@ -72,12 +73,12 @@ function CannonPhysics() {
 
 	}
 
-	var meshes = [];
-	var meshMap = new WeakMap();
+	const meshes = [];
+	const meshMap = new WeakMap();
 
 	function addMesh( mesh, mass = 0 ) {
 
-		var shape = getShape( mesh.geometry );
+		const shape = getShape( mesh.geometry );
 
 		if ( shape !== null ) {
 
@@ -97,13 +98,13 @@ function CannonPhysics() {
 
 	function handleMesh( mesh, mass, shape ) {
 
-		var position = new CANNON.Vec3();
+		const position = new CANNON.Vec3();
 		position.copy( mesh.position );
 
-		var quaternion = new CANNON.Quaternion();
+		const quaternion = new CANNON.Quaternion();
 		quaternion.copy( mesh.quaternion );
 
-		var body = new CANNON.Body( {
+		const body = new CANNON.Body( {
 			position: position,
 			quaternion: quaternion,
 			mass: mass,
@@ -122,18 +123,18 @@ function CannonPhysics() {
 
 	function handleInstancedMesh( mesh, mass, shape ) {
 
-		var array = mesh.instanceMatrix.array;
+		const array = mesh.instanceMatrix.array;
 
-		var bodies = [];
+		const bodies = [];
 
-		for ( var i = 0; i < mesh.count; i ++ ) {
+		for ( let i = 0; i < mesh.count; i ++ ) {
 
-			var index = i * 16;
+			const index = i * 16;
 
-			var position = new CANNON.Vec3();
+			const position = new CANNON.Vec3();
 			position.set( array[ index + 12 ], array[ index + 13 ], array[ index + 14 ] );
 
-			var body = new CANNON.Body( {
+			const body = new CANNON.Body( {
 				position: position,
 				mass: mass,
 				shape: shape
@@ -161,12 +162,12 @@ function CannonPhysics() {
 
 		if ( mesh.isInstancedMesh ) {
 
-			var bodies = meshMap.get( mesh );
+			const bodies = meshMap.get( mesh );
 			bodies[ index ].position.copy( position );
 
 		} else if ( mesh.isMesh ) {
 
-			var body = meshMap.get( mesh );
+			const body = meshMap.get( mesh );
 			body.position.copy( position );
 
 		}
@@ -175,18 +176,18 @@ function CannonPhysics() {
 
 	//
 
-	var lastTime = 0;
+	let lastTime = 0;
 
 	function step() {
 
-		var time = performance.now();
+		const time = performance.now();
 
 		if ( lastTime > 0 ) {
 
-			var delta = ( time - lastTime ) / 1000;
+			const delta = ( time - lastTime ) / 1000;
 
 			// console.time( 'world.step' );
-			world.step( frameTime, delta, frameRate );
+			world.step( frameTime, delta );
 			// console.timeEnd( 'world.step' );
 
 		}
@@ -195,18 +196,18 @@ function CannonPhysics() {
 
 		//
 
-		for ( var i = 0, l = meshes.length; i < l; i ++ ) {
+		for ( let i = 0, l = meshes.length; i < l; i ++ ) {
 
-			var mesh = meshes[ i ];
+			const mesh = meshes[ i ];
 
 			if ( mesh.isInstancedMesh ) {
 
-				var array = mesh.instanceMatrix.array;
-				var bodies = meshMap.get( mesh );
+				const array = mesh.instanceMatrix.array;
+				const bodies = meshMap.get( mesh );
 
-				for ( var j = 0; j < bodies.length; j ++ ) {
+				for ( let j = 0; j < bodies.length; j ++ ) {
 
-					var body = bodies[ j ];
+					const body = bodies[ j ];
 					compose( body.position, body.quaternion, array, j * 16 );
 
 				}
@@ -215,7 +216,7 @@ function CannonPhysics() {
 
 			} else if ( mesh.isMesh ) {
 
-				var body = meshMap.get( mesh );
+				const body = meshMap.get( mesh );
 				mesh.position.copy( body.position );
 				mesh.quaternion.copy( body.quaternion );
 

BIN
examples/models/vox/menger.vox


BIN
examples/models/vox/monu10.vox


+ 9 - 24
examples/physics_cannon_instancing.html

@@ -33,8 +33,8 @@
 				//
 
 				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.1, 100 );
-				camera.position.set( - 1, 1, 2 );
-				camera.lookAt( 0, 0, 0 );
+				camera.position.set( - 1, 1.5, 2 );
+				camera.lookAt( 0, 0.5, 0 );
 
 				scene = new THREE.Scene();
 				scene.background = new THREE.Color( 0x666666 );
@@ -58,42 +58,25 @@
 				scene.add( plane );
 				physics.addMesh( plane );
 
-				/*
-				function getSize() {
-
-					return Math.random() * 0.1 + 0.05;
-
-				}
-				*/
-
 				var geometry = new THREE.BoxBufferGeometry( 0.1, 0.1, 0.1 );
-				var material = new THREE.MeshLambertMaterial( /*{ vertexColors: true }*/ );
+				var material = new THREE.MeshLambertMaterial();
 				var mesh = new THREE.InstancedMesh( geometry, material, 200 );
+				mesh.instanceMatrix.setUsage( THREE.DynamicDrawUsage ); // will be updated every frame
 				mesh.castShadow = true;
 				mesh.receiveShadow = true;
 				scene.add( mesh );
 
 				var matrix = new THREE.Matrix4();
+				var color = new THREE.Color();
 
 				for ( var i = 0; i < mesh.count; i ++ ) {
 
 					matrix.setPosition( Math.random() - 0.5, Math.random() * 2, Math.random() - 0.5 );
 					mesh.setMatrixAt( i, matrix );
+					mesh.setColorAt( i, color.setHex( 0xffffff * Math.random() ) );
 
 				}
 
-				/*
-				var instanceColors = [];
-
-				for ( var i = 0; i < mesh.count; i ++ ) {
-
-					instanceColors.push( Math.random(), Math.random(), Math.random() );
-
-				}
-
-				mesh.geometry.setAttribute( 'instanceColor', new THREE.InstancedBufferAttribute( new Float32Array( instanceColors ), 3 ) );
-				*/
-
 				physics.addMesh( mesh, 1 );
 
 				//
@@ -110,7 +93,9 @@
 
 				//
 
-				new OrbitControls( camera, renderer.domElement );
+				var controls = new OrbitControls( camera, renderer.domElement );
+				controls.target.y = 0.5;
+				controls.update();
 
 			}
 

BIN
examples/screenshots/physics_cannon_instancing.jpg


BIN
examples/screenshots/webgl2_volume_instancing.jpg


BIN
examples/screenshots/webgl_instancing_raycast.jpg


BIN
examples/screenshots/webgl_loader_3ds.jpg


BIN
examples/screenshots/webgl_loader_vox.jpg


BIN
examples/screenshots/webgl_materials_variations_toon.jpg


+ 258 - 0
examples/webgl2_volume_instancing.html

@@ -0,0 +1,258 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<title>three.js webgl2 - volume - instancing</title>
+		<meta charset="utf-8">
+		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+		<link type="text/css" rel="stylesheet" href="main.css">
+	</head>
+
+	<body>
+		<div id="info">
+			<a href="https://threejs.org" target="_blank" rel="noopener">three.js</a> webgl2 - volume - instancing
+		</div>
+
+		<script type="module">
+			import * as THREE from '../build/three.module.js';
+			import { OrbitControls } from './jsm/controls/OrbitControls.js';
+			import { VOXLoader } from './jsm/loaders/VOXLoader.js';
+
+			import { WEBGL } from './jsm/WebGL.js';
+
+			if ( WEBGL.isWebGL2Available() === false ) {
+
+				document.body.appendChild( WEBGL.getWebGL2ErrorMessage() );
+
+			}
+
+			let renderer, scene, camera;
+			let controls;
+
+			init();
+			animate();
+
+			function init() {
+
+				renderer = new THREE.WebGLRenderer();
+				renderer.setPixelRatio( window.devicePixelRatio );
+				renderer.setSize( window.innerWidth, window.innerHeight );
+				document.body.appendChild( renderer.domElement );
+
+				scene = new THREE.Scene();
+
+				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.1, 1000 );
+				camera.position.set( 0, 0, 4 );
+
+				controls = new OrbitControls( camera, renderer.domElement );
+				controls.autoRotate = true;
+				controls.autoRotateSpeed = - 1.0;
+				controls.enableDamping = true;
+
+				// Material
+
+				const vertexShader = `#version 300 es
+
+					in vec3 position;
+					in mat4 instanceMatrix;
+
+					uniform mat4 modelMatrix;
+					uniform mat4 modelViewMatrix;
+					uniform mat4 projectionMatrix;
+					uniform vec3 cameraPos;
+
+					out vec3 vOrigin;
+					out vec3 vDirection;
+
+					void main() {
+						vec4 mvPosition = modelViewMatrix * instanceMatrix * vec4( position, 1.0 );
+
+						vOrigin = vec3( inverse( instanceMatrix * modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz;
+						vDirection = position - vOrigin;
+
+						gl_Position = projectionMatrix * mvPosition;
+					}
+				`;
+
+				const fragmentShader = `#version 300 es
+					precision highp float;
+					precision highp sampler3D;
+
+					uniform mat4 modelViewMatrix;
+					uniform mat4 projectionMatrix;
+
+					in vec3 vOrigin;
+					in vec3 vDirection;
+
+					out vec4 color;
+
+					uniform sampler3D map;
+
+					uniform float threshold;
+					uniform float steps;
+
+					vec2 hitBox( vec3 orig, vec3 dir ) {
+						const vec3 box_min = vec3( - 0.5 );
+						const vec3 box_max = vec3( 0.5 );
+						vec3 inv_dir = 1.0 / dir;
+						vec3 tmin_tmp = ( box_min - orig ) * inv_dir;
+						vec3 tmax_tmp = ( box_max - orig ) * inv_dir;
+						vec3 tmin = min( tmin_tmp, tmax_tmp );
+						vec3 tmax = max( tmin_tmp, tmax_tmp );
+						float t0 = max( tmin.x, max( tmin.y, tmin.z ) );
+						float t1 = min( tmax.x, min( tmax.y, tmax.z ) );
+						return vec2( t0, t1 );
+					}
+
+					float sample1( vec3 p ) {
+						return texture( map, p ).r;
+					}
+
+					#define epsilon .0001
+
+					vec3 normal( vec3 coord ) {
+						if ( coord.x < epsilon ) return vec3( 1.0, 0.0, 0.0 );
+						if ( coord.y < epsilon ) return vec3( 0.0, 1.0, 0.0 );
+						if ( coord.z < epsilon ) return vec3( 0.0, 0.0, 1.0 );
+						if ( coord.x > 1.0 - epsilon ) return vec3( - 1.0, 0.0, 0.0 );
+						if ( coord.y > 1.0 - epsilon ) return vec3( 0.0, - 1.0, 0.0 );
+						if ( coord.z > 1.0 - epsilon ) return vec3( 0.0, 0.0, - 1.0 );
+
+						float step = 0.01;
+						float x = sample1( coord + vec3( - step, 0.0, 0.0 ) ) - sample1( coord + vec3( step, 0.0, 0.0 ) );
+						float y = sample1( coord + vec3( 0.0, - step, 0.0 ) ) - sample1( coord + vec3( 0.0, step, 0.0 ) );
+						float z = sample1( coord + vec3( 0.0, 0.0, - step ) ) - sample1( coord + vec3( 0.0, 0.0, step ) );
+
+						return normalize( vec3( x, y, z ) );
+					}
+
+					void main(){
+
+						vec3 rayDir = normalize( vDirection );
+						vec2 bounds = hitBox( vOrigin, rayDir );
+
+						if ( bounds.x > bounds.y ) discard;
+
+						bounds.x = max( bounds.x, 0.0 );
+
+						vec3 p = vOrigin + bounds.x * rayDir;
+						vec3 inc = 1.0 / abs( rayDir );
+						float delta = min( inc.x, min( inc.y, inc.z ) );
+						delta /= 50.0;
+
+						for ( float t = bounds.x; t < bounds.y; t += delta ) {
+
+							float d = sample1( p + 0.5 );
+
+							if ( d > 0.5 ) {
+
+								color.rgb = p * 2.0; // normal( p + 0.5 ); // * 0.5 + ( p * 1.5 + 0.25 );
+								color.a = 1.;
+								break;
+
+							}
+
+							p += rayDir * delta;
+
+						}
+
+						if ( color.a == 0.0 ) discard;
+
+					}
+				`;
+
+				var loader = new VOXLoader();
+				loader.load( 'models/vox/menger.vox', function ( chunks ) {
+
+					for ( var i = 0; i < chunks.length; i ++ ) {
+
+						const chunk = chunks[ i ];
+						const data = chunk.data;
+						const size = chunk.size;
+
+						const array = new Uint8Array( size.x * size.y * size.z );
+
+						console.log( size.x, size.y, size.z );
+
+						for ( var j = 0, k = 0; j < data.length; j += 4, k ++ ) {
+
+							const x = data[ j + 0 ];
+							const y = data[ j + 1 ];
+							const z = data[ j + 2 ];
+
+							const index = x + ( y * size.x ) + ( z * size.x * size.y );
+
+							array[ index ] = 255.0;
+
+						}
+
+						const texture = new THREE.DataTexture3D( array, size.x, size.y, size.z );
+						texture.format = THREE.RedFormat;
+						texture.minFilter = THREE.NearestFilter;
+						texture.magFilter = THREE.LinearFilter;
+						texture.unpackAlignment = 1;
+
+						const geometry = new THREE.BoxBufferGeometry( 1, 1, 1 );
+						const material = new THREE.RawShaderMaterial( {
+							uniforms: {
+								map: { value: texture },
+								cameraPos: { value: new THREE.Vector3() }
+							},
+							vertexShader,
+							fragmentShader,
+							side: THREE.BackSide
+						} );
+
+						const mesh = new THREE.InstancedMesh( geometry, material, 100000 );
+						mesh.onBeforeRender = function () {
+
+							this.material.uniforms.cameraPos.value.copy( camera.position );
+
+						};
+
+						const transform = new THREE.Object3D();
+
+						for ( let i = 0; i < mesh.count; i ++ ) {
+
+							transform.position.random().subScalar( 0.5 ).multiplyScalar( 150 );
+							transform.rotation.x = Math.random() * Math.PI;
+							transform.rotation.y = Math.random() * Math.PI;
+							transform.rotation.z = Math.random() * Math.PI;
+							transform.updateMatrix();
+
+							mesh.setMatrixAt( i, transform.matrix );
+
+						}
+
+						scene.add( mesh );
+
+					}
+
+				} );
+
+				window.addEventListener( 'resize', onWindowResize, false );
+
+			}
+
+			function onWindowResize() {
+
+				camera.aspect = window.innerWidth / window.innerHeight;
+				camera.updateProjectionMatrix();
+
+				renderer.setSize( window.innerWidth, window.innerHeight );
+
+			}
+
+			function animate() {
+
+				requestAnimationFrame( animate );
+
+				controls.update();
+
+				renderer.render( scene, camera );
+
+			}
+
+		</script>
+
+	</body>
+</html>

+ 2 - 2
examples/webgl2_volume_perlin.html

@@ -91,12 +91,12 @@
 					out vec3 vDirection;
 
 					void main() {
-						vec4 worldPosition = modelViewMatrix * vec4( position, 1.0 );
+						vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );
 
 						vOrigin = vec3( inverse( modelMatrix ) * vec4( cameraPos, 1.0 ) ).xyz;
 						vDirection = position - vOrigin;
 
-						gl_Position = projectionMatrix * worldPosition;
+						gl_Position = projectionMatrix * mvPosition;
 					}
 				`;
 

+ 18 - 16
examples/webgl_buffergeometry_compression.html

@@ -106,7 +106,7 @@
 
 				//
 
-				var geom = newGeometry(data);
+				var geom = newGeometry( data );
 
 				var mesh = new THREE.Mesh( geom, meshMaterial );
 				var lineSegments = new THREE.LineSegments( new THREE.WireframeGeometry( geom ), lineMaterial );
@@ -120,24 +120,26 @@
 				gui = new GUI();
 				gui.width = 350;
 
-				function newGeometry(data) {
+				function newGeometry( data ) {
 
-					switch (data.model) {
-						case "Icosahedron": 
+					switch ( data.model ) {
+
+						case "Icosahedron":
 							return new THREE.IcosahedronBufferGeometry( radius, data.detail );
-						case "Cylinder": 
+						case "Cylinder":
 							return new THREE.CylinderBufferGeometry( radius, radius, radius * 2, data.detail * 6 );
-						case "Teapot": 
+						case "Teapot":
 							return new TeapotBufferGeometry( radius, data.detail * 3, true, true, true, true, true );
-						case "TorusKnot": 
+						case "TorusKnot":
 							return new THREE.TorusKnotBufferGeometry( radius, 10, data.detail * 20, data.detail * 6, 3, 4 );
-					}
+
+		}
 
 				}
 
 				function generateGeometry() {
 
-					geom = newGeometry(data);
+					geom = newGeometry( data );
 
 					updateGroupGeometry(
 						mesh,
@@ -155,7 +157,7 @@
 				}
 
 				var folder = gui.addFolder( 'Scene' );
-				folder.add( data, 'model', ["Icosahedron", "Cylinder", "TorusKnot", "Teapot"] ).onChange( generateGeometry );
+				folder.add( data, 'model', [ "Icosahedron", "Cylinder", "TorusKnot", "Teapot" ] ).onChange( generateGeometry );
 				folder.add( data, 'wireframe', false ).onChange( updateLineSegments );
 				folder.add( data, 'texture', false ).onChange( generateGeometry );
 				folder.add( data, 'detail', 1, 8, 1 ).onChange( generateGeometry );
@@ -167,7 +169,7 @@
 				folder.open();
 
 				folder = gui.addFolder( 'Normal Compression' );
-				folder.add( data, 'NormEncodingMethods', ["None", "DEFAULT", "OCT1Byte", "OCT2Byte", "ANGLES"] ).onChange( generateGeometry );
+				folder.add( data, 'NormEncodingMethods', [ "None", "DEFAULT", "OCT1Byte", "OCT2Byte", "ANGLES" ] ).onChange( generateGeometry );
 				folder.open();
 
 				folder = gui.addFolder( 'UV Compression' );
@@ -252,19 +254,19 @@
 				mesh.material = new THREE.MeshPhongMaterial( { color: 0xffffff, emissive: 0x111111 } );
 				mesh.material.map = data.texture ? texture : null;
 
-				if ( data["QuantizePosEncoding"] ) {
+				if ( data[ "QuantizePosEncoding" ] ) {
 
 					GeometryCompressionUtils.compressPositions( mesh );
 
 				}
 
-				if ( data["NormEncodingMethods"] !== "None" ) {
+				if ( data[ "NormEncodingMethods" ] !== "None" ) {
 
-					GeometryCompressionUtils.compressNormals( mesh, data["NormEncodingMethods"] );
+					GeometryCompressionUtils.compressNormals( mesh, data[ "NormEncodingMethods" ] );
 
 				}
 
-				if ( data["DefaultUVEncoding"] ) {
+				if ( data[ "DefaultUVEncoding" ] ) {
 
 					GeometryCompressionUtils.compressUvs( mesh );
 
@@ -278,7 +280,7 @@
 			function computeGPUMemory( mesh ) {
 
 				// Use BufferGeometryUtils to do memory calculation
-				memoryDisplay.setValue( BufferGeometryUtils.estimateBytesUsed(mesh.geometry) + " bytes");
+				memoryDisplay.setValue( BufferGeometryUtils.estimateBytesUsed( mesh.geometry ) + " bytes" );
 
 			}
 

+ 11 - 14
examples/webgl_instancing_raycast.html

@@ -24,9 +24,7 @@
 			var raycaster = new THREE.Raycaster();
 			var mouse = new THREE.Vector2( 1, 1 );
 
-			var rotationMatrix = new THREE.Matrix4().makeRotationY( 0.1 );
-			var instanceMatrix = new THREE.Matrix4();
-			var matrix = new THREE.Matrix4();
+			var color = new THREE.Color();
 
 			init();
 			animate();
@@ -47,15 +45,15 @@
 				light.position.set( - 1, - 1.5, - 1 );
 				scene.add( light );
 
-				var geometry = new THREE.SphereBufferGeometry( 0.5 );
-				var material = new THREE.MeshPhongMaterial( { flatShading: true } );
+				var geometry = new THREE.IcosahedronGeometry( 0.5, 2 );
+				var material = new THREE.MeshPhongMaterial();
 
 				mesh = new THREE.InstancedMesh( geometry, material, count );
 
 				var i = 0;
 				var offset = ( amount - 1 ) / 2;
 
-				var transform = new THREE.Object3D();
+				var matrix = new THREE.Matrix4();
 
 				for ( var x = 0; x < amount; x ++ ) {
 
@@ -63,10 +61,12 @@
 
 						for ( var z = 0; z < amount; z ++ ) {
 
-							transform.position.set( offset - x, offset - y, offset - z );
-							transform.updateMatrix();
+							matrix.setPosition( offset - x, offset - y, offset - z );
 
-							mesh.setMatrixAt( i ++, transform.matrix );
+							mesh.setMatrixAt( i, matrix );
+							mesh.setColorAt( i, color );
+
+							i ++;
 
 						}
 
@@ -132,11 +132,8 @@
 
 					var instanceId = intersection[ 0 ].instanceId;
 
-					mesh.getMatrixAt( instanceId, instanceMatrix );
-					matrix.multiplyMatrices( instanceMatrix, rotationMatrix );
-
-					mesh.setMatrixAt( instanceId, matrix );
-					mesh.instanceMatrix.needsUpdate = true;
+					mesh.setColorAt( instanceId, color.setHex( Math.random() * 0xffffff ) );
+					mesh.instanceColor.needsUpdate = true;
 
 				}
 

+ 2 - 0
examples/webgl_loader_3ds.html

@@ -52,6 +52,7 @@
 
 						if ( child.isMesh ) {
 
+							child.material.specular.setScalar( 0.1 );
 							child.material.normalMap = normal;
 
 						}
@@ -65,6 +66,7 @@
 				renderer = new THREE.WebGLRenderer();
 				renderer.setPixelRatio( window.devicePixelRatio );
 				renderer.setSize( window.innerWidth, window.innerHeight );
+				renderer.outputEncoding = THREE.sRGBEncoding;
 				container.appendChild( renderer.domElement );
 
 				controls = new TrackballControls( camera, renderer.domElement );

+ 54 - 7
examples/webgl_loader_vox.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <html lang="en">
 	<head>
-		<title>three.js webgl - loaders - vox loader</title>
+		<title>three.js webgl - loaders - vox</title>
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<link type="text/css" rel="stylesheet" href="main.css">
@@ -28,18 +28,28 @@
 
 			function init() {
 
-				camera = new THREE.PerspectiveCamera( 60, window.innerWidth / window.innerHeight, 0.01, 1e10 );
-				camera.position.set( 0, 0.1, 0.2 );
+				camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.01, 10 );
+				camera.position.set( 0.175, 0.075, 0.175 );
 
 				scene = new THREE.Scene();
 				scene.add( camera );
 
+				// light
+
+				var hemiLight = new THREE.HemisphereLight( 0x888888, 0x000000, 1 );
+				scene.add( hemiLight );
+
+				var dirLight = new THREE.DirectionalLight( 0xffffff, 0.75 );
+				dirLight.position.set( 1.5, 3, 2.5 );
+				scene.add( dirLight );
+
 				var loader = new VOXLoader();
-				loader.load( 'models/vox/teapot.vox', function ( chunks ) {
+				loader.load( 'models/vox/monu10.vox', function ( chunks ) {
 
 					const geometry = new THREE.BoxBufferGeometry( 1, 1, 1 );
-					const material = new THREE.MeshNormalMaterial();
+					const material = new THREE.MeshStandardMaterial();
 
+					const color = new THREE.Color();
 					const matrix = new THREE.Matrix4();
 
 					for ( var i = 0; i < chunks.length; i ++ ) {
@@ -48,6 +58,9 @@
 
 						const size = chunk.size;
 						const data = chunk.data;
+						const palette = chunk.palette;
+
+						// displayPalette( palette );
 
 						const mesh = new THREE.InstancedMesh( geometry, material, data.length / 4 );
 						mesh.scale.setScalar( 0.0015 );
@@ -58,7 +71,14 @@
 							const x = data[ j + 0 ] - size.x / 2;
 							const y = data[ j + 1 ] - size.y / 2;
 							const z = data[ j + 2 ] - size.z / 2;
+							const c = data[ j + 3 ];
 
+							const hex = palette[ c ];
+							const r = ( hex >> 0 & 0xff ) / 0xff;
+							const g = ( hex >> 8 & 0xff ) / 0xff;
+							const b = ( hex >> 16 & 0xff ) / 0xff;
+
+							mesh.setColorAt( k, color.setRGB( r, g, b ) );
 							mesh.setMatrixAt( k, matrix.setPosition( x, z, - y ) );
 
 						}
@@ -89,6 +109,35 @@
 
 			}
 
+			function displayPalette( palette ) {
+
+				const canvas = document.createElement( 'canvas' );
+				canvas.width = 8;
+				canvas.height = 32;
+				canvas.style.position = 'absolute';
+				canvas.style.top = '0';
+				canvas.style.width = 100 + 'px';
+				canvas.style.imageRendering = 'pixelated';
+				document.body.appendChild( canvas );
+
+				const context = canvas.getContext( '2d' );
+
+				for ( var c = 0; c < 256; c ++ ) {
+
+					const x = c % 8;
+					const y = Math.floor( c / 8 );
+
+					const hex = palette[ c + 1 ];
+					const r = hex >> 0 & 0xff;
+					const g = hex >> 8 & 0xff;
+					const b = hex >> 16 & 0xff;
+					context.fillStyle = `rgba(${r},${g},${b},1)`;
+					context.fillRect( x, 31 - y, 1, 1 );
+
+				}
+
+			}
+
 			function onWindowResize() {
 
 				camera.aspect = window.innerWidth / window.innerHeight;
@@ -96,8 +145,6 @@
 
 				renderer.setSize( window.innerWidth, window.innerHeight );
 
-				controls.handleResize();
-
 			}
 
 			function animate() {

+ 2 - 6
examples/webgl_materials_variations_toon.html

@@ -129,13 +129,9 @@
 
 				// Lights
 
-				scene.add( new THREE.AmbientLight( 0x111111 ) );
+				scene.add( new THREE.AmbientLight( 0x888888 ) );
 
-				var directionalLight = new THREE.DirectionalLight( 0xffffff, 1 );
-				directionalLight.position.set( 1, 1, 1 ).normalize();
-				scene.add( directionalLight );
-
-				var pointLight = new THREE.PointLight( 0xffffff, 1.75, 800 );
+				var pointLight = new THREE.PointLight( 0xffffff, 2, 800 );
 				particleLight.add( pointLight );
 
 				//

+ 7 - 0
package.json

@@ -41,6 +41,13 @@
         {
           "SwitchCase": 1
         }
+      ],
+      "prefer-const": [
+        "error",
+        {
+          "destructuring": "any",
+          "ignoreReadBeforeAssign": false
+        }
       ]
     }
   },

+ 13 - 0
src/Three.Legacy.js

@@ -88,6 +88,7 @@ import { WebGLShadowMap } from './renderers/webgl/WebGLShadowMap.js';
 import { ImageUtils } from './extras/ImageUtils.js';
 import { Shape } from './extras/core/Shape.js';
 import { CubeCamera } from './cameras/CubeCamera.js';
+import { Scene } from './scenes/Scene.js';
 
 export { BoxGeometry as CubeGeometry };
 export { MathUtils as Math };
@@ -1467,6 +1468,18 @@ Object.assign( ExtrudeBufferGeometry.prototype, {
 
 //
 
+Object.assign( Scene.prototype, {
+
+	dispose: function () {
+
+		console.error( 'THREE.Scene: .dispose() has been removed.' );
+
+	}
+
+} );
+
+//
+
 Object.defineProperties( Uniform.prototype, {
 
 	dynamic: {

+ 108 - 107
src/animation/AnimationAction.js

@@ -1,92 +1,93 @@
 import { WrapAroundEnding, ZeroCurvatureEnding, ZeroSlopeEnding, LoopPingPong, LoopOnce, LoopRepeat, NormalAnimationBlendMode, AdditiveAnimationBlendMode } from '../constants.js';
 
-function AnimationAction( mixer, clip, localRoot, blendMode ) {
 
-	this._mixer = mixer;
-	this._clip = clip;
-	this._localRoot = localRoot || null;
-	this.blendMode = blendMode || clip.blendMode;
+class AnimationAction {
 
-	const tracks = clip.tracks,
-		nTracks = tracks.length,
-		interpolants = new Array( nTracks );
+	constructor( mixer, clip, localRoot, blendMode ) {
 
-	const interpolantSettings = {
-		endingStart: ZeroCurvatureEnding,
-		endingEnd: ZeroCurvatureEnding
-	};
+		this._mixer = mixer;
+		this._clip = clip;
+		this._localRoot = localRoot || null;
+		this.blendMode = blendMode || clip.blendMode;
 
-	for ( let i = 0; i !== nTracks; ++ i ) {
+		const tracks = clip.tracks,
+			nTracks = tracks.length,
+			interpolants = new Array( nTracks );
 
-		const interpolant = tracks[ i ].createInterpolant( null );
-		interpolants[ i ] = interpolant;
-		interpolant.settings = interpolantSettings;
+		const interpolantSettings = {
+			endingStart: ZeroCurvatureEnding,
+			endingEnd: ZeroCurvatureEnding
+		};
 
-	}
+		for ( let i = 0; i !== nTracks; ++ i ) {
 
-	this._interpolantSettings = interpolantSettings;
+			const interpolant = tracks[ i ].createInterpolant( null );
+			interpolants[ i ] = interpolant;
+			interpolant.settings = interpolantSettings;
 
-	this._interpolants = interpolants; // bound by the mixer
+		}
 
-	// inside: PropertyMixer (managed by the mixer)
-	this._propertyBindings = new Array( nTracks );
+		this._interpolantSettings = interpolantSettings;
 
-	this._cacheIndex = null; // for the memory manager
-	this._byClipCacheIndex = null; // for the memory manager
+		this._interpolants = interpolants; // bound by the mixer
 
-	this._timeScaleInterpolant = null;
-	this._weightInterpolant = null;
+		// inside: PropertyMixer (managed by the mixer)
+		this._propertyBindings = new Array( nTracks );
 
-	this.loop = LoopRepeat;
-	this._loopCount = - 1;
+		this._cacheIndex = null; // for the memory manager
+		this._byClipCacheIndex = null; // for the memory manager
 
-	// global mixer time when the action is to be started
-	// it's set back to 'null' upon start of the action
-	this._startTime = null;
+		this._timeScaleInterpolant = null;
+		this._weightInterpolant = null;
 
-	// scaled local time of the action
-	// gets clamped or wrapped to 0..clip.duration according to loop
-	this.time = 0;
+		this.loop = LoopRepeat;
+		this._loopCount = - 1;
 
-	this.timeScale = 1;
-	this._effectiveTimeScale = 1;
+		// global mixer time when the action is to be started
+		// it's set back to 'null' upon start of the action
+		this._startTime = null;
 
-	this.weight = 1;
-	this._effectiveWeight = 1;
+		// scaled local time of the action
+		// gets clamped or wrapped to 0..clip.duration according to loop
+		this.time = 0;
 
-	this.repetitions = Infinity; // no. of repetitions when looping
+		this.timeScale = 1;
+		this._effectiveTimeScale = 1;
 
-	this.paused = false; // true -> zero effective time scale
-	this.enabled = true; // false -> zero effective weight
+		this.weight = 1;
+		this._effectiveWeight = 1;
 
-	this.clampWhenFinished = false;// keep feeding the last frame?
+		this.repetitions = Infinity; // no. of repetitions when looping
 
-	this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate
-	this.zeroSlopeAtEnd = true;// clips for start, loop and end
+		this.paused = false; // true -> zero effective time scale
+		this.enabled = true; // false -> zero effective weight
 
-}
+		this.clampWhenFinished = false;// keep feeding the last frame?
 
-Object.assign( AnimationAction.prototype, {
+		this.zeroSlopeAtStart = true;// for smooth interpolation w/o separate
+		this.zeroSlopeAtEnd = true;// clips for start, loop and end
+
+	}
 
 	// State & Scheduling
 
-	play: function () {
+	play() {
 
 		this._mixer._activateAction( this );
 
 		return this;
 
-	},
+	}
 
-	stop: function () {
+	stop() {
 
 		this._mixer._deactivateAction( this );
 
 		return this.reset();
 
-	},
+	}
 
-	reset: function () {
+	reset() {
 
 		this.paused = false;
 		this.enabled = true;
@@ -97,45 +98,45 @@ Object.assign( AnimationAction.prototype, {
 
 		return this.stopFading().stopWarping();
 
-	},
+	}
 
-	isRunning: function () {
+	isRunning() {
 
 		return this.enabled && ! this.paused && this.timeScale !== 0 &&
 			this._startTime === null && this._mixer._isActiveAction( this );
 
-	},
+	}
 
 	// return true when play has been called
-	isScheduled: function () {
+	isScheduled() {
 
 		return this._mixer._isActiveAction( this );
 
-	},
+	}
 
-	startAt: function ( time ) {
+	startAt( time ) {
 
 		this._startTime = time;
 
 		return this;
 
-	},
+	}
 
-	setLoop: function ( mode, repetitions ) {
+	setLoop( mode, repetitions ) {
 
 		this.loop = mode;
 		this.repetitions = repetitions;
 
 		return this;
 
-	},
+	}
 
 	// Weight
 
 	// set the weight stopping any scheduled fading
 	// although .enabled = false yields an effective weight of zero, this
 	// method does *not* change .enabled, because it would be confusing
-	setEffectiveWeight: function ( weight ) {
+	setEffectiveWeight( weight ) {
 
 		this.weight = weight;
 
@@ -144,28 +145,28 @@ Object.assign( AnimationAction.prototype, {
 
 		return this.stopFading();
 
-	},
+	}
 
 	// return the weight considering fading and .enabled
-	getEffectiveWeight: function () {
+	getEffectiveWeight() {
 
 		return this._effectiveWeight;
 
-	},
+	}
 
-	fadeIn: function ( duration ) {
+	fadeIn( duration ) {
 
 		return this._scheduleFading( duration, 0, 1 );
 
-	},
+	}
 
-	fadeOut: function ( duration ) {
+	fadeOut( duration ) {
 
 		return this._scheduleFading( duration, 1, 0 );
 
-	},
+	}
 
-	crossFadeFrom: function ( fadeOutAction, duration, warp ) {
+	crossFadeFrom( fadeOutAction, duration, warp ) {
 
 		fadeOutAction.fadeOut( duration );
 		this.fadeIn( duration );
@@ -185,17 +186,17 @@ Object.assign( AnimationAction.prototype, {
 
 		return this;
 
-	},
+	}
 
-	crossFadeTo: function ( fadeInAction, duration, warp ) {
+	crossFadeTo( fadeInAction, duration, warp ) {
 
 		return fadeInAction.crossFadeFrom( this, duration, warp );
 
-	},
+	}
 
-	stopFading: function () {
+	stopFading() {
 
-		let weightInterpolant = this._weightInterpolant;
+		const weightInterpolant = this._weightInterpolant;
 
 		if ( weightInterpolant !== null ) {
 
@@ -206,53 +207,53 @@ Object.assign( AnimationAction.prototype, {
 
 		return this;
 
-	},
+	}
 
 	// Time Scale Control
 
 	// set the time scale stopping any scheduled warping
 	// although .paused = true yields an effective time scale of zero, this
 	// method does *not* change .paused, because it would be confusing
-	setEffectiveTimeScale: function ( timeScale ) {
+	setEffectiveTimeScale( timeScale ) {
 
 		this.timeScale = timeScale;
 		this._effectiveTimeScale = this.paused ? 0 : timeScale;
 
 		return this.stopWarping();
 
-	},
+	}
 
 	// return the time scale considering warping and .paused
-	getEffectiveTimeScale: function () {
+	getEffectiveTimeScale() {
 
 		return this._effectiveTimeScale;
 
-	},
+	}
 
-	setDuration: function ( duration ) {
+	setDuration( duration ) {
 
 		this.timeScale = this._clip.duration / duration;
 
 		return this.stopWarping();
 
-	},
+	}
 
-	syncWith: function ( action ) {
+	syncWith( action ) {
 
 		this.time = action.time;
 		this.timeScale = action.timeScale;
 
 		return this.stopWarping();
 
-	},
+	}
 
-	halt: function ( duration ) {
+	halt( duration ) {
 
 		return this.warp( this._effectiveTimeScale, 0, duration );
 
-	},
+	}
 
-	warp: function ( startTimeScale, endTimeScale, duration ) {
+	warp( startTimeScale, endTimeScale, duration ) {
 
 		const mixer = this._mixer,
 			now = mixer.time,
@@ -278,11 +279,11 @@ Object.assign( AnimationAction.prototype, {
 
 		return this;
 
-	},
+	}
 
-	stopWarping: function () {
+	stopWarping() {
 
-		let timeScaleInterpolant = this._timeScaleInterpolant;
+		const timeScaleInterpolant = this._timeScaleInterpolant;
 
 		if ( timeScaleInterpolant !== null ) {
 
@@ -293,31 +294,31 @@ Object.assign( AnimationAction.prototype, {
 
 		return this;
 
-	},
+	}
 
 	// Object Accessors
 
-	getMixer: function () {
+	getMixer() {
 
 		return this._mixer;
 
-	},
+	}
 
-	getClip: function () {
+	getClip() {
 
 		return this._clip;
 
-	},
+	}
 
-	getRoot: function () {
+	getRoot() {
 
 		return this._localRoot || this._mixer._root;
 
-	},
+	}
 
 	// Interna
 
-	_update: function ( time, deltaTime, timeDirection, accuIndex ) {
+	_update( time, deltaTime, timeDirection, accuIndex ) {
 
 		// called by the mixer
 
@@ -392,9 +393,9 @@ Object.assign( AnimationAction.prototype, {
 
 		}
 
-	},
+	}
 
-	_updateWeight: function ( time ) {
+	_updateWeight( time ) {
 
 		let weight = 0;
 
@@ -429,9 +430,9 @@ Object.assign( AnimationAction.prototype, {
 		this._effectiveWeight = weight;
 		return weight;
 
-	},
+	}
 
-	_updateTimeScale: function ( time ) {
+	_updateTimeScale( time ) {
 
 		let timeScale = 0;
 
@@ -472,9 +473,9 @@ Object.assign( AnimationAction.prototype, {
 		this._effectiveTimeScale = timeScale;
 		return timeScale;
 
-	},
+	}
 
-	_updateTime: function ( deltaTime ) {
+	_updateTime( deltaTime ) {
 
 		const duration = this._clip.duration;
 		const loop = this.loop;
@@ -629,9 +630,9 @@ Object.assign( AnimationAction.prototype, {
 
 		return time;
 
-	},
+	}
 
-	_setEndings: function ( atStart, atEnd, pingPong ) {
+	_setEndings( atStart, atEnd, pingPong ) {
 
 		const settings = this._interpolantSettings;
 
@@ -666,9 +667,9 @@ Object.assign( AnimationAction.prototype, {
 
 		}
 
-	},
+	}
 
-	_scheduleFading: function ( duration, weightNow, weightThen ) {
+	_scheduleFading( duration, weightNow, weightThen ) {
 
 		const mixer = this._mixer, now = mixer.time;
 		let interpolant = this._weightInterpolant;
@@ -692,7 +693,7 @@ Object.assign( AnimationAction.prototype, {
 
 	}
 
-} );
+}
 
 
 export { AnimationAction };

+ 2 - 2
src/animation/AnimationMixer.js

@@ -521,8 +521,8 @@ AnimationMixer.prototype = Object.assign( Object.create( EventDispatcher.prototy
 
 		const clipUuid = clipObject !== null ? clipObject.uuid : clip;
 
-		let actionsForClip = this._actionsByClip[ clipUuid ],
-			prototypeAction = null;
+		const actionsForClip = this._actionsByClip[ clipUuid ];
+		let prototypeAction = null;
 
 		if ( blendMode === undefined ) {
 

+ 3 - 3
src/animation/AnimationObjectGroup.js

@@ -313,9 +313,9 @@ Object.assign( AnimationObjectGroup.prototype, {
 		// returns an array of bindings for the given path that is changed
 		// according to the contained objects in the group
 
-		let indicesByPath = this._bindingsIndicesByPath,
-			index = indicesByPath[ path ],
-			bindings = this._bindings;
+		const indicesByPath = this._bindingsIndicesByPath;
+		let index = indicesByPath[ path ];
+		const bindings = this._bindings;
 
 		if ( index !== undefined ) return bindings[ index ];
 

+ 5 - 5
src/animation/PropertyBinding.js

@@ -445,12 +445,12 @@ Object.assign( PropertyBinding.prototype, { // prototype, continued
 	// create getter / setter pair for a property in the scene graph
 	bind: function () {
 
-		let targetObject = this.node,
-			parsedPath = this.parsedPath,
+		let targetObject = this.node;
+		const parsedPath = this.parsedPath;
 
-			objectName = parsedPath.objectName,
-			propertyName = parsedPath.propertyName,
-			propertyIndex = parsedPath.propertyIndex;
+		const objectName = parsedPath.objectName;
+		const propertyName = parsedPath.propertyName;
+		let propertyIndex = parsedPath.propertyIndex;
 
 		if ( ! targetObject ) {
 

+ 74 - 76
src/audio/Audio.js

@@ -1,49 +1,47 @@
 import { Object3D } from '../core/Object3D.js';
 
-function Audio( listener ) {
+class Audio extends Object3D {
 
-	Object3D.call( this );
+	constructor( listener ) {
 
-	this.type = 'Audio';
+		super();
 
-	this.listener = listener;
-	this.context = listener.context;
+		this.type = 'Audio';
 
-	this.gain = this.context.createGain();
-	this.gain.connect( listener.getInput() );
+		this.listener = listener;
+		this.context = listener.context;
 
-	this.autoplay = false;
+		this.gain = this.context.createGain();
+		this.gain.connect( listener.getInput() );
 
-	this.buffer = null;
-	this.detune = 0;
-	this.loop = false;
-	this.loopStart = 0;
-	this.loopEnd = 0;
-	this.offset = 0;
-	this.duration = undefined;
-	this.playbackRate = 1;
-	this.isPlaying = false;
-	this.hasPlaybackControl = true;
-	this.sourceType = 'empty';
+		this.autoplay = false;
 
-	this._startedAt = 0;
-	this._progress = 0;
-
-	this.filters = [];
+		this.buffer = null;
+		this.detune = 0;
+		this.loop = false;
+		this.loopStart = 0;
+		this.loopEnd = 0;
+		this.offset = 0;
+		this.duration = undefined;
+		this.playbackRate = 1;
+		this.isPlaying = false;
+		this.hasPlaybackControl = true;
+		this.sourceType = 'empty';
 
-}
+		this._startedAt = 0;
+		this._progress = 0;
 
-Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
+		this.filters = [];
 
-	constructor: Audio,
+	}
 
-	getOutput: function () {
+	getOutput() {
 
 		return this.gain;
 
-	},
+	}
 
-	setNodeSource: function ( audioNode ) {
+	setNodeSource( audioNode ) {
 
 		this.hasPlaybackControl = false;
 		this.sourceType = 'audioNode';
@@ -52,9 +50,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	setMediaElementSource: function ( mediaElement ) {
+	setMediaElementSource( mediaElement ) {
 
 		this.hasPlaybackControl = false;
 		this.sourceType = 'mediaNode';
@@ -63,9 +61,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	setMediaStreamSource: function ( mediaStream ) {
+	setMediaStreamSource( mediaStream ) {
 
 		this.hasPlaybackControl = false;
 		this.sourceType = 'mediaStreamNode';
@@ -74,9 +72,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	setBuffer: function ( audioBuffer ) {
+	setBuffer( audioBuffer ) {
 
 		this.buffer = audioBuffer;
 		this.sourceType = 'buffer';
@@ -85,9 +83,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	play: function ( delay ) {
+	play( delay ) {
 
 		if ( delay === undefined ) delay = 0;
 
@@ -124,9 +122,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this.connect();
 
-	},
+	}
 
-	pause: function () {
+	pause() {
 
 		if ( this.hasPlaybackControl === false ) {
 
@@ -158,9 +156,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	stop: function () {
+	stop() {
 
 		if ( this.hasPlaybackControl === false ) {
 
@@ -177,9 +175,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	connect: function () {
+	connect() {
 
 		if ( this.filters.length > 0 ) {
 
@@ -201,9 +199,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	disconnect: function () {
+	disconnect() {
 
 		if ( this.filters.length > 0 ) {
 
@@ -225,15 +223,15 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	getFilters: function () {
+	getFilters() {
 
 		return this.filters;
 
-	},
+	}
 
-	setFilters: function ( value ) {
+	setFilters( value ) {
 
 		if ( ! value ) value = [];
 
@@ -251,9 +249,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	setDetune: function ( value ) {
+	setDetune( value ) {
 
 		this.detune = value;
 
@@ -267,27 +265,27 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	getDetune: function () {
+	getDetune() {
 
 		return this.detune;
 
-	},
+	}
 
-	getFilter: function () {
+	getFilter() {
 
 		return this.getFilters()[ 0 ];
 
-	},
+	}
 
-	setFilter: function ( filter ) {
+	setFilter( filter ) {
 
 		return this.setFilters( filter ? [ filter ] : [] );
 
-	},
+	}
 
-	setPlaybackRate: function ( value ) {
+	setPlaybackRate( value ) {
 
 		if ( this.hasPlaybackControl === false ) {
 
@@ -306,21 +304,21 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	getPlaybackRate: function () {
+	getPlaybackRate() {
 
 		return this.playbackRate;
 
-	},
+	}
 
-	onEnded: function () {
+	onEnded() {
 
 		this.isPlaying = false;
 
-	},
+	}
 
-	getLoop: function () {
+	getLoop() {
 
 		if ( this.hasPlaybackControl === false ) {
 
@@ -331,9 +329,9 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this.loop;
 
-	},
+	}
 
-	setLoop: function ( value ) {
+	setLoop( value ) {
 
 		if ( this.hasPlaybackControl === false ) {
 
@@ -352,31 +350,31 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	setLoopStart: function ( value ) {
+	setLoopStart( value ) {
 
 		this.loopStart = value;
 
 		return this;
 
-	},
+	}
 
-	setLoopEnd: function ( value ) {
+	setLoopEnd( value ) {
 
 		this.loopEnd = value;
 
 		return this;
 
-	},
+	}
 
-	getVolume: function () {
+	getVolume() {
 
 		return this.gain.gain.value;
 
-	},
+	}
 
-	setVolume: function ( value ) {
+	setVolume( value ) {
 
 		this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
 
@@ -384,6 +382,6 @@ Audio.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 	}
 
-} );
+}
 
 export { Audio };

+ 12 - 11
src/audio/AudioAnalyser.js

@@ -1,25 +1,26 @@
-function AudioAnalyser( audio, fftSize ) {
+class AudioAnalyser {
 
-	this.analyser = audio.context.createAnalyser();
-	this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048;
+	constructor( audio, fftSize ) {
 
-	this.data = new Uint8Array( this.analyser.frequencyBinCount );
+		this.analyser = audio.context.createAnalyser();
+		this.analyser.fftSize = fftSize !== undefined ? fftSize : 2048;
 
-	audio.getOutput().connect( this.analyser );
+		this.data = new Uint8Array( this.analyser.frequencyBinCount );
 
-}
+		audio.getOutput().connect( this.analyser );
+
+	}
 
-Object.assign( AudioAnalyser.prototype, {
 
-	getFrequencyData: function () {
+	getFrequencyData() {
 
 		this.analyser.getByteFrequencyData( this.data );
 
 		return this.data;
 
-	},
+	}
 
-	getAverageFrequency: function () {
+	getAverageFrequency() {
 
 		let value = 0;
 		const data = this.getFrequencyData();
@@ -34,6 +35,6 @@ Object.assign( AudioAnalyser.prototype, {
 
 	}
 
-} );
+}
 
 export { AudioAnalyser };

+ 27 - 29
src/audio/AudioListener.js

@@ -9,38 +9,36 @@ const _quaternion = new Quaternion();
 const _scale = new Vector3();
 const _orientation = new Vector3();
 
-function AudioListener() {
+class AudioListener extends Object3D {
 
-	Object3D.call( this );
+	constructor() {
 
-	this.type = 'AudioListener';
+		super();
 
-	this.context = AudioContext.getContext();
+		this.type = 'AudioListener';
 
-	this.gain = this.context.createGain();
-	this.gain.connect( this.context.destination );
+		this.context = AudioContext.getContext();
 
-	this.filter = null;
+		this.gain = this.context.createGain();
+		this.gain.connect( this.context.destination );
 
-	this.timeDelta = 0;
+		this.filter = null;
 
-	// private
+		this.timeDelta = 0;
 
-	this._clock = new Clock();
+		// private
 
-}
-
-AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {
+		this._clock = new Clock();
 
-	constructor: AudioListener,
+	}
 
-	getInput: function () {
+	getInput() {
 
 		return this.gain;
 
-	},
+	}
 
-	removeFilter: function ( ) {
+	removeFilter() {
 
 		if ( this.filter !== null ) {
 
@@ -53,15 +51,15 @@ AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	getFilter: function () {
+	getFilter() {
 
 		return this.filter;
 
-	},
+	}
 
-	setFilter: function ( value ) {
+	setFilter( value ) {
 
 		if ( this.filter !== null ) {
 
@@ -80,25 +78,25 @@ AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	getMasterVolume: function () {
+	getMasterVolume() {
 
 		return this.gain.gain.value;
 
-	},
+	}
 
-	setMasterVolume: function ( value ) {
+	setMasterVolume( value ) {
 
 		this.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );
 
 		return this;
 
-	},
+	}
 
-	updateMatrixWorld: function ( force ) {
+	updateMatrixWorld( force ) {
 
-		Object3D.prototype.updateMatrixWorld.call( this, force );
+		super.updateMatrixWorld( force );
 
 		const listener = this.context.listener;
 		const up = this.up;
@@ -134,6 +132,6 @@ AudioListener.prototype = Object.assign( Object.create( Object3D.prototype ), {
 
 	}
 
-} );
+}
 
 export { AudioListener };

+ 30 - 33
src/audio/PositionalAudio.js

@@ -1,90 +1,87 @@
 import { Vector3 } from '../math/Vector3.js';
 import { Quaternion } from '../math/Quaternion.js';
 import { Audio } from './Audio.js';
-import { Object3D } from '../core/Object3D.js';
 
 const _position = new Vector3();
 const _quaternion = new Quaternion();
 const _scale = new Vector3();
 const _orientation = new Vector3();
 
-function PositionalAudio( listener ) {
+class PositionalAudio extends Audio {
 
-	Audio.call( this, listener );
+	constructor( listener ) {
 
-	this.panner = this.context.createPanner();
-	this.panner.panningModel = 'HRTF';
-	this.panner.connect( this.gain );
+		super( listener );
 
-}
-
-PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {
+		this.panner = this.context.createPanner();
+		this.panner.panningModel = 'HRTF';
+		this.panner.connect( this.gain );
 
-	constructor: PositionalAudio,
+	}
 
-	getOutput: function () {
+	getOutput() {
 
 		return this.panner;
 
-	},
+	}
 
-	getRefDistance: function () {
+	getRefDistance() {
 
 		return this.panner.refDistance;
 
-	},
+	}
 
-	setRefDistance: function ( value ) {
+	setRefDistance( value ) {
 
 		this.panner.refDistance = value;
 
 		return this;
 
-	},
+	}
 
-	getRolloffFactor: function () {
+	getRolloffFactor() {
 
 		return this.panner.rolloffFactor;
 
-	},
+	}
 
-	setRolloffFactor: function ( value ) {
+	setRolloffFactor( value ) {
 
 		this.panner.rolloffFactor = value;
 
 		return this;
 
-	},
+	}
 
-	getDistanceModel: function () {
+	getDistanceModel() {
 
 		return this.panner.distanceModel;
 
-	},
+	}
 
-	setDistanceModel: function ( value ) {
+	setDistanceModel( value ) {
 
 		this.panner.distanceModel = value;
 
 		return this;
 
-	},
+	}
 
-	getMaxDistance: function () {
+	getMaxDistance() {
 
 		return this.panner.maxDistance;
 
-	},
+	}
 
-	setMaxDistance: function ( value ) {
+	setMaxDistance( value ) {
 
 		this.panner.maxDistance = value;
 
 		return this;
 
-	},
+	}
 
-	setDirectionalCone: function ( coneInnerAngle, coneOuterAngle, coneOuterGain ) {
+	setDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) {
 
 		this.panner.coneInnerAngle = coneInnerAngle;
 		this.panner.coneOuterAngle = coneOuterAngle;
@@ -92,11 +89,11 @@ PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {
 
 		return this;
 
-	},
+	}
 
-	updateMatrixWorld: function ( force ) {
+	updateMatrixWorld( force ) {
 
-		Object3D.prototype.updateMatrixWorld.call( this, force );
+		super.updateMatrixWorld( force );
 
 		if ( this.hasPlaybackControl === true && this.isPlaying === false ) return;
 
@@ -128,6 +125,6 @@ PositionalAudio.prototype = Object.assign( Object.create( Audio.prototype ), {
 
 	}
 
-} );
+}
 
 export { PositionalAudio };

+ 6 - 6
src/cameras/PerspectiveCamera.js

@@ -181,12 +181,12 @@ PerspectiveCamera.prototype = Object.assign( Object.create( Camera.prototype ),
 
 	updateProjectionMatrix: function () {
 
-		let near = this.near,
-			top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom,
-			height = 2 * top,
-			width = this.aspect * height,
-			left = - 0.5 * width,
-			view = this.view;
+		const near = this.near;
+		let top = near * Math.tan( MathUtils.DEG2RAD * 0.5 * this.fov ) / this.zoom;
+		let height = 2 * top;
+		let width = this.aspect * height;
+		let left = - 0.5 * width;
+		const view = this.view;
 
 		if ( this.view !== null && this.view.enabled ) {
 

+ 1 - 1
src/constants.js

@@ -1,4 +1,4 @@
-export const REVISION = '119';
+export const REVISION = '120dev';
 export const MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };
 export const TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };
 export const CullFaceNone = 0;

+ 16 - 17
src/core/Clock.js

@@ -1,18 +1,18 @@
-function Clock( autoStart ) {
+class Clock {
 
-	this.autoStart = ( autoStart !== undefined ) ? autoStart : true;
+	constructor( autoStart ) {
 
-	this.startTime = 0;
-	this.oldTime = 0;
-	this.elapsedTime = 0;
+		this.autoStart = ( autoStart !== undefined ) ? autoStart : true;
 
-	this.running = false;
+		this.startTime = 0;
+		this.oldTime = 0;
+		this.elapsedTime = 0;
 
-}
+		this.running = false;
 
-Object.assign( Clock.prototype, {
+	}
 
-	start: function () {
+	start() {
 
 		this.startTime = ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732
 
@@ -20,24 +20,24 @@ Object.assign( Clock.prototype, {
 		this.elapsedTime = 0;
 		this.running = true;
 
-	},
+	}
 
-	stop: function () {
+	stop() {
 
 		this.getElapsedTime();
 		this.running = false;
 		this.autoStart = false;
 
-	},
+	}
 
-	getElapsedTime: function () {
+	getElapsedTime() {
 
 		this.getDelta();
 		return this.elapsedTime;
 
-	},
+	}
 
-	getDelta: function () {
+	getDelta() {
 
 		let diff = 0;
 
@@ -63,7 +63,6 @@ Object.assign( Clock.prototype, {
 
 	}
 
-} );
-
+}
 
 export { Clock };

+ 25 - 25
src/core/DirectGeometry.js

@@ -1,38 +1,38 @@
 import { Vector2 } from '../math/Vector2.js';
 
-function DirectGeometry() {
+class DirectGeometry {
 
-	this.vertices = [];
-	this.normals = [];
-	this.colors = [];
-	this.uvs = [];
-	this.uvs2 = [];
+	constructor() {
 
-	this.groups = [];
+		this.vertices = [];
+		this.normals = [];
+		this.colors = [];
+		this.uvs = [];
+		this.uvs2 = [];
 
-	this.morphTargets = {};
+		this.groups = [];
 
-	this.skinWeights = [];
-	this.skinIndices = [];
+		this.morphTargets = {};
 
-	// this.lineDistances = [];
+		this.skinWeights = [];
+		this.skinIndices = [];
 
-	this.boundingBox = null;
-	this.boundingSphere = null;
+		// this.lineDistances = [];
 
-	// update flags
+		this.boundingBox = null;
+		this.boundingSphere = null;
 
-	this.verticesNeedUpdate = false;
-	this.normalsNeedUpdate = false;
-	this.colorsNeedUpdate = false;
-	this.uvsNeedUpdate = false;
-	this.groupsNeedUpdate = false;
+		// update flags
 
-}
+		this.verticesNeedUpdate = false;
+		this.normalsNeedUpdate = false;
+		this.colorsNeedUpdate = false;
+		this.uvsNeedUpdate = false;
+		this.groupsNeedUpdate = false;
 
-Object.assign( DirectGeometry.prototype, {
+	}
 
-	computeGroups: function ( geometry ) {
+	computeGroups( geometry ) {
 
 		const groups = [];
 
@@ -76,9 +76,9 @@ Object.assign( DirectGeometry.prototype, {
 
 		this.groups = groups;
 
-	},
+	}
 
-	fromGeometry: function ( geometry ) {
+	fromGeometry( geometry ) {
 
 		const faces = geometry.faces;
 		const vertices = geometry.vertices;
@@ -277,7 +277,7 @@ Object.assign( DirectGeometry.prototype, {
 
 	}
 
-} );
+}
 
 
 export { DirectGeometry };

+ 15 - 15
src/core/Face3.js

@@ -1,31 +1,31 @@
 import { Color } from '../math/Color.js';
 import { Vector3 } from '../math/Vector3.js';
 
-function Face3( a, b, c, normal, color, materialIndex ) {
+class Face3 {
 
-	this.a = a;
-	this.b = b;
-	this.c = c;
+	constructor( a, b, c, normal, color, materialIndex ) {
 
-	this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
-	this.vertexNormals = Array.isArray( normal ) ? normal : [];
+		this.a = a;
+		this.b = b;
+		this.c = c;
 
-	this.color = ( color && color.isColor ) ? color : new Color();
-	this.vertexColors = Array.isArray( color ) ? color : [];
+		this.normal = ( normal && normal.isVector3 ) ? normal : new Vector3();
+		this.vertexNormals = Array.isArray( normal ) ? normal : [];
 
-	this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
+		this.color = ( color && color.isColor ) ? color : new Color();
+		this.vertexColors = Array.isArray( color ) ? color : [];
 
-}
+		this.materialIndex = materialIndex !== undefined ? materialIndex : 0;
 
-Object.assign( Face3.prototype, {
+	}
 
-	clone: function () {
+	clone() {
 
 		return new this.constructor().copy( this );
 
-	},
+	}
 
-	copy: function ( source ) {
+	copy( source ) {
 
 		this.a = source.a;
 		this.b = source.b;
@@ -52,7 +52,7 @@ Object.assign( Face3.prototype, {
 
 	}
 
-} );
+}
 
 
 export { Face3 };

+ 6 - 5
src/core/Geometry.js

@@ -640,8 +640,8 @@ Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 		}
 
-		let normalMatrix,
-			vertexOffset = this.vertices.length,
+		let normalMatrix;
+		const vertexOffset = this.vertices.length,
 			vertices1 = this.vertices,
 			vertices2 = geometry.vertices,
 			faces1 = this.faces,
@@ -683,11 +683,12 @@ Geometry.prototype = Object.assign( Object.create( EventDispatcher.prototype ),
 
 		for ( let i = 0, il = faces2.length; i < il; i ++ ) {
 
-			let face = faces2[ i ], faceCopy, normal, color,
-				faceVertexNormals = face.vertexNormals,
+			const face = faces2[ i ];
+			let normal, color;
+			const faceVertexNormals = face.vertexNormals,
 				faceVertexColors = face.vertexColors;
 
-			faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
+			const faceCopy = new Face3( face.a + vertexOffset, face.b + vertexOffset, face.c + vertexOffset );
 			faceCopy.normal.copy( face.normal );
 
 			if ( normalMatrix !== undefined ) {

+ 18 - 18
src/core/Layers.js

@@ -1,54 +1,54 @@
-function Layers() {
+class Layers {
 
-	this.mask = 1 | 0;
+	constructor() {
 
-}
+		this.mask = 1 | 0;
 
-Object.assign( Layers.prototype, {
+	}
 
-	set: function ( channel ) {
+	set( channel ) {
 
 		this.mask = 1 << channel | 0;
 
-	},
+	}
 
-	enable: function ( channel ) {
+	enable( channel ) {
 
 		this.mask |= 1 << channel | 0;
 
-	},
+	}
 
-	enableAll: function () {
+	enableAll() {
 
 		this.mask = 0xffffffff | 0;
 
-	},
+	}
 
-	toggle: function ( channel ) {
+	toggle( channel ) {
 
 		this.mask ^= 1 << channel | 0;
 
-	},
+	}
 
-	disable: function ( channel ) {
+	disable( channel ) {
 
 		this.mask &= ~ ( 1 << channel | 0 );
 
-	},
+	}
 
-	disableAll: function () {
+	disableAll() {
 
 		this.mask = 0;
 
-	},
+	}
 
-	test: function ( layers ) {
+	test( layers ) {
 
 		return ( this.mask & layers.mask ) !== 0;
 
 	}
 
-} );
+}
 
 
 export { Layers };

+ 14 - 10
src/core/Uniform.js

@@ -1,20 +1,24 @@
-function Uniform( value ) {
+class Uniform {
 
-	if ( typeof value === 'string' ) {
+	constructor( value ) {
 
-		console.warn( 'THREE.Uniform: Type parameter is no longer needed.' );
-		value = arguments[ 1 ];
+		if ( typeof value === 'string' ) {
 
-	}
+			console.warn( 'THREE.Uniform: Type parameter is no longer needed.' );
+			value = arguments[ 1 ];
 
-	this.value = value;
+		}
 
-}
+		this.value = value;
+
+	}
 
-Uniform.prototype.clone = function () {
+	clone() {
 
-	return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
+		return new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );
 
-};
+	}
+
+}
 
 export { Uniform };

+ 22 - 24
src/extras/Earcut.js

@@ -8,10 +8,10 @@ const Earcut = {
 
 		dim = dim || 2;
 
-		let hasHoles = holeIndices && holeIndices.length,
-			outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length,
-			outerNode = linkedList( data, 0, outerLen, dim, true ),
-			triangles = [];
+		const hasHoles = holeIndices && holeIndices.length;
+		const outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;
+		let outerNode = linkedList( data, 0, outerLen, dim, true );
+		const triangles = [];
 
 		if ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;
 
@@ -177,7 +177,7 @@ function earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {
 // check whether a polygon node forms a valid ear with adjacent nodes
 function isEar( ear ) {
 
-	let a = ear.prev,
+	const a = ear.prev,
 		b = ear,
 		c = ear.next;
 
@@ -200,20 +200,20 @@ function isEar( ear ) {
 
 function isEarHashed( ear, minX, minY, invSize ) {
 
-	let a = ear.prev,
+	const a = ear.prev,
 		b = ear,
 		c = ear.next;
 
 	if ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear
 
 	// triangle bbox; min & max are calculated like this for speed
-	let minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ),
+	const minTX = a.x < b.x ? ( a.x < c.x ? a.x : c.x ) : ( b.x < c.x ? b.x : c.x ),
 		minTY = a.y < b.y ? ( a.y < c.y ? a.y : c.y ) : ( b.y < c.y ? b.y : c.y ),
 		maxTX = a.x > b.x ? ( a.x > c.x ? a.x : c.x ) : ( b.x > c.x ? b.x : c.x ),
 		maxTY = a.y > b.y ? ( a.y > c.y ? a.y : c.y ) : ( b.y > c.y ? b.y : c.y );
 
 	// z-order range for the current triangle bbox;
-	let minZ = zOrder( minTX, minTY, minX, minY, invSize ),
+	const minZ = zOrder( minTX, minTY, minX, minY, invSize ),
 		maxZ = zOrder( maxTX, maxTY, minX, minY, invSize );
 
 	let p = ear.prevZ,
@@ -264,7 +264,7 @@ function cureLocalIntersections( start, triangles, dim ) {
 	let p = start;
 	do {
 
-		let a = p.prev,
+		const a = p.prev,
 			b = p.next.next;
 
 		if ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {
@@ -328,8 +328,8 @@ function splitEarcut( start, triangles, dim, minX, minY, invSize ) {
 // link every hole into the outer loop, producing a single-ring polygon without holes
 function eliminateHoles( data, holeIndices, outerNode, dim ) {
 
-	let queue = [],
-		i, len, start, end, list;
+	const queue = [];
+	let i, len, start, end, list;
 
 	for ( i = 0, len = holeIndices.length; i < len; i ++ ) {
 
@@ -380,11 +380,10 @@ function eliminateHole( hole, outerNode ) {
 // David Eberly's algorithm for finding a bridge between hole and outer polygon
 function findHoleBridge( hole, outerNode ) {
 
-	let p = outerNode,
-		hx = hole.x,
-		hy = hole.y,
-		qx = - Infinity,
-		m;
+	let p = outerNode;
+	const hx = hole.x;
+	const hy = hole.y;
+	let qx = - Infinity, m;
 
 	// find a segment intersected by a ray from the hole's leftmost point to the left;
 	// segment's endpoint with lesser x will be potential connection point
@@ -392,7 +391,7 @@ function findHoleBridge( hole, outerNode ) {
 
 		if ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {
 
-			let x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
+			const x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );
 			if ( x <= hx && x > qx ) {
 
 				qx = x;
@@ -421,11 +420,10 @@ function findHoleBridge( hole, outerNode ) {
 	// if there are no points found, we have a valid connection;
 	// otherwise choose the point of the minimum angle with the ray as connection point
 
-	let stop = m,
+	const stop = m,
 		mx = m.x,
-		my = m.y,
-		tanMin = Infinity,
-		tan;
+		my = m.y;
+	let tanMin = Infinity, tan;
 
 	p = m;
 
@@ -677,8 +675,8 @@ function locallyInside( a, b ) {
 function middleInside( a, b ) {
 
 	let p = a,
-		inside = false,
-		px = ( a.x + b.x ) / 2,
+		inside = false;
+	const px = ( a.x + b.x ) / 2,
 		py = ( a.y + b.y ) / 2;
 	do {
 
@@ -697,7 +695,7 @@ function middleInside( a, b ) {
 // if one belongs to the outer ring and another to a hole, it merges it into a single ring
 function splitPolygon( a, b ) {
 
-	let a2 = new Node( a.i, a.x, a.y ),
+	const a2 = new Node( a.i, a.x, a.y ),
 		b2 = new Node( b.i, b.x, b.y ),
 		an = a.next,
 		bp = b.prev;

+ 39 - 41
src/extras/PMREMGenerator.js

@@ -84,22 +84,20 @@ const _axisDirections = [
  * interpolate diffuse lighting while limiting sampling computation.
  */
 
-function PMREMGenerator( renderer ) {
+class PMREMGenerator {
 
-	this._renderer = renderer;
-	this._pingPongRenderTarget = null;
+	constructor( renderer ) {
 
-	this._blurMaterial = _getBlurShader( MAX_SAMPLES );
-	this._equirectShader = null;
-	this._cubemapShader = null;
+		this._renderer = renderer;
+		this._pingPongRenderTarget = null;
 
-	this._compileMaterial( this._blurMaterial );
+		this._blurMaterial = _getBlurShader( MAX_SAMPLES );
+		this._equirectShader = null;
+		this._cubemapShader = null;
 
-}
-
-PMREMGenerator.prototype = {
+		this._compileMaterial( this._blurMaterial );
 
-	constructor: PMREMGenerator,
+	}
 
 	/**
 	 * Generates a PMREM from a supplied Scene, which can be faster than using an
@@ -108,7 +106,7 @@ PMREMGenerator.prototype = {
 	 * and far planes ensure the scene is rendered in its entirety (the cubeCamera
 	 * is placed at the origin).
 	 */
-	fromScene: function ( scene, sigma = 0, near = 0.1, far = 100 ) {
+	fromScene( scene, sigma = 0, near = 0.1, far = 100 ) {
 
 		_oldTarget = this._renderer.getRenderTarget();
 		const cubeUVRenderTarget = this._allocateTargets();
@@ -125,35 +123,35 @@ PMREMGenerator.prototype = {
 
 		return cubeUVRenderTarget;
 
-	},
+	}
 
 	/**
 	 * Generates a PMREM from an equirectangular texture, which can be either LDR
 	 * (RGBFormat) or HDR (RGBEFormat). The ideal input image size is 1k (1024 x 512),
 	 * as this matches best with the 256 x 256 cubemap output.
 	 */
-	fromEquirectangular: function ( equirectangular ) {
+	fromEquirectangular( equirectangular ) {
 
 		return this._fromTexture( equirectangular );
 
-	},
+	}
 
 	/**
 	 * Generates a PMREM from an cubemap texture, which can be either LDR
 	 * (RGBFormat) or HDR (RGBEFormat). The ideal input cube size is 256 x 256,
 	 * as this matches best with the 256 x 256 cubemap output.
 	 */
-	fromCubemap: function ( cubemap ) {
+	fromCubemap( cubemap ) {
 
 		return this._fromTexture( cubemap );
 
-	},
+	}
 
 	/**
 	 * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during
 	 * your texture's network fetch for increased concurrency.
 	 */
-	compileCubemapShader: function () {
+	compileCubemapShader() {
 
 		if ( this._cubemapShader === null ) {
 
@@ -162,13 +160,13 @@ PMREMGenerator.prototype = {
 
 		}
 
-	},
+	}
 
 	/**
 	 * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during
 	 * your texture's network fetch for increased concurrency.
 	 */
-	compileEquirectangularShader: function () {
+	compileEquirectangularShader() {
 
 		if ( this._equirectShader === null ) {
 
@@ -177,14 +175,14 @@ PMREMGenerator.prototype = {
 
 		}
 
-	},
+	}
 
 	/**
 	 * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,
 	 * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on
 	 * one of them will cause any others to also become unusable.
 	 */
-	dispose: function () {
+	dispose() {
 
 		this._blurMaterial.dispose();
 
@@ -197,20 +195,20 @@ PMREMGenerator.prototype = {
 
 		}
 
-	},
+	}
 
 	// private interface
 
-	_cleanup: function ( outputTarget ) {
+	_cleanup( outputTarget ) {
 
 		this._pingPongRenderTarget.dispose();
 		this._renderer.setRenderTarget( _oldTarget );
 		outputTarget.scissorTest = false;
 		_setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );
 
-	},
+	}
 
-	_fromTexture: function ( texture ) {
+	_fromTexture( texture ) {
 
 		_oldTarget = this._renderer.getRenderTarget();
 		const cubeUVRenderTarget = this._allocateTargets( texture );
@@ -220,9 +218,9 @@ PMREMGenerator.prototype = {
 
 		return cubeUVRenderTarget;
 
-	},
+	}
 
-	_allocateTargets: function ( texture ) { // warning: null texture is valid
+	_allocateTargets( texture ) { // warning: null texture is valid
 
 		const params = {
 			magFilter: NearestFilter,
@@ -240,16 +238,16 @@ PMREMGenerator.prototype = {
 		this._pingPongRenderTarget = _createRenderTarget( params );
 		return cubeUVRenderTarget;
 
-	},
+	}
 
-	_compileMaterial: function ( material ) {
+	_compileMaterial( material ) {
 
 		const tmpMesh = new Mesh( _lodPlanes[ 0 ], material );
 		this._renderer.compile( tmpMesh, _flatCamera );
 
-	},
+	}
 
-	_sceneToCubeUV: function ( scene, near, far, cubeUVRenderTarget ) {
+	_sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {
 
 		const fov = 90;
 		const aspect = 1;
@@ -311,9 +309,9 @@ PMREMGenerator.prototype = {
 		renderer.outputEncoding = outputEncoding;
 		renderer.setClearColor( clearColor, clearAlpha );
 
-	},
+	}
 
-	_textureToCubeUV: function ( texture, cubeUVRenderTarget ) {
+	_textureToCubeUV( texture, cubeUVRenderTarget ) {
 
 		const renderer = this._renderer;
 
@@ -356,9 +354,9 @@ PMREMGenerator.prototype = {
 		renderer.setRenderTarget( cubeUVRenderTarget );
 		renderer.render( mesh, _flatCamera );
 
-	},
+	}
 
-	_applyPMREM: function ( cubeUVRenderTarget ) {
+	_applyPMREM( cubeUVRenderTarget ) {
 
 		const renderer = this._renderer;
 		const autoClear = renderer.autoClear;
@@ -376,7 +374,7 @@ PMREMGenerator.prototype = {
 
 		renderer.autoClear = autoClear;
 
-	},
+	}
 
 	/**
 	 * This is a two-pass Gaussian blur for a cubemap. Normally this is done
@@ -385,7 +383,7 @@ PMREMGenerator.prototype = {
 	 * the poles) to approximate the orthogonally-separable blur. It is least
 	 * accurate at the poles, but still does a decent job.
 	 */
-	_blur: function ( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {
+	_blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {
 
 		const pingPongRenderTarget = this._pingPongRenderTarget;
 
@@ -407,9 +405,9 @@ PMREMGenerator.prototype = {
 			'longitudinal',
 			poleAxis );
 
-	},
+	}
 
-	_halfBlur: function ( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {
+	_halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {
 
 		const renderer = this._renderer;
 		const blurMaterial = this._blurMaterial;
@@ -493,7 +491,7 @@ PMREMGenerator.prototype = {
 
 	}
 
-};
+}
 
 function _isLDR( texture ) {
 

+ 2 - 1
src/extras/core/Curve.js

@@ -158,7 +158,8 @@ Object.assign( Curve.prototype, {
 
 		const arcLengths = this.getLengths();
 
-		let i = 0, il = arcLengths.length;
+		let i = 0;
+		const il = arcLengths.length;
 
 		let targetArcLength; // The targeted u distance value to get
 

+ 2 - 1
src/extras/core/ShapePath.js

@@ -147,7 +147,8 @@ Object.assign( ShapePath.prototype, {
 		if ( noHoles === true )	return	toShapesNoHoles( subPaths );
 
 
-		let solid, tmpPath, tmpShape, shapes = [];
+		let solid, tmpPath, tmpShape;
+		const shapes = [];
 
 		if ( subPaths.length === 1 ) {
 

+ 3 - 3
src/extras/curves/CatmullRomCurve3.js

@@ -121,7 +121,7 @@ CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) {
 
 	}
 
-	let p0, p1, p2, p3; // 4 points
+	let p0, p3; // 4 points (p1 & p2 defined below)
 
 	if ( this.closed || intPoint > 0 ) {
 
@@ -135,8 +135,8 @@ CatmullRomCurve3.prototype.getPoint = function ( t, optionalTarget ) {
 
 	}
 
-	p1 = points[ intPoint % l ];
-	p2 = points[ ( intPoint + 1 ) % l ];
+	const p1 = points[ intPoint % l ];
+	const p2 = points[ ( intPoint + 1 ) % l ];
 
 	if ( this.closed || intPoint + 2 < l ) {
 

+ 65 - 64
src/geometries/CircleGeometry.js

@@ -6,109 +6,110 @@ import { Vector2 } from '../math/Vector2.js';
 
 // CircleGeometry
 
-function CircleGeometry( radius, segments, thetaStart, thetaLength ) {
+class CircleGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( radius, segments, thetaStart, thetaLength ) {
 
-	this.type = 'CircleGeometry';
+		super();
+		this.type = 'CircleGeometry';
 
-	this.parameters = {
-		radius: radius,
-		segments: segments,
-		thetaStart: thetaStart,
-		thetaLength: thetaLength
-	};
+		this.parameters = {
+			radius: radius,
+			segments: segments,
+			thetaStart: thetaStart,
+			thetaLength: thetaLength
+		};
 
-	this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );
-	this.mergeVertices();
+		this.fromBufferGeometry( new CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) );
+		this.mergeVertices();
 
-}
+	}
 
-CircleGeometry.prototype = Object.create( Geometry.prototype );
-CircleGeometry.prototype.constructor = CircleGeometry;
+}
 
 // CircleBufferGeometry
 
-function CircleBufferGeometry( radius, segments, thetaStart, thetaLength ) {
+class CircleBufferGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( radius, segments, thetaStart, thetaLength ) {
 
-	this.type = 'CircleBufferGeometry';
+		super();
 
-	this.parameters = {
-		radius: radius,
-		segments: segments,
-		thetaStart: thetaStart,
-		thetaLength: thetaLength
-	};
+		this.type = 'CircleBufferGeometry';
 
-	radius = radius || 1;
-	segments = segments !== undefined ? Math.max( 3, segments ) : 8;
+		this.parameters = {
+			radius: radius,
+			segments: segments,
+			thetaStart: thetaStart,
+			thetaLength: thetaLength
+		};
 
-	thetaStart = thetaStart !== undefined ? thetaStart : 0;
-	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
+		radius = radius || 1;
+		segments = segments !== undefined ? Math.max( 3, segments ) : 8;
 
-	// buffers
+		thetaStart = thetaStart !== undefined ? thetaStart : 0;
+		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
 
-	const indices = [];
-	const vertices = [];
-	const normals = [];
-	const uvs = [];
+		// buffers
 
-	// helper variables
+		const indices = [];
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
 
-	const vertex = new Vector3();
-	const uv = new Vector2();
+		// helper variables
 
-	// center point
+		const vertex = new Vector3();
+		const uv = new Vector2();
 
-	vertices.push( 0, 0, 0 );
-	normals.push( 0, 0, 1 );
-	uvs.push( 0.5, 0.5 );
+		// center point
 
-	for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {
+		vertices.push( 0, 0, 0 );
+		normals.push( 0, 0, 1 );
+		uvs.push( 0.5, 0.5 );
 
-		const segment = thetaStart + s / segments * thetaLength;
+		for ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {
 
-		// vertex
+			const segment = thetaStart + s / segments * thetaLength;
 
-		vertex.x = radius * Math.cos( segment );
-		vertex.y = radius * Math.sin( segment );
+			// vertex
 
-		vertices.push( vertex.x, vertex.y, vertex.z );
+			vertex.x = radius * Math.cos( segment );
+			vertex.y = radius * Math.sin( segment );
 
-		// normal
+			vertices.push( vertex.x, vertex.y, vertex.z );
 
-		normals.push( 0, 0, 1 );
+			// normal
 
-		// uvs
+			normals.push( 0, 0, 1 );
 
-		uv.x = ( vertices[ i ] / radius + 1 ) / 2;
-		uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
+			// uvs
 
-		uvs.push( uv.x, uv.y );
+			uv.x = ( vertices[ i ] / radius + 1 ) / 2;
+			uv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;
 
-	}
+			uvs.push( uv.x, uv.y );
 
-	// indices
+		}
 
-	for ( let i = 1; i <= segments; i ++ ) {
+		// indices
 
-		indices.push( i, i + 1, 0 );
+		for ( let i = 1; i <= segments; i ++ ) {
 
-	}
+			indices.push( i, i + 1, 0 );
 
-	// build geometry
+		}
 
-	this.setIndex( indices );
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+		// build geometry
 
-}
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-CircleBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-CircleBufferGeometry.prototype.constructor = CircleBufferGeometry;
+	}
+
+}
 
 
 export { CircleGeometry, CircleBufferGeometry };

+ 30 - 30
src/geometries/ConeGeometry.js

@@ -3,49 +3,49 @@ import { CylinderBufferGeometry } from './CylinderGeometry.js';
 
 // ConeGeometry
 
-function ConeGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
+class ConeGeometry extends CylinderGeometry {
 
-	CylinderGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
+	constructor( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
 
-	this.type = 'ConeGeometry';
+		super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
+		this.type = 'ConeGeometry';
 
-	this.parameters = {
-		radius: radius,
-		height: height,
-		radialSegments: radialSegments,
-		heightSegments: heightSegments,
-		openEnded: openEnded,
-		thetaStart: thetaStart,
-		thetaLength: thetaLength
-	};
+		this.parameters = {
+			radius: radius,
+			height: height,
+			radialSegments: radialSegments,
+			heightSegments: heightSegments,
+			openEnded: openEnded,
+			thetaStart: thetaStart,
+			thetaLength: thetaLength
+		};
 
-}
+	}
 
-ConeGeometry.prototype = Object.create( CylinderGeometry.prototype );
-ConeGeometry.prototype.constructor = ConeGeometry;
+}
 
 // ConeBufferGeometry
 
-function ConeBufferGeometry( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
+class ConeBufferGeometry extends CylinderBufferGeometry {
 
-	CylinderBufferGeometry.call( this, 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
+	constructor( radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
 
-	this.type = 'ConeBufferGeometry';
+		super( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );
+		this.type = 'ConeBufferGeometry';
 
-	this.parameters = {
-		radius: radius,
-		height: height,
-		radialSegments: radialSegments,
-		heightSegments: heightSegments,
-		openEnded: openEnded,
-		thetaStart: thetaStart,
-		thetaLength: thetaLength
-	};
+		this.parameters = {
+			radius: radius,
+			height: height,
+			radialSegments: radialSegments,
+			heightSegments: heightSegments,
+			openEnded: openEnded,
+			thetaStart: thetaStart,
+			thetaLength: thetaLength
+		};
 
-}
+	}
 
-ConeBufferGeometry.prototype = Object.create( CylinderBufferGeometry.prototype );
-ConeBufferGeometry.prototype.constructor = ConeBufferGeometry;
+}
 
 
 export { ConeGeometry, ConeBufferGeometry };

+ 175 - 178
src/geometries/CylinderGeometry.js

@@ -6,305 +6,302 @@ import { Vector2 } from '../math/Vector2.js';
 
 // CylinderGeometry
 
-function CylinderGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
+class CylinderGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
 
-	this.type = 'CylinderGeometry';
+		super();
+		this.type = 'CylinderGeometry';
 
-	this.parameters = {
-		radiusTop: radiusTop,
-		radiusBottom: radiusBottom,
-		height: height,
-		radialSegments: radialSegments,
-		heightSegments: heightSegments,
-		openEnded: openEnded,
-		thetaStart: thetaStart,
-		thetaLength: thetaLength
-	};
+		this.parameters = {
+			radiusTop: radiusTop,
+			radiusBottom: radiusBottom,
+			height: height,
+			radialSegments: radialSegments,
+			heightSegments: heightSegments,
+			openEnded: openEnded,
+			thetaStart: thetaStart,
+			thetaLength: thetaLength
+		};
 
-	this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );
-	this.mergeVertices();
+		this.fromBufferGeometry( new CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) );
+		this.mergeVertices();
 
-}
+	}
 
-CylinderGeometry.prototype = Object.create( Geometry.prototype );
-CylinderGeometry.prototype.constructor = CylinderGeometry;
+}
 
 // CylinderBufferGeometry
 
-function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
+class CylinderBufferGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
 
-	this.type = 'CylinderBufferGeometry';
+		super();
+		this.type = 'CylinderBufferGeometry';
 
-	this.parameters = {
-		radiusTop: radiusTop,
-		radiusBottom: radiusBottom,
-		height: height,
-		radialSegments: radialSegments,
-		heightSegments: heightSegments,
-		openEnded: openEnded,
-		thetaStart: thetaStart,
-		thetaLength: thetaLength
-	};
+		this.parameters = {
+			radiusTop: radiusTop,
+			radiusBottom: radiusBottom,
+			height: height,
+			radialSegments: radialSegments,
+			heightSegments: heightSegments,
+			openEnded: openEnded,
+			thetaStart: thetaStart,
+			thetaLength: thetaLength
+		};
 
-	const scope = this;
+		const scope = this;
 
-	radiusTop = radiusTop !== undefined ? radiusTop : 1;
-	radiusBottom = radiusBottom !== undefined ? radiusBottom : 1;
-	height = height || 1;
+		radiusTop = radiusTop !== undefined ? radiusTop : 1;
+		radiusBottom = radiusBottom !== undefined ? radiusBottom : 1;
+		height = height || 1;
 
-	radialSegments = Math.floor( radialSegments ) || 8;
-	heightSegments = Math.floor( heightSegments ) || 1;
+		radialSegments = Math.floor( radialSegments ) || 8;
+		heightSegments = Math.floor( heightSegments ) || 1;
 
-	openEnded = openEnded !== undefined ? openEnded : false;
-	thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
-	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
+		openEnded = openEnded !== undefined ? openEnded : false;
+		thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
+		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
 
-	// buffers
+		// buffers
 
-	const indices = [];
-	const vertices = [];
-	const normals = [];
-	const uvs = [];
+		const indices = [];
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
 
-	// helper variables
+		// helper variables
 
-	let index = 0;
-	const indexArray = [];
-	const halfHeight = height / 2;
-	let groupStart = 0;
+		let index = 0;
+		const indexArray = [];
+		const halfHeight = height / 2;
+		let groupStart = 0;
 
-	// generate geometry
+		// generate geometry
 
-	generateTorso();
+		generateTorso();
 
-	if ( openEnded === false ) {
+		if ( openEnded === false ) {
 
-		if ( radiusTop > 0 ) generateCap( true );
-		if ( radiusBottom > 0 ) generateCap( false );
+			if ( radiusTop > 0 ) generateCap( true );
+			if ( radiusBottom > 0 ) generateCap( false );
 
-	}
+		}
 
-	// build geometry
+		// build geometry
 
-	this.setIndex( indices );
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-	function generateTorso() {
+		function generateTorso() {
 
-		const normal = new Vector3();
-		const vertex = new Vector3();
+			const normal = new Vector3();
+			const vertex = new Vector3();
 
-		let groupCount = 0;
+			let groupCount = 0;
 
-		// this will be used to calculate the normal
-		const slope = ( radiusBottom - radiusTop ) / height;
+			// this will be used to calculate the normal
+			const slope = ( radiusBottom - radiusTop ) / height;
 
-		// generate vertices, normals and uvs
+			// generate vertices, normals and uvs
 
-		for ( let y = 0; y <= heightSegments; y ++ ) {
+			for ( let y = 0; y <= heightSegments; y ++ ) {
 
-			const indexRow = [];
+				const indexRow = [];
 
-			const v = y / heightSegments;
+				const v = y / heightSegments;
 
-			// calculate the radius of the current row
+				// calculate the radius of the current row
 
-			const radius = v * ( radiusBottom - radiusTop ) + radiusTop;
+				const radius = v * ( radiusBottom - radiusTop ) + radiusTop;
 
-			for ( let x = 0; x <= radialSegments; x ++ ) {
+				for ( let x = 0; x <= radialSegments; x ++ ) {
 
-				const u = x / radialSegments;
+					const u = x / radialSegments;
 
-				const theta = u * thetaLength + thetaStart;
+					const theta = u * thetaLength + thetaStart;
 
-				const sinTheta = Math.sin( theta );
-				const cosTheta = Math.cos( theta );
+					const sinTheta = Math.sin( theta );
+					const cosTheta = Math.cos( theta );
 
-				// vertex
+					// vertex
 
-				vertex.x = radius * sinTheta;
-				vertex.y = - v * height + halfHeight;
-				vertex.z = radius * cosTheta;
-				vertices.push( vertex.x, vertex.y, vertex.z );
+					vertex.x = radius * sinTheta;
+					vertex.y = - v * height + halfHeight;
+					vertex.z = radius * cosTheta;
+					vertices.push( vertex.x, vertex.y, vertex.z );
 
-				// normal
+					// normal
 
-				normal.set( sinTheta, slope, cosTheta ).normalize();
-				normals.push( normal.x, normal.y, normal.z );
+					normal.set( sinTheta, slope, cosTheta ).normalize();
+					normals.push( normal.x, normal.y, normal.z );
 
-				// uv
+					// uv
 
-				uvs.push( u, 1 - v );
+					uvs.push( u, 1 - v );
 
-				// save index of vertex in respective row
+					// save index of vertex in respective row
 
-				indexRow.push( index ++ );
+					indexRow.push( index ++ );
 
-			}
+				}
 
-			// now save vertices of the row in our index array
+				// now save vertices of the row in our index array
 
-			indexArray.push( indexRow );
+				indexArray.push( indexRow );
 
-		}
+			}
 
-		// generate indices
+			// generate indices
 
-		for ( let x = 0; x < radialSegments; x ++ ) {
+			for ( let x = 0; x < radialSegments; x ++ ) {
 
-			for ( let y = 0; y < heightSegments; y ++ ) {
+				for ( let y = 0; y < heightSegments; y ++ ) {
 
-				// we use the index array to access the correct indices
+					// we use the index array to access the correct indices
 
-				const a = indexArray[ y ][ x ];
-				const b = indexArray[ y + 1 ][ x ];
-				const c = indexArray[ y + 1 ][ x + 1 ];
-				const d = indexArray[ y ][ x + 1 ];
+					const a = indexArray[ y ][ x ];
+					const b = indexArray[ y + 1 ][ x ];
+					const c = indexArray[ y + 1 ][ x + 1 ];
+					const d = indexArray[ y ][ x + 1 ];
 
-				// faces
+					// faces
 
-				indices.push( a, b, d );
-				indices.push( b, c, d );
+					indices.push( a, b, d );
+					indices.push( b, c, d );
 
-				// update group counter
+					// update group counter
 
-				groupCount += 6;
+					groupCount += 6;
 
-			}
+				}
 
-		}
+			}
 
-		// add a group to the geometry. this will ensure multi material support
+			// add a group to the geometry. this will ensure multi material support
 
-		scope.addGroup( groupStart, groupCount, 0 );
+			scope.addGroup( groupStart, groupCount, 0 );
 
-		// calculate new start value for groups
+			// calculate new start value for groups
 
-		groupStart += groupCount;
+			groupStart += groupCount;
 
-	}
+		}
 
-	function generateCap( top ) {
+		function generateCap( top ) {
 
-		let centerIndexStart, centerIndexEnd;
+			// save the index of the first center vertex
+			const centerIndexStart = index;
 
-		const uv = new Vector2();
-		const vertex = new Vector3();
+			const uv = new Vector2();
+			const vertex = new Vector3();
 
-		let groupCount = 0;
+			let groupCount = 0;
 
-		const radius = ( top === true ) ? radiusTop : radiusBottom;
-		const sign = ( top === true ) ? 1 : - 1;
+			const radius = ( top === true ) ? radiusTop : radiusBottom;
+			const sign = ( top === true ) ? 1 : - 1;
 
-		// save the index of the first center vertex
-		centerIndexStart = index;
+			// first we generate the center vertex data of the cap.
+			// because the geometry needs one set of uvs per face,
+			// we must generate a center vertex per face/segment
 
-		// first we generate the center vertex data of the cap.
-		// because the geometry needs one set of uvs per face,
-		// we must generate a center vertex per face/segment
+			for ( let x = 1; x <= radialSegments; x ++ ) {
 
-		for ( let x = 1; x <= radialSegments; x ++ ) {
+				// vertex
 
-			// vertex
+				vertices.push( 0, halfHeight * sign, 0 );
 
-			vertices.push( 0, halfHeight * sign, 0 );
+				// normal
 
-			// normal
+				normals.push( 0, sign, 0 );
 
-			normals.push( 0, sign, 0 );
+				// uv
 
-			// uv
+				uvs.push( 0.5, 0.5 );
 
-			uvs.push( 0.5, 0.5 );
+				// increase index
 
-			// increase index
+				index ++;
 
-			index ++;
+			}
 
-		}
+			// save the index of the last center vertex
+			const centerIndexEnd = index;
 
-		// save the index of the last center vertex
+			// now we generate the surrounding vertices, normals and uvs
 
-		centerIndexEnd = index;
+			for ( let x = 0; x <= radialSegments; x ++ ) {
 
-		// now we generate the surrounding vertices, normals and uvs
+				const u = x / radialSegments;
+				const theta = u * thetaLength + thetaStart;
 
-		for ( let x = 0; x <= radialSegments; x ++ ) {
+				const cosTheta = Math.cos( theta );
+				const sinTheta = Math.sin( theta );
 
-			const u = x / radialSegments;
-			const theta = u * thetaLength + thetaStart;
+				// vertex
 
-			const cosTheta = Math.cos( theta );
-			const sinTheta = Math.sin( theta );
+				vertex.x = radius * sinTheta;
+				vertex.y = halfHeight * sign;
+				vertex.z = radius * cosTheta;
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			// vertex
+				// normal
 
-			vertex.x = radius * sinTheta;
-			vertex.y = halfHeight * sign;
-			vertex.z = radius * cosTheta;
-			vertices.push( vertex.x, vertex.y, vertex.z );
+				normals.push( 0, sign, 0 );
 
-			// normal
+				// uv
 
-			normals.push( 0, sign, 0 );
+				uv.x = ( cosTheta * 0.5 ) + 0.5;
+				uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
+				uvs.push( uv.x, uv.y );
 
-			// uv
+				// increase index
 
-			uv.x = ( cosTheta * 0.5 ) + 0.5;
-			uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
-			uvs.push( uv.x, uv.y );
+				index ++;
 
-			// increase index
+			}
 
-			index ++;
+			// generate indices
 
-		}
+			for ( let x = 0; x < radialSegments; x ++ ) {
 
-		// generate indices
+				const c = centerIndexStart + x;
+				const i = centerIndexEnd + x;
 
-		for ( let x = 0; x < radialSegments; x ++ ) {
+				if ( top === true ) {
 
-			const c = centerIndexStart + x;
-			const i = centerIndexEnd + x;
+					// face top
 
-			if ( top === true ) {
+					indices.push( i, i + 1, c );
 
-				// face top
+				} else {
 
-				indices.push( i, i + 1, c );
+					// face bottom
 
-			} else {
+					indices.push( i + 1, i, c );
 
-				// face bottom
+				}
 
-				indices.push( i + 1, i, c );
+				groupCount += 3;
 
 			}
 
-			groupCount += 3;
-
-		}
+			// add a group to the geometry. this will ensure multi material support
 
-		// add a group to the geometry. this will ensure multi material support
+			scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
 
-		scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
+			// calculate new start value for groups
 
-		// calculate new start value for groups
+			groupStart += groupCount;
 
-		groupStart += groupCount;
+		}
 
 	}
 
 }
 
-CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry;
-
 
 export { CylinderGeometry, CylinderBufferGeometry };

+ 55 - 54
src/geometries/DodecahedronGeometry.js

@@ -3,81 +3,82 @@ import { PolyhedronBufferGeometry } from './PolyhedronGeometry.js';
 
 // DodecahedronGeometry
 
-function DodecahedronGeometry( radius, detail ) {
+class DodecahedronGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( radius, detail ) {
 
-	this.type = 'DodecahedronGeometry';
+		super();
+		this.type = 'DodecahedronGeometry';
 
-	this.parameters = {
-		radius: radius,
-		detail: detail
-	};
+		this.parameters = {
+			radius: radius,
+			detail: detail
+		};
 
-	this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );
-	this.mergeVertices();
+		this.fromBufferGeometry( new DodecahedronBufferGeometry( radius, detail ) );
+		this.mergeVertices();
 
-}
+	}
 
-DodecahedronGeometry.prototype = Object.create( Geometry.prototype );
-DodecahedronGeometry.prototype.constructor = DodecahedronGeometry;
+}
 
 // DodecahedronBufferGeometry
 
-function DodecahedronBufferGeometry( radius, detail ) {
+class DodecahedronBufferGeometry extends PolyhedronBufferGeometry {
 
-	const t = ( 1 + Math.sqrt( 5 ) ) / 2;
-	const r = 1 / t;
+	constructor( radius, detail ) {
 
-	const vertices = [
+		const t = ( 1 + Math.sqrt( 5 ) ) / 2;
+		const r = 1 / t;
 
-		// (±1, ±1, ±1)
-		- 1, - 1, - 1,	- 1, - 1, 1,
-		- 1, 1, - 1, - 1, 1, 1,
-		1, - 1, - 1, 1, - 1, 1,
-		1, 1, - 1, 1, 1, 1,
+		const vertices = [
 
-		// (0, ±1/φ, ±φ)
-		 0, - r, - t, 0, - r, t,
-		 0, r, - t, 0, r, t,
+			// (±1, ±1, ±1)
+			- 1, - 1, - 1,	- 1, - 1, 1,
+			- 1, 1, - 1, - 1, 1, 1,
+			1, - 1, - 1, 1, - 1, 1,
+			1, 1, - 1, 1, 1, 1,
 
-		// (±1/φ, ±φ, 0)
-		- r, - t, 0, - r, t, 0,
-		 r, - t, 0, r, t, 0,
+			// (0, ±1/φ, ±φ)
+			0, - r, - t, 0, - r, t,
+			0, r, - t, 0, r, t,
 
-		// (±φ, 0, ±1/φ)
-		- t, 0, - r, t, 0, - r,
-		- t, 0, r, t, 0, r
-	];
+			// (±1/φ, ±φ, 0)
+			- r, - t, 0, - r, t, 0,
+			r, - t, 0, r, t, 0,
 
-	const indices = [
-		3, 11, 7, 	3, 7, 15, 	3, 15, 13,
-		7, 19, 17, 	7, 17, 6, 	7, 6, 15,
-		17, 4, 8, 	17, 8, 10, 	17, 10, 6,
-		8, 0, 16, 	8, 16, 2, 	8, 2, 10,
-		0, 12, 1, 	0, 1, 18, 	0, 18, 16,
-		6, 10, 2, 	6, 2, 13, 	6, 13, 15,
-		2, 16, 18, 	2, 18, 3, 	2, 3, 13,
-		18, 1, 9, 	18, 9, 11, 	18, 11, 3,
-		4, 14, 12, 	4, 12, 0, 	4, 0, 8,
-		11, 9, 5, 	11, 5, 19, 	11, 19, 7,
-		19, 5, 14, 	19, 14, 4, 	19, 4, 17,
-		1, 12, 14, 	1, 14, 5, 	1, 5, 9
-	];
+			// (±φ, 0, ±1/φ)
+			- t, 0, - r, t, 0, - r,
+			- t, 0, r, t, 0, r
+		];
 
-	PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
+		const indices = [
+			3, 11, 7, 	3, 7, 15, 	3, 15, 13,
+			7, 19, 17, 	7, 17, 6, 	7, 6, 15,
+			17, 4, 8, 	17, 8, 10, 	17, 10, 6,
+			8, 0, 16, 	8, 16, 2, 	8, 2, 10,
+			0, 12, 1, 	0, 1, 18, 	0, 18, 16,
+			6, 10, 2, 	6, 2, 13, 	6, 13, 15,
+			2, 16, 18, 	2, 18, 3, 	2, 3, 13,
+			18, 1, 9, 	18, 9, 11, 	18, 11, 3,
+			4, 14, 12, 	4, 12, 0, 	4, 0, 8,
+			11, 9, 5, 	11, 5, 19, 	11, 19, 7,
+			19, 5, 14, 	19, 14, 4, 	19, 4, 17,
+			1, 12, 14, 	1, 14, 5, 	1, 5, 9
+		];
 
-	this.type = 'DodecahedronBufferGeometry';
+		super( vertices, indices, radius, detail );
 
-	this.parameters = {
-		radius: radius,
-		detail: detail
-	};
+		this.type = 'DodecahedronBufferGeometry';
 
-}
+		this.parameters = {
+			radius: radius,
+			detail: detail
+		};
 
-DodecahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
-DodecahedronBufferGeometry.prototype.constructor = DodecahedronBufferGeometry;
+	}
+
+}
 
 
 export { DodecahedronGeometry, DodecahedronBufferGeometry };

+ 56 - 55
src/geometries/EdgesGeometry.js

@@ -3,107 +3,108 @@ import { Float32BufferAttribute } from '../core/BufferAttribute.js';
 import { Geometry } from '../core/Geometry.js';
 import { MathUtils } from '../math/MathUtils.js';
 
-function EdgesGeometry( geometry, thresholdAngle ) {
+class EdgesGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( geometry, thresholdAngle ) {
 
-	this.type = 'EdgesGeometry';
+		super();
 
-	this.parameters = {
-		thresholdAngle: thresholdAngle
-	};
+		this.type = 'EdgesGeometry';
 
-	thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;
+		this.parameters = {
+			thresholdAngle: thresholdAngle
+		};
 
-	// buffer
+		thresholdAngle = ( thresholdAngle !== undefined ) ? thresholdAngle : 1;
 
-	const vertices = [];
+		// buffer
 
-	// helper variables
+		const vertices = [];
 
-	const thresholdDot = Math.cos( MathUtils.DEG2RAD * thresholdAngle );
-	const edge = [ 0, 0 ], edges = {};
-	let edge1, edge2, key;
-	const keys = [ 'a', 'b', 'c' ];
+		// helper variables
 
-	// prepare source geometry
+		const thresholdDot = Math.cos( MathUtils.DEG2RAD * thresholdAngle );
+		const edge = [ 0, 0 ], edges = {};
+		let edge1, edge2, key;
+		const keys = [ 'a', 'b', 'c' ];
 
-	let geometry2;
+		// prepare source geometry
 
-	if ( geometry.isBufferGeometry ) {
+		let geometry2;
 
-		geometry2 = new Geometry();
-		geometry2.fromBufferGeometry( geometry );
+		if ( geometry.isBufferGeometry ) {
 
-	} else {
+			geometry2 = new Geometry();
+			geometry2.fromBufferGeometry( geometry );
 
-		geometry2 = geometry.clone();
+		} else {
 
-	}
+			geometry2 = geometry.clone();
+
+		}
 
-	geometry2.mergeVertices();
-	geometry2.computeFaceNormals();
+		geometry2.mergeVertices();
+		geometry2.computeFaceNormals();
 
-	const sourceVertices = geometry2.vertices;
-	const faces = geometry2.faces;
+		const sourceVertices = geometry2.vertices;
+		const faces = geometry2.faces;
 
-	// now create a data structure where each entry represents an edge with its adjoining faces
+		// now create a data structure where each entry represents an edge with its adjoining faces
 
-	for ( let i = 0, l = faces.length; i < l; i ++ ) {
+		for ( let i = 0, l = faces.length; i < l; i ++ ) {
 
-		const face = faces[ i ];
+			const face = faces[ i ];
 
-		for ( let j = 0; j < 3; j ++ ) {
+			for ( let j = 0; j < 3; j ++ ) {
 
-			edge1 = face[ keys[ j ] ];
-			edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
-			edge[ 0 ] = Math.min( edge1, edge2 );
-			edge[ 1 ] = Math.max( edge1, edge2 );
+				edge1 = face[ keys[ j ] ];
+				edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
+				edge[ 0 ] = Math.min( edge1, edge2 );
+				edge[ 1 ] = Math.max( edge1, edge2 );
 
-			key = edge[ 0 ] + ',' + edge[ 1 ];
+				key = edge[ 0 ] + ',' + edge[ 1 ];
 
-			if ( edges[ key ] === undefined ) {
+				if ( edges[ key ] === undefined ) {
 
-				edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined };
+					edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ], face1: i, face2: undefined };
 
-			} else {
+				} else {
 
-				edges[ key ].face2 = i;
+					edges[ key ].face2 = i;
+
+				}
 
 			}
 
 		}
 
-	}
+		// generate vertices
 
-	// generate vertices
+		for ( key in edges ) {
 
-	for ( key in edges ) {
+			const e = edges[ key ];
 
-		const e = edges[ key ];
+			// an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.
 
-		// an edge is only rendered if the angle (in degrees) between the face normals of the adjoining faces exceeds this value. default = 1 degree.
+			if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) {
 
-		if ( e.face2 === undefined || faces[ e.face1 ].normal.dot( faces[ e.face2 ].normal ) <= thresholdDot ) {
+				let vertex = sourceVertices[ e.index1 ];
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			let vertex = sourceVertices[ e.index1 ];
-			vertices.push( vertex.x, vertex.y, vertex.z );
+				vertex = sourceVertices[ e.index2 ];
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			vertex = sourceVertices[ e.index2 ];
-			vertices.push( vertex.x, vertex.y, vertex.z );
+			}
 
 		}
 
-	}
+		// build geometry
 
-	// build geometry
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+	}
 
 }
 
-EdgesGeometry.prototype = Object.create( BufferGeometry.prototype );
-EdgesGeometry.prototype.constructor = EdgesGeometry;
-
 
 export { EdgesGeometry };

Fișier diff suprimat deoarece este prea mare
+ 382 - 381
src/geometries/ExtrudeGeometry.js


+ 36 - 34
src/geometries/IcosahedronGeometry.js

@@ -3,57 +3,59 @@ import { PolyhedronBufferGeometry } from './PolyhedronGeometry.js';
 
 // IcosahedronGeometry
 
-function IcosahedronGeometry( radius, detail ) {
+class IcosahedronGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( radius, detail ) {
 
-	this.type = 'IcosahedronGeometry';
+		super();
 
-	this.parameters = {
-		radius: radius,
-		detail: detail
-	};
+		this.type = 'IcosahedronGeometry';
 
-	this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );
-	this.mergeVertices();
+		this.parameters = {
+			radius: radius,
+			detail: detail
+		};
 
-}
+		this.fromBufferGeometry( new IcosahedronBufferGeometry( radius, detail ) );
+		this.mergeVertices();
+
+	}
 
-IcosahedronGeometry.prototype = Object.create( Geometry.prototype );
-IcosahedronGeometry.prototype.constructor = IcosahedronGeometry;
+}
 
 // IcosahedronBufferGeometry
 
-function IcosahedronBufferGeometry( radius, detail ) {
+class IcosahedronBufferGeometry extends PolyhedronBufferGeometry {
 
-	const t = ( 1 + Math.sqrt( 5 ) ) / 2;
+	constructor( radius, detail ) {
 
-	const vertices = [
-		- 1, t, 0, 	1, t, 0, 	- 1, - t, 0, 	1, - t, 0,
-		 0, - 1, t, 	0, 1, t,	0, - 1, - t, 	0, 1, - t,
-		 t, 0, - 1, 	t, 0, 1, 	- t, 0, - 1, 	- t, 0, 1
-	];
+		const t = ( 1 + Math.sqrt( 5 ) ) / 2;
 
-	const indices = [
-		 0, 11, 5, 	0, 5, 1, 	0, 1, 7, 	0, 7, 10, 	0, 10, 11,
-		 1, 5, 9, 	5, 11, 4,	11, 10, 2,	10, 7, 6,	7, 1, 8,
-		 3, 9, 4, 	3, 4, 2,	3, 2, 6,	3, 6, 8,	3, 8, 9,
-		 4, 9, 5, 	2, 4, 11,	6, 2, 10,	8, 6, 7,	9, 8, 1
-	];
+		const vertices = [
+			- 1, t, 0, 	1, t, 0, 	- 1, - t, 0, 	1, - t, 0,
+			0, - 1, t, 	0, 1, t,	0, - 1, - t, 	0, 1, - t,
+			t, 0, - 1, 	t, 0, 1, 	- t, 0, - 1, 	- t, 0, 1
+		];
 
-	PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
+		const indices = [
+			0, 11, 5, 	0, 5, 1, 	0, 1, 7, 	0, 7, 10, 	0, 10, 11,
+			1, 5, 9, 	5, 11, 4,	11, 10, 2,	10, 7, 6,	7, 1, 8,
+			3, 9, 4, 	3, 4, 2,	3, 2, 6,	3, 6, 8,	3, 8, 9,
+			4, 9, 5, 	2, 4, 11,	6, 2, 10,	8, 6, 7,	9, 8, 1
+		];
 
-	this.type = 'IcosahedronBufferGeometry';
+		super( vertices, indices, radius, detail );
 
-	this.parameters = {
-		radius: radius,
-		detail: detail
-	};
+		this.type = 'IcosahedronBufferGeometry';
 
-}
+		this.parameters = {
+			radius: radius,
+			detail: detail
+		};
+
+	}
 
-IcosahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
-IcosahedronBufferGeometry.prototype.constructor = IcosahedronBufferGeometry;
+}
 
 
 export { IcosahedronGeometry, IcosahedronBufferGeometry };

+ 99 - 97
src/geometries/LatheGeometry.js

@@ -7,163 +7,168 @@ import { MathUtils } from '../math/MathUtils.js';
 
 // LatheGeometry
 
-function LatheGeometry( points, segments, phiStart, phiLength ) {
+class LatheGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( points, segments, phiStart, phiLength ) {
 
-	this.type = 'LatheGeometry';
+		super();
 
-	this.parameters = {
-		points: points,
-		segments: segments,
-		phiStart: phiStart,
-		phiLength: phiLength
-	};
+		this.type = 'LatheGeometry';
 
-	this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );
-	this.mergeVertices();
+		this.parameters = {
+			points: points,
+			segments: segments,
+			phiStart: phiStart,
+			phiLength: phiLength
+		};
 
-}
+		this.fromBufferGeometry( new LatheBufferGeometry( points, segments, phiStart, phiLength ) );
+		this.mergeVertices();
 
-LatheGeometry.prototype = Object.create( Geometry.prototype );
-LatheGeometry.prototype.constructor = LatheGeometry;
+	}
+
+}
 
 // LatheBufferGeometry
 
-function LatheBufferGeometry( points, segments, phiStart, phiLength ) {
+class LatheBufferGeometry extends BufferGeometry {
+
+	constructor( points, segments, phiStart, phiLength ) {
 
-	BufferGeometry.call( this );
+		super();
 
-	this.type = 'LatheBufferGeometry';
+		this.type = 'LatheBufferGeometry';
 
-	this.parameters = {
-		points: points,
-		segments: segments,
-		phiStart: phiStart,
-		phiLength: phiLength
-	};
+		this.parameters = {
+			points: points,
+			segments: segments,
+			phiStart: phiStart,
+			phiLength: phiLength
+		};
 
-	segments = Math.floor( segments ) || 12;
-	phiStart = phiStart || 0;
-	phiLength = phiLength || Math.PI * 2;
+		segments = Math.floor( segments ) || 12;
+		phiStart = phiStart || 0;
+		phiLength = phiLength || Math.PI * 2;
 
-	// clamp phiLength so it's in range of [ 0, 2PI ]
+		// clamp phiLength so it's in range of [ 0, 2PI ]
 
-	phiLength = MathUtils.clamp( phiLength, 0, Math.PI * 2 );
+		phiLength = MathUtils.clamp( phiLength, 0, Math.PI * 2 );
 
 
-	// buffers
+		// buffers
 
-	const indices = [];
-	const vertices = [];
-	const uvs = [];
+		const indices = [];
+		const vertices = [];
+		const uvs = [];
 
-	// helper variables
+		// helper variables
 
-	const inverseSegments = 1.0 / segments;
-	const vertex = new Vector3();
-	const uv = new Vector2();
+		const inverseSegments = 1.0 / segments;
+		const vertex = new Vector3();
+		const uv = new Vector2();
 
-	// generate vertices and uvs
+		// generate vertices and uvs
 
-	for ( let i = 0; i <= segments; i ++ ) {
+		for ( let i = 0; i <= segments; i ++ ) {
 
-		const phi = phiStart + i * inverseSegments * phiLength;
+			const phi = phiStart + i * inverseSegments * phiLength;
 
-		const sin = Math.sin( phi );
-		const cos = Math.cos( phi );
+			const sin = Math.sin( phi );
+			const cos = Math.cos( phi );
 
-		for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
+			for ( let j = 0; j <= ( points.length - 1 ); j ++ ) {
 
-			// vertex
+				// vertex
 
-			vertex.x = points[ j ].x * sin;
-			vertex.y = points[ j ].y;
-			vertex.z = points[ j ].x * cos;
+				vertex.x = points[ j ].x * sin;
+				vertex.y = points[ j ].y;
+				vertex.z = points[ j ].x * cos;
 
-			vertices.push( vertex.x, vertex.y, vertex.z );
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			// uv
+				// uv
 
-			uv.x = i / segments;
-			uv.y = j / ( points.length - 1 );
+				uv.x = i / segments;
+				uv.y = j / ( points.length - 1 );
 
-			uvs.push( uv.x, uv.y );
+				uvs.push( uv.x, uv.y );
 
 
+			}
+
 		}
 
-	}
+		// indices
 
-	// indices
+		for ( let i = 0; i < segments; i ++ ) {
 
-	for ( let i = 0; i < segments; i ++ ) {
+			for ( let j = 0; j < ( points.length - 1 ); j ++ ) {
 
-		for ( let j = 0; j < ( points.length - 1 ); j ++ ) {
+				const base = j + i * points.length;
 
-			const base = j + i * points.length;
+				const a = base;
+				const b = base + points.length;
+				const c = base + points.length + 1;
+				const d = base + 1;
 
-			const a = base;
-			const b = base + points.length;
-			const c = base + points.length + 1;
-			const d = base + 1;
+				// faces
 
-			// faces
+				indices.push( a, b, d );
+				indices.push( b, c, d );
 
-			indices.push( a, b, d );
-			indices.push( b, c, d );
+			}
 
 		}
 
-	}
+		// build geometry
 
-	// build geometry
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-	this.setIndex( indices );
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+		// generate normals
 
-	// generate normals
+		this.computeVertexNormals();
 
-	this.computeVertexNormals();
+		// if the geometry is closed, we need to average the normals along the seam.
+		// because the corresponding vertices are identical (but still have different UVs).
 
-	// if the geometry is closed, we need to average the normals along the seam.
-	// because the corresponding vertices are identical (but still have different UVs).
+		if ( phiLength === Math.PI * 2 ) {
 
-	if ( phiLength === Math.PI * 2 ) {
+			const normals = this.attributes.normal.array;
+			const n1 = new Vector3();
+			const n2 = new Vector3();
+			const n = new Vector3();
 
-		const normals = this.attributes.normal.array;
-		const n1 = new Vector3();
-		const n2 = new Vector3();
-		const n = new Vector3();
+			// this is the buffer offset for the last line of vertices
 
-		// this is the buffer offset for the last line of vertices
+			const base = segments * points.length * 3;
 
-		const base = segments * points.length * 3;
+			for ( let i = 0, j = 0; i < points.length; i ++, j += 3 ) {
 
-		for ( let i = 0, j = 0; i < points.length; i ++, j += 3 ) {
+				// select the normal of the vertex in the first line
 
-			// select the normal of the vertex in the first line
+				n1.x = normals[ j + 0 ];
+				n1.y = normals[ j + 1 ];
+				n1.z = normals[ j + 2 ];
 
-			n1.x = normals[ j + 0 ];
-			n1.y = normals[ j + 1 ];
-			n1.z = normals[ j + 2 ];
+				// select the normal of the vertex in the last line
 
-			// select the normal of the vertex in the last line
+				n2.x = normals[ base + j + 0 ];
+				n2.y = normals[ base + j + 1 ];
+				n2.z = normals[ base + j + 2 ];
 
-			n2.x = normals[ base + j + 0 ];
-			n2.y = normals[ base + j + 1 ];
-			n2.z = normals[ base + j + 2 ];
+				// average normals
 
-			// average normals
+				n.addVectors( n1, n2 ).normalize();
 
-			n.addVectors( n1, n2 ).normalize();
+				// assign the new values to both normals
 
-			// assign the new values to both normals
+				normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
+				normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
+				normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
 
-			normals[ j + 0 ] = normals[ base + j + 0 ] = n.x;
-			normals[ j + 1 ] = normals[ base + j + 1 ] = n.y;
-			normals[ j + 2 ] = normals[ base + j + 2 ] = n.z;
+			}
 
 		}
 
@@ -171,8 +176,5 @@ function LatheBufferGeometry( points, segments, phiStart, phiLength ) {
 
 }
 
-LatheBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-LatheBufferGeometry.prototype.constructor = LatheBufferGeometry;
-
 
 export { LatheGeometry, LatheBufferGeometry };

+ 33 - 31
src/geometries/OctahedronGeometry.js

@@ -3,53 +3,55 @@ import { PolyhedronBufferGeometry } from './PolyhedronGeometry.js';
 
 // OctahedronGeometry
 
-function OctahedronGeometry( radius, detail ) {
+class OctahedronGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( radius, detail ) {
 
-	this.type = 'OctahedronGeometry';
+		super();
 
-	this.parameters = {
-		radius: radius,
-		detail: detail
-	};
+		this.type = 'OctahedronGeometry';
 
-	this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );
-	this.mergeVertices();
+		this.parameters = {
+			radius: radius,
+			detail: detail
+		};
 
-}
+		this.fromBufferGeometry( new OctahedronBufferGeometry( radius, detail ) );
+		this.mergeVertices();
+
+	}
 
-OctahedronGeometry.prototype = Object.create( Geometry.prototype );
-OctahedronGeometry.prototype.constructor = OctahedronGeometry;
+}
 
 // OctahedronBufferGeometry
 
-function OctahedronBufferGeometry( radius, detail ) {
+class OctahedronBufferGeometry extends PolyhedronBufferGeometry {
 
-	const vertices = [
-		1, 0, 0, 	- 1, 0, 0,	0, 1, 0,
-		0, - 1, 0, 	0, 0, 1,	0, 0, - 1
-	];
+	constructor( radius, detail ) {
 
-	const indices = [
-		0, 2, 4,	0, 4, 3,	0, 3, 5,
-		0, 5, 2,	1, 2, 5,	1, 5, 3,
-		1, 3, 4,	1, 4, 2
-	];
+		const vertices = [
+			1, 0, 0, 	- 1, 0, 0,	0, 1, 0,
+			0, - 1, 0, 	0, 0, 1,	0, 0, - 1
+		];
 
-	PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
+		const indices = [
+			0, 2, 4,	0, 4, 3,	0, 3, 5,
+			0, 5, 2,	1, 2, 5,	1, 5, 3,
+			1, 3, 4,	1, 4, 2
+		];
 
-	this.type = 'OctahedronBufferGeometry';
+		super( vertices, indices, radius, detail );
 
-	this.parameters = {
-		radius: radius,
-		detail: detail
-	};
+		this.type = 'OctahedronBufferGeometry';
 
-}
+		this.parameters = {
+			radius: radius,
+			detail: detail
+		};
+
+	}
 
-OctahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
-OctahedronBufferGeometry.prototype.constructor = OctahedronBufferGeometry;
+}
 
 
 export { OctahedronGeometry, OctahedronBufferGeometry };

+ 68 - 67
src/geometries/PlaneGeometry.js

@@ -4,116 +4,117 @@ import { Float32BufferAttribute } from '../core/BufferAttribute.js';
 
 // PlaneGeometry
 
-function PlaneGeometry( width, height, widthSegments, heightSegments ) {
+class PlaneGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( width, height, widthSegments, heightSegments ) {
 
-	this.type = 'PlaneGeometry';
+		super();
 
-	this.parameters = {
-		width: width,
-		height: height,
-		widthSegments: widthSegments,
-		heightSegments: heightSegments
-	};
+		this.type = 'PlaneGeometry';
 
-	this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );
-	this.mergeVertices();
+		this.parameters = {
+			width: width,
+			height: height,
+			widthSegments: widthSegments,
+			heightSegments: heightSegments
+		};
 
-}
+		this.fromBufferGeometry( new PlaneBufferGeometry( width, height, widthSegments, heightSegments ) );
+		this.mergeVertices();
 
-PlaneGeometry.prototype = Object.create( Geometry.prototype );
-PlaneGeometry.prototype.constructor = PlaneGeometry;
+	}
+
+}
 
 // PlaneBufferGeometry
 
-function PlaneBufferGeometry( width, height, widthSegments, heightSegments ) {
+class PlaneBufferGeometry extends BufferGeometry {
+
+	constructor( width, height, widthSegments, heightSegments ) {
 
-	BufferGeometry.call( this );
+		super();
+		this.type = 'PlaneBufferGeometry';
 
-	this.type = 'PlaneBufferGeometry';
+		this.parameters = {
+			width: width,
+			height: height,
+			widthSegments: widthSegments,
+			heightSegments: heightSegments
+		};
 
-	this.parameters = {
-		width: width,
-		height: height,
-		widthSegments: widthSegments,
-		heightSegments: heightSegments
-	};
+		width = width || 1;
+		height = height || 1;
 
-	width = width || 1;
-	height = height || 1;
+		const width_half = width / 2;
+		const height_half = height / 2;
 
-	const width_half = width / 2;
-	const height_half = height / 2;
+		const gridX = Math.floor( widthSegments ) || 1;
+		const gridY = Math.floor( heightSegments ) || 1;
 
-	const gridX = Math.floor( widthSegments ) || 1;
-	const gridY = Math.floor( heightSegments ) || 1;
+		const gridX1 = gridX + 1;
+		const gridY1 = gridY + 1;
 
-	const gridX1 = gridX + 1;
-	const gridY1 = gridY + 1;
+		const segment_width = width / gridX;
+		const segment_height = height / gridY;
 
-	const segment_width = width / gridX;
-	const segment_height = height / gridY;
+		// buffers
 
-	// buffers
+		const indices = [];
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
 
-	const indices = [];
-	const vertices = [];
-	const normals = [];
-	const uvs = [];
+		// generate vertices, normals and uvs
 
-	// generate vertices, normals and uvs
+		for ( let iy = 0; iy < gridY1; iy ++ ) {
 
-	for ( let iy = 0; iy < gridY1; iy ++ ) {
+			const y = iy * segment_height - height_half;
 
-		const y = iy * segment_height - height_half;
+			for ( let ix = 0; ix < gridX1; ix ++ ) {
 
-		for ( let ix = 0; ix < gridX1; ix ++ ) {
+				const x = ix * segment_width - width_half;
 
-			const x = ix * segment_width - width_half;
+				vertices.push( x, - y, 0 );
 
-			vertices.push( x, - y, 0 );
+				normals.push( 0, 0, 1 );
 
-			normals.push( 0, 0, 1 );
+				uvs.push( ix / gridX );
+				uvs.push( 1 - ( iy / gridY ) );
 
-			uvs.push( ix / gridX );
-			uvs.push( 1 - ( iy / gridY ) );
+			}
 
 		}
 
-	}
+		// indices
 
-	// indices
+		for ( let iy = 0; iy < gridY; iy ++ ) {
 
-	for ( let iy = 0; iy < gridY; iy ++ ) {
+			for ( let ix = 0; ix < gridX; ix ++ ) {
 
-		for ( let ix = 0; ix < gridX; ix ++ ) {
+				const a = ix + gridX1 * iy;
+				const b = ix + gridX1 * ( iy + 1 );
+				const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
+				const d = ( ix + 1 ) + gridX1 * iy;
 
-			const a = ix + gridX1 * iy;
-			const b = ix + gridX1 * ( iy + 1 );
-			const c = ( ix + 1 ) + gridX1 * ( iy + 1 );
-			const d = ( ix + 1 ) + gridX1 * iy;
+				// faces
 
-			// faces
+				indices.push( a, b, d );
+				indices.push( b, c, d );
 
-			indices.push( a, b, d );
-			indices.push( b, c, d );
+			}
 
 		}
 
-	}
+		// build geometry
 
-	// build geometry
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-	this.setIndex( indices );
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+	}
 
 }
 
-PlaneBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-PlaneBufferGeometry.prototype.constructor = PlaneBufferGeometry;
-
 
 export { PlaneGeometry, PlaneBufferGeometry };

+ 175 - 173
src/geometries/PolyhedronGeometry.js

@@ -6,158 +6,163 @@ import { Vector2 } from '../math/Vector2.js';
 
 // PolyhedronGeometry
 
-function PolyhedronGeometry( vertices, indices, radius, detail ) {
+class PolyhedronGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( vertices, indices, radius, detail ) {
 
-	this.type = 'PolyhedronGeometry';
+		super();
 
-	this.parameters = {
-		vertices: vertices,
-		indices: indices,
-		radius: radius,
-		detail: detail
-	};
+		this.type = 'PolyhedronGeometry';
 
-	this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
-	this.mergeVertices();
+		this.parameters = {
+			vertices: vertices,
+			indices: indices,
+			radius: radius,
+			detail: detail
+		};
 
-}
+		this.fromBufferGeometry( new PolyhedronBufferGeometry( vertices, indices, radius, detail ) );
+		this.mergeVertices();
 
-PolyhedronGeometry.prototype = Object.create( Geometry.prototype );
-PolyhedronGeometry.prototype.constructor = PolyhedronGeometry;
+	}
+
+}
 
 // PolyhedronBufferGeometry
 
-function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
+class PolyhedronBufferGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( vertices, indices, radius, detail ) {
 
-	this.type = 'PolyhedronBufferGeometry';
+		super();
 
-	this.parameters = {
-		vertices: vertices,
-		indices: indices,
-		radius: radius,
-		detail: detail
-	};
+		this.type = 'PolyhedronBufferGeometry';
 
-	radius = radius || 1;
-	detail = detail || 0;
+		this.parameters = {
+			vertices: vertices,
+			indices: indices,
+			radius: radius,
+			detail: detail
+		};
 
-	// default buffer data
+		radius = radius || 1;
+		detail = detail || 0;
 
-	const vertexBuffer = [];
-	const uvBuffer = [];
+		// default buffer data
 
-	// the subdivision creates the vertex buffer data
+		const vertexBuffer = [];
+		const uvBuffer = [];
 
-	subdivide( detail );
+		// the subdivision creates the vertex buffer data
 
-	// all vertices should lie on a conceptual sphere with a given radius
+		subdivide( detail );
 
-	applyRadius( radius );
+		// all vertices should lie on a conceptual sphere with a given radius
 
-	// finally, create the uv data
+		applyRadius( radius );
 
-	generateUVs();
+		// finally, create the uv data
 
-	// build non-indexed geometry
+		generateUVs();
 
-	this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
+		// build non-indexed geometry
 
-	if ( detail === 0 ) {
+		this.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );
 
-		this.computeVertexNormals(); // flat normals
+		if ( detail === 0 ) {
 
-	} else {
+			this.computeVertexNormals(); // flat normals
 
-		this.normalizeNormals(); // smooth normals
+		} else {
 
-	}
+			this.normalizeNormals(); // smooth normals
 
-	// helper functions
+		}
+
+		// helper functions
 
-	function subdivide( detail ) {
+		function subdivide( detail ) {
 
-		const a = new Vector3();
-		const b = new Vector3();
-		const c = new Vector3();
+			const a = new Vector3();
+			const b = new Vector3();
+			const c = new Vector3();
 
-		// iterate over all faces and apply a subdivison with the given detail value
+			// iterate over all faces and apply a subdivison with the given detail value
 
-		for ( let i = 0; i < indices.length; i += 3 ) {
+			for ( let i = 0; i < indices.length; i += 3 ) {
 
-			// get the vertices of the face
+				// get the vertices of the face
 
-			getVertexByIndex( indices[ i + 0 ], a );
-			getVertexByIndex( indices[ i + 1 ], b );
-			getVertexByIndex( indices[ i + 2 ], c );
+				getVertexByIndex( indices[ i + 0 ], a );
+				getVertexByIndex( indices[ i + 1 ], b );
+				getVertexByIndex( indices[ i + 2 ], c );
 
-			// perform subdivision
+				// perform subdivision
 
-			subdivideFace( a, b, c, detail );
+				subdivideFace( a, b, c, detail );
+
+			}
 
 		}
 
-	}
+		function subdivideFace( a, b, c, detail ) {
 
-	function subdivideFace( a, b, c, detail ) {
+			const cols = Math.pow( 2, detail );
 
-		const cols = Math.pow( 2, detail );
+			// we use this multidimensional array as a data structure for creating the subdivision
 
-		// we use this multidimensional array as a data structure for creating the subdivision
+			const v = [];
 
-		const v = [];
+			// construct all of the vertices for this subdivision
 
-		// construct all of the vertices for this subdivision
+			for ( let i = 0; i <= cols; i ++ ) {
 
-		for ( let i = 0; i <= cols; i ++ ) {
+				v[ i ] = [];
 
-			v[ i ] = [];
+				const aj = a.clone().lerp( c, i / cols );
+				const bj = b.clone().lerp( c, i / cols );
 
-			const aj = a.clone().lerp( c, i / cols );
-			const bj = b.clone().lerp( c, i / cols );
+				const rows = cols - i;
 
-			const rows = cols - i;
+				for ( let j = 0; j <= rows; j ++ ) {
 
-			for ( let j = 0; j <= rows; j ++ ) {
+					if ( j === 0 && i === cols ) {
 
-				if ( j === 0 && i === cols ) {
+						v[ i ][ j ] = aj;
 
-					v[ i ][ j ] = aj;
+					} else {
 
-				} else {
+						v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
 
-					v[ i ][ j ] = aj.clone().lerp( bj, j / rows );
+					}
 
 				}
 
 			}
 
-		}
+			// construct all of the faces
 
-		// construct all of the faces
+			for ( let i = 0; i < cols; i ++ ) {
 
-		for ( let i = 0; i < cols; i ++ ) {
+				for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
 
-			for ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {
+					const k = Math.floor( j / 2 );
 
-				const k = Math.floor( j / 2 );
+					if ( j % 2 === 0 ) {
 
-				if ( j % 2 === 0 ) {
+						pushVertex( v[ i ][ k + 1 ] );
+						pushVertex( v[ i + 1 ][ k ] );
+						pushVertex( v[ i ][ k ] );
 
-					pushVertex( v[ i ][ k + 1 ] );
-					pushVertex( v[ i + 1 ][ k ] );
-					pushVertex( v[ i ][ k ] );
+					} else {
 
-				} else {
+						pushVertex( v[ i ][ k + 1 ] );
+						pushVertex( v[ i + 1 ][ k + 1 ] );
+						pushVertex( v[ i + 1 ][ k ] );
 
-					pushVertex( v[ i ][ k + 1 ] );
-					pushVertex( v[ i + 1 ][ k + 1 ] );
-					pushVertex( v[ i + 1 ][ k ] );
+					}
 
 				}
 
@@ -165,168 +170,165 @@ function PolyhedronBufferGeometry( vertices, indices, radius, detail ) {
 
 		}
 
-	}
+		function applyRadius( radius ) {
 
-	function applyRadius( radius ) {
+			const vertex = new Vector3();
 
-		const vertex = new Vector3();
+			// iterate over the entire buffer and apply the radius to each vertex
 
-		// iterate over the entire buffer and apply the radius to each vertex
+			for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
 
-		for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
+				vertex.x = vertexBuffer[ i + 0 ];
+				vertex.y = vertexBuffer[ i + 1 ];
+				vertex.z = vertexBuffer[ i + 2 ];
 
-			vertex.x = vertexBuffer[ i + 0 ];
-			vertex.y = vertexBuffer[ i + 1 ];
-			vertex.z = vertexBuffer[ i + 2 ];
+				vertex.normalize().multiplyScalar( radius );
 
-			vertex.normalize().multiplyScalar( radius );
+				vertexBuffer[ i + 0 ] = vertex.x;
+				vertexBuffer[ i + 1 ] = vertex.y;
+				vertexBuffer[ i + 2 ] = vertex.z;
 
-			vertexBuffer[ i + 0 ] = vertex.x;
-			vertexBuffer[ i + 1 ] = vertex.y;
-			vertexBuffer[ i + 2 ] = vertex.z;
+			}
 
 		}
 
-	}
+		function generateUVs() {
 
-	function generateUVs() {
+			const vertex = new Vector3();
 
-		const vertex = new Vector3();
+			for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
 
-		for ( let i = 0; i < vertexBuffer.length; i += 3 ) {
+				vertex.x = vertexBuffer[ i + 0 ];
+				vertex.y = vertexBuffer[ i + 1 ];
+				vertex.z = vertexBuffer[ i + 2 ];
 
-			vertex.x = vertexBuffer[ i + 0 ];
-			vertex.y = vertexBuffer[ i + 1 ];
-			vertex.z = vertexBuffer[ i + 2 ];
+				const u = azimuth( vertex ) / 2 / Math.PI + 0.5;
+				const v = inclination( vertex ) / Math.PI + 0.5;
+				uvBuffer.push( u, 1 - v );
 
-			const u = azimuth( vertex ) / 2 / Math.PI + 0.5;
-			const v = inclination( vertex ) / Math.PI + 0.5;
-			uvBuffer.push( u, 1 - v );
+			}
 
-		}
+			correctUVs();
 
-		correctUVs();
+			correctSeam();
 
-		correctSeam();
+		}
 
-	}
+		function correctSeam() {
 
-	function correctSeam() {
+			// handle case when face straddles the seam, see #3269
 
-		// handle case when face straddles the seam, see #3269
+			for ( let i = 0; i < uvBuffer.length; i += 6 ) {
 
-		for ( let i = 0; i < uvBuffer.length; i += 6 ) {
+				// uv data of a single face
 
-			// uv data of a single face
+				const x0 = uvBuffer[ i + 0 ];
+				const x1 = uvBuffer[ i + 2 ];
+				const x2 = uvBuffer[ i + 4 ];
 
-			const x0 = uvBuffer[ i + 0 ];
-			const x1 = uvBuffer[ i + 2 ];
-			const x2 = uvBuffer[ i + 4 ];
+				const max = Math.max( x0, x1, x2 );
+				const min = Math.min( x0, x1, x2 );
 
-			const max = Math.max( x0, x1, x2 );
-			const min = Math.min( x0, x1, x2 );
+				// 0.9 is somewhat arbitrary
 
-			// 0.9 is somewhat arbitrary
+				if ( max > 0.9 && min < 0.1 ) {
 
-			if ( max > 0.9 && min < 0.1 ) {
+					if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
+					if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
+					if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
 
-				if ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;
-				if ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;
-				if ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;
+				}
 
 			}
 
 		}
 
-	}
+		function pushVertex( vertex ) {
 
-	function pushVertex( vertex ) {
+			vertexBuffer.push( vertex.x, vertex.y, vertex.z );
 
-		vertexBuffer.push( vertex.x, vertex.y, vertex.z );
+		}
 
-	}
+		function getVertexByIndex( index, vertex ) {
 
-	function getVertexByIndex( index, vertex ) {
+			const stride = index * 3;
 
-		const stride = index * 3;
+			vertex.x = vertices[ stride + 0 ];
+			vertex.y = vertices[ stride + 1 ];
+			vertex.z = vertices[ stride + 2 ];
 
-		vertex.x = vertices[ stride + 0 ];
-		vertex.y = vertices[ stride + 1 ];
-		vertex.z = vertices[ stride + 2 ];
+		}
 
-	}
+		function correctUVs() {
 
-	function correctUVs() {
+			const a = new Vector3();
+			const b = new Vector3();
+			const c = new Vector3();
 
-		const a = new Vector3();
-		const b = new Vector3();
-		const c = new Vector3();
+			const centroid = new Vector3();
 
-		const centroid = new Vector3();
+			const uvA = new Vector2();
+			const uvB = new Vector2();
+			const uvC = new Vector2();
 
-		const uvA = new Vector2();
-		const uvB = new Vector2();
-		const uvC = new Vector2();
+			for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
 
-		for ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {
+				a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
+				b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
+				c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
 
-			a.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );
-			b.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );
-			c.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );
+				uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
+				uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
+				uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
 
-			uvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );
-			uvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );
-			uvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );
+				centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
 
-			centroid.copy( a ).add( b ).add( c ).divideScalar( 3 );
+				const azi = azimuth( centroid );
 
-			const azi = azimuth( centroid );
+				correctUV( uvA, j + 0, a, azi );
+				correctUV( uvB, j + 2, b, azi );
+				correctUV( uvC, j + 4, c, azi );
 
-			correctUV( uvA, j + 0, a, azi );
-			correctUV( uvB, j + 2, b, azi );
-			correctUV( uvC, j + 4, c, azi );
+			}
 
 		}
 
-	}
+		function correctUV( uv, stride, vector, azimuth ) {
 
-	function correctUV( uv, stride, vector, azimuth ) {
+			if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
 
-		if ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {
+				uvBuffer[ stride ] = uv.x - 1;
 
-			uvBuffer[ stride ] = uv.x - 1;
+			}
 
-		}
+			if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
 
-		if ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {
+				uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
 
-			uvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;
+			}
 
 		}
 
-	}
+		// Angle around the Y axis, counter-clockwise when looking from above.
 
-	// Angle around the Y axis, counter-clockwise when looking from above.
+		function azimuth( vector ) {
 
-	function azimuth( vector ) {
+			return Math.atan2( vector.z, - vector.x );
 
-		return Math.atan2( vector.z, - vector.x );
+		}
 
-	}
 
+		// Angle above the XZ plane.
 
-	// Angle above the XZ plane.
+		function inclination( vector ) {
 
-	function inclination( vector ) {
+			return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
 
-		return Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );
+		}
 
 	}
 
 }
 
-PolyhedronBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-PolyhedronBufferGeometry.prototype.constructor = PolyhedronBufferGeometry;
-
 
 export { PolyhedronGeometry, PolyhedronBufferGeometry };

+ 85 - 83
src/geometries/RingGeometry.js

@@ -6,140 +6,142 @@ import { Vector3 } from '../math/Vector3.js';
 
 // RingGeometry
 
-function RingGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
+class RingGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
 
-	this.type = 'RingGeometry';
+		super();
 
-	this.parameters = {
-		innerRadius: innerRadius,
-		outerRadius: outerRadius,
-		thetaSegments: thetaSegments,
-		phiSegments: phiSegments,
-		thetaStart: thetaStart,
-		thetaLength: thetaLength
-	};
+		this.type = 'RingGeometry';
 
-	this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );
-	this.mergeVertices();
+		this.parameters = {
+			innerRadius: innerRadius,
+			outerRadius: outerRadius,
+			thetaSegments: thetaSegments,
+			phiSegments: phiSegments,
+			thetaStart: thetaStart,
+			thetaLength: thetaLength
+		};
 
-}
+		this.fromBufferGeometry( new RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) );
+		this.mergeVertices();
+
+	}
 
-RingGeometry.prototype = Object.create( Geometry.prototype );
-RingGeometry.prototype.constructor = RingGeometry;
+}
 
 // RingBufferGeometry
 
-function RingBufferGeometry( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
+class RingBufferGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength ) {
 
-	this.type = 'RingBufferGeometry';
+		super();
 
-	this.parameters = {
-		innerRadius: innerRadius,
-		outerRadius: outerRadius,
-		thetaSegments: thetaSegments,
-		phiSegments: phiSegments,
-		thetaStart: thetaStart,
-		thetaLength: thetaLength
-	};
+		this.type = 'RingBufferGeometry';
 
-	innerRadius = innerRadius || 0.5;
-	outerRadius = outerRadius || 1;
+		this.parameters = {
+			innerRadius: innerRadius,
+			outerRadius: outerRadius,
+			thetaSegments: thetaSegments,
+			phiSegments: phiSegments,
+			thetaStart: thetaStart,
+			thetaLength: thetaLength
+		};
 
-	thetaStart = thetaStart !== undefined ? thetaStart : 0;
-	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
+		innerRadius = innerRadius || 0.5;
+		outerRadius = outerRadius || 1;
 
-	thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8;
-	phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1;
+		thetaStart = thetaStart !== undefined ? thetaStart : 0;
+		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI * 2;
 
-	// buffers
+		thetaSegments = thetaSegments !== undefined ? Math.max( 3, thetaSegments ) : 8;
+		phiSegments = phiSegments !== undefined ? Math.max( 1, phiSegments ) : 1;
 
-	const indices = [];
-	const vertices = [];
-	const normals = [];
-	const uvs = [];
+		// buffers
 
-	// some helper variables
+		const indices = [];
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
 
-	let radius = innerRadius;
-	const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
-	const vertex = new Vector3();
-	const uv = new Vector2();
+		// some helper variables
 
-	// generate vertices, normals and uvs
+		let radius = innerRadius;
+		const radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );
+		const vertex = new Vector3();
+		const uv = new Vector2();
 
-	for ( let j = 0; j <= phiSegments; j ++ ) {
+		// generate vertices, normals and uvs
 
-		for ( let i = 0; i <= thetaSegments; i ++ ) {
+		for ( let j = 0; j <= phiSegments; j ++ ) {
 
-			// values are generate from the inside of the ring to the outside
+			for ( let i = 0; i <= thetaSegments; i ++ ) {
 
-			const segment = thetaStart + i / thetaSegments * thetaLength;
+				// values are generate from the inside of the ring to the outside
 
-			// vertex
+				const segment = thetaStart + i / thetaSegments * thetaLength;
 
-			vertex.x = radius * Math.cos( segment );
-			vertex.y = radius * Math.sin( segment );
+				// vertex
 
-			vertices.push( vertex.x, vertex.y, vertex.z );
+				vertex.x = radius * Math.cos( segment );
+				vertex.y = radius * Math.sin( segment );
 
-			// normal
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			normals.push( 0, 0, 1 );
+				// normal
 
-			// uv
+				normals.push( 0, 0, 1 );
 
-			uv.x = ( vertex.x / outerRadius + 1 ) / 2;
-			uv.y = ( vertex.y / outerRadius + 1 ) / 2;
+				// uv
 
-			uvs.push( uv.x, uv.y );
+				uv.x = ( vertex.x / outerRadius + 1 ) / 2;
+				uv.y = ( vertex.y / outerRadius + 1 ) / 2;
 
-		}
+				uvs.push( uv.x, uv.y );
 
-		// increase the radius for next row of vertices
+			}
 
-		radius += radiusStep;
+			// increase the radius for next row of vertices
 
-	}
+			radius += radiusStep;
 
-	// indices
+		}
+
+		// indices
+
+		for ( let j = 0; j < phiSegments; j ++ ) {
 
-	for ( let j = 0; j < phiSegments; j ++ ) {
+			const thetaSegmentLevel = j * ( thetaSegments + 1 );
 
-		const thetaSegmentLevel = j * ( thetaSegments + 1 );
+			for ( let i = 0; i < thetaSegments; i ++ ) {
 
-		for ( let i = 0; i < thetaSegments; i ++ ) {
+				const segment = i + thetaSegmentLevel;
 
-			const segment = i + thetaSegmentLevel;
+				const a = segment;
+				const b = segment + thetaSegments + 1;
+				const c = segment + thetaSegments + 2;
+				const d = segment + 1;
 
-			const a = segment;
-			const b = segment + thetaSegments + 1;
-			const c = segment + thetaSegments + 2;
-			const d = segment + 1;
+				// faces
 
-			// faces
+				indices.push( a, b, d );
+				indices.push( b, c, d );
 
-			indices.push( a, b, d );
-			indices.push( b, c, d );
+			}
 
 		}
 
-	}
+		// build geometry
 
-	// build geometry
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-	this.setIndex( indices );
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+	}
 
 }
 
-RingBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-RingBufferGeometry.prototype.constructor = RingBufferGeometry;
-
 
 export { RingGeometry, RingBufferGeometry };

+ 97 - 97
src/geometries/ShapeGeometry.js

@@ -5,183 +5,183 @@ import { ShapeUtils } from '../extras/ShapeUtils.js';
 
 // ShapeGeometry
 
-function ShapeGeometry( shapes, curveSegments ) {
+class ShapeGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( shapes, curveSegments ) {
 
-	this.type = 'ShapeGeometry';
+		super();
+		this.type = 'ShapeGeometry';
 
-	if ( typeof curveSegments === 'object' ) {
+		if ( typeof curveSegments === 'object' ) {
 
-		console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );
+			console.warn( 'THREE.ShapeGeometry: Options parameter has been removed.' );
 
-		curveSegments = curveSegments.curveSegments;
+			curveSegments = curveSegments.curveSegments;
 
-	}
+		}
 
-	this.parameters = {
-		shapes: shapes,
-		curveSegments: curveSegments
-	};
+		this.parameters = {
+			shapes: shapes,
+			curveSegments: curveSegments
+		};
 
-	this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );
-	this.mergeVertices();
+		this.fromBufferGeometry( new ShapeBufferGeometry( shapes, curveSegments ) );
+		this.mergeVertices();
 
-}
+	}
 
-ShapeGeometry.prototype = Object.create( Geometry.prototype );
-ShapeGeometry.prototype.constructor = ShapeGeometry;
+	toJSON() {
 
-ShapeGeometry.prototype.toJSON = function () {
+		const data = Geometry.prototype.toJSON.call( this );
 
-	const data = Geometry.prototype.toJSON.call( this );
+		const shapes = this.parameters.shapes;
 
-	const shapes = this.parameters.shapes;
+		return toJSON( shapes, data );
 
-	return toJSON( shapes, data );
+	}
 
-};
+}
 
 // ShapeBufferGeometry
 
-function ShapeBufferGeometry( shapes, curveSegments ) {
+class ShapeBufferGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( shapes, curveSegments ) {
 
-	this.type = 'ShapeBufferGeometry';
+		super();
+		this.type = 'ShapeBufferGeometry';
 
-	this.parameters = {
-		shapes: shapes,
-		curveSegments: curveSegments
-	};
+		this.parameters = {
+			shapes: shapes,
+			curveSegments: curveSegments
+		};
 
-	curveSegments = curveSegments || 12;
+		curveSegments = curveSegments || 12;
 
-	// buffers
+		// buffers
 
-	const indices = [];
-	const vertices = [];
-	const normals = [];
-	const uvs = [];
+		const indices = [];
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
 
-	// helper variables
+		// helper variables
 
-	let groupStart = 0;
-	let groupCount = 0;
+		let groupStart = 0;
+		let groupCount = 0;
 
-	// allow single and array values for "shapes" parameter
+		// allow single and array values for "shapes" parameter
 
-	if ( Array.isArray( shapes ) === false ) {
+		if ( Array.isArray( shapes ) === false ) {
 
-		addShape( shapes );
+			addShape( shapes );
 
-	} else {
+		} else {
+
+			for ( let i = 0; i < shapes.length; i ++ ) {
 
-		for ( let i = 0; i < shapes.length; i ++ ) {
+				addShape( shapes[ i ] );
 
-			addShape( shapes[ i ] );
+				this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
 
-			this.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support
+				groupStart += groupCount;
+				groupCount = 0;
 
-			groupStart += groupCount;
-			groupCount = 0;
+			}
 
 		}
 
-	}
+		// build geometry
 
-	// build geometry
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-	this.setIndex( indices );
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
+		// helper functions
 
-	// helper functions
+		function addShape( shape ) {
 
-	function addShape( shape ) {
+			const indexOffset = vertices.length / 3;
+			const points = shape.extractPoints( curveSegments );
 
-		const indexOffset = vertices.length / 3;
-		const points = shape.extractPoints( curveSegments );
+			let shapeVertices = points.shape;
+			const shapeHoles = points.holes;
 
-		let shapeVertices = points.shape;
-		const shapeHoles = points.holes;
+			// check direction of vertices
 
-		// check direction of vertices
+			if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
 
-		if ( ShapeUtils.isClockWise( shapeVertices ) === false ) {
+				shapeVertices = shapeVertices.reverse();
 
-			shapeVertices = shapeVertices.reverse();
+			}
 
-		}
+			for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
 
-		for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
+				const shapeHole = shapeHoles[ i ];
 
-			const shapeHole = shapeHoles[ i ];
+				if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
 
-			if ( ShapeUtils.isClockWise( shapeHole ) === true ) {
+					shapeHoles[ i ] = shapeHole.reverse();
 
-				shapeHoles[ i ] = shapeHole.reverse();
+				}
 
 			}
 
-		}
+			const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
 
-		const faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );
+			// join vertices of inner and outer paths to a single array
 
-		// join vertices of inner and outer paths to a single array
+			for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
 
-		for ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {
+				const shapeHole = shapeHoles[ i ];
+				shapeVertices = shapeVertices.concat( shapeHole );
 
-			const shapeHole = shapeHoles[ i ];
-			shapeVertices = shapeVertices.concat( shapeHole );
+			}
 
-		}
+			// vertices, normals, uvs
 
-		// vertices, normals, uvs
+			for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {
 
-		for ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {
+				const vertex = shapeVertices[ i ];
 
-			const vertex = shapeVertices[ i ];
+				vertices.push( vertex.x, vertex.y, 0 );
+				normals.push( 0, 0, 1 );
+				uvs.push( vertex.x, vertex.y ); // world uvs
 
-			vertices.push( vertex.x, vertex.y, 0 );
-			normals.push( 0, 0, 1 );
-			uvs.push( vertex.x, vertex.y ); // world uvs
+			}
 
-		}
+			// incides
 
-		// incides
+			for ( let i = 0, l = faces.length; i < l; i ++ ) {
 
-		for ( let i = 0, l = faces.length; i < l; i ++ ) {
+				const face = faces[ i ];
 
-			const face = faces[ i ];
+				const a = face[ 0 ] + indexOffset;
+				const b = face[ 1 ] + indexOffset;
+				const c = face[ 2 ] + indexOffset;
 
-			const a = face[ 0 ] + indexOffset;
-			const b = face[ 1 ] + indexOffset;
-			const c = face[ 2 ] + indexOffset;
+				indices.push( a, b, c );
+				groupCount += 3;
 
-			indices.push( a, b, c );
-			groupCount += 3;
+			}
 
 		}
 
 	}
 
-}
-
-ShapeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-ShapeBufferGeometry.prototype.constructor = ShapeBufferGeometry;
+	toJSON() {
 
-ShapeBufferGeometry.prototype.toJSON = function () {
+		const data = BufferGeometry.prototype.toJSON.call( this );
 
-	const data = BufferGeometry.prototype.toJSON.call( this );
+		const shapes = this.parameters.shapes;
 
-	const shapes = this.parameters.shapes;
+		return toJSON( shapes, data );
 
-	return toJSON( shapes, data );
+	}
 
-};
+}
 
 //
 

+ 91 - 91
src/geometries/SphereGeometry.js

@@ -5,154 +5,154 @@ import { Vector3 } from '../math/Vector3.js';
 
 // SphereGeometry
 
-function SphereGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
+class SphereGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
 
-	this.type = 'SphereGeometry';
+		super();
+		this.type = 'SphereGeometry';
 
-	this.parameters = {
-		radius: radius,
-		widthSegments: widthSegments,
-		heightSegments: heightSegments,
-		phiStart: phiStart,
-		phiLength: phiLength,
-		thetaStart: thetaStart,
-		thetaLength: thetaLength
-	};
+		this.parameters = {
+			radius: radius,
+			widthSegments: widthSegments,
+			heightSegments: heightSegments,
+			phiStart: phiStart,
+			phiLength: phiLength,
+			thetaStart: thetaStart,
+			thetaLength: thetaLength
+		};
 
-	this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );
-	this.mergeVertices();
+		this.fromBufferGeometry( new SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) );
+		this.mergeVertices();
 
-}
+	}
 
-SphereGeometry.prototype = Object.create( Geometry.prototype );
-SphereGeometry.prototype.constructor = SphereGeometry;
+}
 
 // SphereBufferGeometry
 
-function SphereBufferGeometry( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
+class SphereBufferGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength ) {
 
-	this.type = 'SphereBufferGeometry';
+		super();
+		this.type = 'SphereBufferGeometry';
 
-	this.parameters = {
-		radius: radius,
-		widthSegments: widthSegments,
-		heightSegments: heightSegments,
-		phiStart: phiStart,
-		phiLength: phiLength,
-		thetaStart: thetaStart,
-		thetaLength: thetaLength
-	};
+		this.parameters = {
+			radius: radius,
+			widthSegments: widthSegments,
+			heightSegments: heightSegments,
+			phiStart: phiStart,
+			phiLength: phiLength,
+			thetaStart: thetaStart,
+			thetaLength: thetaLength
+		};
 
-	radius = radius || 1;
+		radius = radius || 1;
 
-	widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
-	heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );
+		widthSegments = Math.max( 3, Math.floor( widthSegments ) || 8 );
+		heightSegments = Math.max( 2, Math.floor( heightSegments ) || 6 );
 
-	phiStart = phiStart !== undefined ? phiStart : 0;
-	phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
+		phiStart = phiStart !== undefined ? phiStart : 0;
+		phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
 
-	thetaStart = thetaStart !== undefined ? thetaStart : 0;
-	thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
+		thetaStart = thetaStart !== undefined ? thetaStart : 0;
+		thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
 
-	const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
+		const thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );
 
-	let index = 0;
-	const grid = [];
+		let index = 0;
+		const grid = [];
 
-	const vertex = new Vector3();
-	const normal = new Vector3();
+		const vertex = new Vector3();
+		const normal = new Vector3();
 
-	// buffers
+		// buffers
 
-	const indices = [];
-	const vertices = [];
-	const normals = [];
-	const uvs = [];
+		const indices = [];
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
 
-	// generate vertices, normals and uvs
+		// generate vertices, normals and uvs
 
-	for ( let iy = 0; iy <= heightSegments; iy ++ ) {
+		for ( let iy = 0; iy <= heightSegments; iy ++ ) {
 
-		const verticesRow = [];
+			const verticesRow = [];
 
-		const v = iy / heightSegments;
+			const v = iy / heightSegments;
 
-		// special case for the poles
+			// special case for the poles
 
-		let uOffset = 0;
+			let uOffset = 0;
 
-		if ( iy == 0 && thetaStart == 0 ) {
+			if ( iy == 0 && thetaStart == 0 ) {
 
-			uOffset = 0.5 / widthSegments;
+				uOffset = 0.5 / widthSegments;
 
-		} else if ( iy == heightSegments && thetaEnd == Math.PI ) {
+			} else if ( iy == heightSegments && thetaEnd == Math.PI ) {
 
-			uOffset = - 0.5 / widthSegments;
+				uOffset = - 0.5 / widthSegments;
 
-		}
+			}
 
-		for ( let ix = 0; ix <= widthSegments; ix ++ ) {
+			for ( let ix = 0; ix <= widthSegments; ix ++ ) {
 
-			const u = ix / widthSegments;
+				const u = ix / widthSegments;
 
-			// vertex
+				// vertex
 
-			vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
-			vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
-			vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
+				vertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
+				vertex.y = radius * Math.cos( thetaStart + v * thetaLength );
+				vertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );
 
-			vertices.push( vertex.x, vertex.y, vertex.z );
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			// normal
+				// normal
 
-			normal.copy( vertex ).normalize();
-			normals.push( normal.x, normal.y, normal.z );
+				normal.copy( vertex ).normalize();
+				normals.push( normal.x, normal.y, normal.z );
 
-			// uv
+				// uv
 
-			uvs.push( u + uOffset, 1 - v );
+				uvs.push( u + uOffset, 1 - v );
 
-			verticesRow.push( index ++ );
+				verticesRow.push( index ++ );
 
-		}
+			}
 
-		grid.push( verticesRow );
+			grid.push( verticesRow );
 
-	}
+		}
+
+		// indices
 
-	// indices
+		for ( let iy = 0; iy < heightSegments; iy ++ ) {
 
-	for ( let iy = 0; iy < heightSegments; iy ++ ) {
+			for ( let ix = 0; ix < widthSegments; ix ++ ) {
 
-		for ( let ix = 0; ix < widthSegments; ix ++ ) {
+				const a = grid[ iy ][ ix + 1 ];
+				const b = grid[ iy ][ ix ];
+				const c = grid[ iy + 1 ][ ix ];
+				const d = grid[ iy + 1 ][ ix + 1 ];
 
-			const a = grid[ iy ][ ix + 1 ];
-			const b = grid[ iy ][ ix ];
-			const c = grid[ iy + 1 ][ ix ];
-			const d = grid[ iy + 1 ][ ix + 1 ];
+				if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
+				if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
 
-			if ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );
-			if ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );
+			}
 
 		}
 
-	}
+		// build geometry
 
-	// build geometry
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-	this.setIndex( indices );
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+	}
 
 }
 
-SphereBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-SphereBufferGeometry.prototype.constructor = SphereBufferGeometry;
-
 
 export { SphereGeometry, SphereBufferGeometry };

+ 29 - 27
src/geometries/TetrahedronGeometry.js

@@ -3,50 +3,52 @@ import { PolyhedronBufferGeometry } from './PolyhedronGeometry.js';
 
 // TetrahedronGeometry
 
-function TetrahedronGeometry( radius, detail ) {
+class TetrahedronGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( radius, detail ) {
 
-	this.type = 'TetrahedronGeometry';
+		super();
+		this.type = 'TetrahedronGeometry';
 
-	this.parameters = {
-		radius: radius,
-		detail: detail
-	};
+		this.parameters = {
+			radius: radius,
+			detail: detail
+		};
 
-	this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );
-	this.mergeVertices();
+		this.fromBufferGeometry( new TetrahedronBufferGeometry( radius, detail ) );
+		this.mergeVertices();
+
+	}
 
 }
 
-TetrahedronGeometry.prototype = Object.create( Geometry.prototype );
-TetrahedronGeometry.prototype.constructor = TetrahedronGeometry;
 
 // TetrahedronBufferGeometry
 
-function TetrahedronBufferGeometry( radius, detail ) {
+class TetrahedronBufferGeometry extends PolyhedronBufferGeometry {
 
-	const vertices = [
-		1, 1, 1, 	- 1, - 1, 1, 	- 1, 1, - 1, 	1, - 1, - 1
-	];
+	constructor( radius, detail ) {
 
-	const indices = [
-		2, 1, 0, 	0, 3, 2,	1, 3, 0,	2, 3, 1
-	];
+		const vertices = [
+			1, 1, 1, 	- 1, - 1, 1, 	- 1, 1, - 1, 	1, - 1, - 1
+		];
 
-	PolyhedronBufferGeometry.call( this, vertices, indices, radius, detail );
+		const indices = [
+			2, 1, 0, 	0, 3, 2,	1, 3, 0,	2, 3, 1
+		];
 
-	this.type = 'TetrahedronBufferGeometry';
+		super( vertices, indices, radius, detail );
 
-	this.parameters = {
-		radius: radius,
-		detail: detail
-	};
+		this.type = 'TetrahedronBufferGeometry';
 
-}
+		this.parameters = {
+			radius: radius,
+			detail: detail
+		};
 
-TetrahedronBufferGeometry.prototype = Object.create( PolyhedronBufferGeometry.prototype );
-TetrahedronBufferGeometry.prototype.constructor = TetrahedronBufferGeometry;
+	}
+
+}
 
 
 export { TetrahedronGeometry, TetrahedronBufferGeometry };

+ 32 - 30
src/geometries/TextGeometry.js

@@ -20,60 +20,62 @@ import { ExtrudeBufferGeometry } from './ExtrudeGeometry.js';
 
 // TextGeometry
 
-function TextGeometry( text, parameters ) {
+class TextGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( text, parameters ) {
 
-	this.type = 'TextGeometry';
+		super();
+		this.type = 'TextGeometry';
 
-	this.parameters = {
-		text: text,
-		parameters: parameters
-	};
+		this.parameters = {
+			text: text,
+			parameters: parameters
+		};
 
-	this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) );
-	this.mergeVertices();
+		this.fromBufferGeometry( new TextBufferGeometry( text, parameters ) );
+		this.mergeVertices();
+
+	}
 
 }
 
-TextGeometry.prototype = Object.create( Geometry.prototype );
-TextGeometry.prototype.constructor = TextGeometry;
 
 // TextBufferGeometry
 
-function TextBufferGeometry( text, parameters ) {
+class TextBufferGeometry extends ExtrudeBufferGeometry {
 
-	parameters = parameters || {};
+	constructor( text, parameters ) {
 
-	const font = parameters.font;
+		parameters = parameters || {};
 
-	if ( ! ( font && font.isFont ) ) {
+		const font = parameters.font;
 
-		console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
-		return new Geometry();
+		if ( ! ( font && font.isFont ) ) {
 
-	}
+			console.error( 'THREE.TextGeometry: font parameter is not an instance of THREE.Font.' );
+			return new Geometry();
 
-	const shapes = font.generateShapes( text, parameters.size );
+		}
 
-	// translate parameters to ExtrudeGeometry API
+		const shapes = font.generateShapes( text, parameters.size );
 
-	parameters.depth = parameters.height !== undefined ? parameters.height : 50;
+		// translate parameters to ExtrudeGeometry API
 
-	// defaults
+		parameters.depth = parameters.height !== undefined ? parameters.height : 50;
 
-	if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
-	if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
-	if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
+		// defaults
 
-	ExtrudeBufferGeometry.call( this, shapes, parameters );
+		if ( parameters.bevelThickness === undefined ) parameters.bevelThickness = 10;
+		if ( parameters.bevelSize === undefined ) parameters.bevelSize = 8;
+		if ( parameters.bevelEnabled === undefined ) parameters.bevelEnabled = false;
 
-	this.type = 'TextBufferGeometry';
+		super( shapes, parameters );
 
-}
+		this.type = 'TextBufferGeometry';
 
-TextBufferGeometry.prototype = Object.create( ExtrudeBufferGeometry.prototype );
-TextBufferGeometry.prototype.constructor = TextBufferGeometry;
+	}
+
+}
 
 
 export { TextGeometry, TextBufferGeometry };

+ 78 - 77
src/geometries/TorusGeometry.js

@@ -5,130 +5,131 @@ import { Vector3 } from '../math/Vector3.js';
 
 // TorusGeometry
 
-function TorusGeometry( radius, tube, radialSegments, tubularSegments, arc ) {
+class TorusGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( radius, tube, radialSegments, tubularSegments, arc ) {
 
-	this.type = 'TorusGeometry';
+		super();
+		this.type = 'TorusGeometry';
 
-	this.parameters = {
-		radius: radius,
-		tube: tube,
-		radialSegments: radialSegments,
-		tubularSegments: tubularSegments,
-		arc: arc
-	};
+		this.parameters = {
+			radius: radius,
+			tube: tube,
+			radialSegments: radialSegments,
+			tubularSegments: tubularSegments,
+			arc: arc
+		};
 
-	this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );
-	this.mergeVertices();
+		this.fromBufferGeometry( new TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) );
+		this.mergeVertices();
+
+	}
 
 }
 
-TorusGeometry.prototype = Object.create( Geometry.prototype );
-TorusGeometry.prototype.constructor = TorusGeometry;
 
 // TorusBufferGeometry
 
-function TorusBufferGeometry( radius, tube, radialSegments, tubularSegments, arc ) {
+class TorusBufferGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( radius, tube, radialSegments, tubularSegments, arc ) {
 
-	this.type = 'TorusBufferGeometry';
+		super();
+		this.type = 'TorusBufferGeometry';
 
-	this.parameters = {
-		radius: radius,
-		tube: tube,
-		radialSegments: radialSegments,
-		tubularSegments: tubularSegments,
-		arc: arc
-	};
+		this.parameters = {
+			radius: radius,
+			tube: tube,
+			radialSegments: radialSegments,
+			tubularSegments: tubularSegments,
+			arc: arc
+		};
 
-	radius = radius || 1;
-	tube = tube || 0.4;
-	radialSegments = Math.floor( radialSegments ) || 8;
-	tubularSegments = Math.floor( tubularSegments ) || 6;
-	arc = arc || Math.PI * 2;
+		radius = radius || 1;
+		tube = tube || 0.4;
+		radialSegments = Math.floor( radialSegments ) || 8;
+		tubularSegments = Math.floor( tubularSegments ) || 6;
+		arc = arc || Math.PI * 2;
 
-	// buffers
+		// buffers
 
-	const indices = [];
-	const vertices = [];
-	const normals = [];
-	const uvs = [];
+		const indices = [];
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
 
-	// helper variables
+		// helper variables
 
-	const center = new Vector3();
-	const vertex = new Vector3();
-	const normal = new Vector3();
+		const center = new Vector3();
+		const vertex = new Vector3();
+		const normal = new Vector3();
 
-	// generate vertices, normals and uvs
+		// generate vertices, normals and uvs
 
-	for ( let j = 0; j <= radialSegments; j ++ ) {
+		for ( let j = 0; j <= radialSegments; j ++ ) {
 
-		for ( let i = 0; i <= tubularSegments; i ++ ) {
+			for ( let i = 0; i <= tubularSegments; i ++ ) {
 
-			const u = i / tubularSegments * arc;
-			const v = j / radialSegments * Math.PI * 2;
+				const u = i / tubularSegments * arc;
+				const v = j / radialSegments * Math.PI * 2;
 
-			// vertex
+				// vertex
 
-			vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
-			vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
-			vertex.z = tube * Math.sin( v );
+				vertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );
+				vertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );
+				vertex.z = tube * Math.sin( v );
 
-			vertices.push( vertex.x, vertex.y, vertex.z );
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			// normal
+				// normal
 
-			center.x = radius * Math.cos( u );
-			center.y = radius * Math.sin( u );
-			normal.subVectors( vertex, center ).normalize();
+				center.x = radius * Math.cos( u );
+				center.y = radius * Math.sin( u );
+				normal.subVectors( vertex, center ).normalize();
 
-			normals.push( normal.x, normal.y, normal.z );
+				normals.push( normal.x, normal.y, normal.z );
 
-			// uv
+				// uv
 
-			uvs.push( i / tubularSegments );
-			uvs.push( j / radialSegments );
+				uvs.push( i / tubularSegments );
+				uvs.push( j / radialSegments );
+
+			}
 
 		}
 
-	}
+		// generate indices
 
-	// generate indices
+		for ( let j = 1; j <= radialSegments; j ++ ) {
 
-	for ( let j = 1; j <= radialSegments; j ++ ) {
+			for ( let i = 1; i <= tubularSegments; i ++ ) {
 
-		for ( let i = 1; i <= tubularSegments; i ++ ) {
+				// indices
 
-			// indices
+				const a = ( tubularSegments + 1 ) * j + i - 1;
+				const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
+				const c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
+				const d = ( tubularSegments + 1 ) * j + i;
 
-			const a = ( tubularSegments + 1 ) * j + i - 1;
-			const b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;
-			const c = ( tubularSegments + 1 ) * ( j - 1 ) + i;
-			const d = ( tubularSegments + 1 ) * j + i;
+				// faces
 
-			// faces
+				indices.push( a, b, d );
+				indices.push( b, c, d );
 
-			indices.push( a, b, d );
-			indices.push( b, c, d );
+			}
 
 		}
 
-	}
+		// build geometry
 
-	// build geometry
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-	this.setIndex( indices );
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+	}
 
 }
 
-TorusBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-TorusBufferGeometry.prototype.constructor = TorusBufferGeometry;
-
 
 export { TorusGeometry, TorusBufferGeometry };

+ 111 - 110
src/geometries/TorusKnotGeometry.js

@@ -5,181 +5,182 @@ import { Vector3 } from '../math/Vector3.js';
 
 // TorusKnotGeometry
 
-function TorusKnotGeometry( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {
+class TorusKnotGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( radius, tube, tubularSegments, radialSegments, p, q, heightScale ) {
 
-	this.type = 'TorusKnotGeometry';
+		super();
+		this.type = 'TorusKnotGeometry';
 
-	this.parameters = {
-		radius: radius,
-		tube: tube,
-		tubularSegments: tubularSegments,
-		radialSegments: radialSegments,
-		p: p,
-		q: q
-	};
+		this.parameters = {
+			radius: radius,
+			tube: tube,
+			tubularSegments: tubularSegments,
+			radialSegments: radialSegments,
+			p: p,
+			q: q
+		};
 
-	if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );
+		if ( heightScale !== undefined ) console.warn( 'THREE.TorusKnotGeometry: heightScale has been deprecated. Use .scale( x, y, z ) instead.' );
 
-	this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );
-	this.mergeVertices();
+		this.fromBufferGeometry( new TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) );
+		this.mergeVertices();
+
+	}
 
 }
 
-TorusKnotGeometry.prototype = Object.create( Geometry.prototype );
-TorusKnotGeometry.prototype.constructor = TorusKnotGeometry;
 
 // TorusKnotBufferGeometry
 
-function TorusKnotBufferGeometry( radius, tube, tubularSegments, radialSegments, p, q ) {
+class TorusKnotBufferGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( radius, tube, tubularSegments, radialSegments, p, q ) {
 
-	this.type = 'TorusKnotBufferGeometry';
+		super();
+		this.type = 'TorusKnotBufferGeometry';
 
-	this.parameters = {
-		radius: radius,
-		tube: tube,
-		tubularSegments: tubularSegments,
-		radialSegments: radialSegments,
-		p: p,
-		q: q
-	};
+		this.parameters = {
+			radius: radius,
+			tube: tube,
+			tubularSegments: tubularSegments,
+			radialSegments: radialSegments,
+			p: p,
+			q: q
+		};
 
-	radius = radius || 1;
-	tube = tube || 0.4;
-	tubularSegments = Math.floor( tubularSegments ) || 64;
-	radialSegments = Math.floor( radialSegments ) || 8;
-	p = p || 2;
-	q = q || 3;
+		radius = radius || 1;
+		tube = tube || 0.4;
+		tubularSegments = Math.floor( tubularSegments ) || 64;
+		radialSegments = Math.floor( radialSegments ) || 8;
+		p = p || 2;
+		q = q || 3;
 
-	// buffers
+		// buffers
 
-	const indices = [];
-	const vertices = [];
-	const normals = [];
-	const uvs = [];
+		const indices = [];
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
 
-	// helper variables
+		// helper variables
 
-	const vertex = new Vector3();
-	const normal = new Vector3();
+		const vertex = new Vector3();
+		const normal = new Vector3();
 
-	const P1 = new Vector3();
-	const P2 = new Vector3();
+		const P1 = new Vector3();
+		const P2 = new Vector3();
 
-	const B = new Vector3();
-	const T = new Vector3();
-	const N = new Vector3();
+		const B = new Vector3();
+		const T = new Vector3();
+		const N = new Vector3();
 
-	// generate vertices, normals and uvs
+		// generate vertices, normals and uvs
 
-	for ( let i = 0; i <= tubularSegments; ++ i ) {
+		for ( let i = 0; i <= tubularSegments; ++ i ) {
 
-		// the radian "u" is used to calculate the position on the torus curve of the current tubular segement
+			// the radian "u" is used to calculate the position on the torus curve of the current tubular segement
 
-		const u = i / tubularSegments * p * Math.PI * 2;
+			const u = i / tubularSegments * p * Math.PI * 2;
 
-		// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
-		// these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
+			// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.
+			// these points are used to create a special "coordinate space", which is necessary to calculate the correct vertex positions
 
-		calculatePositionOnCurve( u, p, q, radius, P1 );
-		calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
+			calculatePositionOnCurve( u, p, q, radius, P1 );
+			calculatePositionOnCurve( u + 0.01, p, q, radius, P2 );
 
-		// calculate orthonormal basis
+			// calculate orthonormal basis
 
-		T.subVectors( P2, P1 );
-		N.addVectors( P2, P1 );
-		B.crossVectors( T, N );
-		N.crossVectors( B, T );
+			T.subVectors( P2, P1 );
+			N.addVectors( P2, P1 );
+			B.crossVectors( T, N );
+			N.crossVectors( B, T );
 
-		// normalize B, N. T can be ignored, we don't use it
+			// normalize B, N. T can be ignored, we don't use it
 
-		B.normalize();
-		N.normalize();
+			B.normalize();
+			N.normalize();
 
-		for ( let j = 0; j <= radialSegments; ++ j ) {
+			for ( let j = 0; j <= radialSegments; ++ j ) {
 
-			// now calculate the vertices. they are nothing more than an extrusion of the torus curve.
-			// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
+				// now calculate the vertices. they are nothing more than an extrusion of the torus curve.
+				// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.
 
-			const v = j / radialSegments * Math.PI * 2;
-			const cx = - tube * Math.cos( v );
-			const cy = tube * Math.sin( v );
+				const v = j / radialSegments * Math.PI * 2;
+				const cx = - tube * Math.cos( v );
+				const cy = tube * Math.sin( v );
 
-			// now calculate the final vertex position.
-			// first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
+				// now calculate the final vertex position.
+				// first we orient the extrusion with our basis vectos, then we add it to the current position on the curve
 
-			vertex.x = P1.x + ( cx * N.x + cy * B.x );
-			vertex.y = P1.y + ( cx * N.y + cy * B.y );
-			vertex.z = P1.z + ( cx * N.z + cy * B.z );
+				vertex.x = P1.x + ( cx * N.x + cy * B.x );
+				vertex.y = P1.y + ( cx * N.y + cy * B.y );
+				vertex.z = P1.z + ( cx * N.z + cy * B.z );
 
-			vertices.push( vertex.x, vertex.y, vertex.z );
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
+				// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)
 
-			normal.subVectors( vertex, P1 ).normalize();
+				normal.subVectors( vertex, P1 ).normalize();
 
-			normals.push( normal.x, normal.y, normal.z );
+				normals.push( normal.x, normal.y, normal.z );
 
-			// uv
+				// uv
 
-			uvs.push( i / tubularSegments );
-			uvs.push( j / radialSegments );
+				uvs.push( i / tubularSegments );
+				uvs.push( j / radialSegments );
+
+			}
 
 		}
 
-	}
+		// generate indices
 
-	// generate indices
+		for ( let j = 1; j <= tubularSegments; j ++ ) {
 
-	for ( let j = 1; j <= tubularSegments; j ++ ) {
+			for ( let i = 1; i <= radialSegments; i ++ ) {
 
-		for ( let i = 1; i <= radialSegments; i ++ ) {
+				// indices
 
-			// indices
+				const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
+				const b = ( radialSegments + 1 ) * j + ( i - 1 );
+				const c = ( radialSegments + 1 ) * j + i;
+				const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
 
-			const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
-			const b = ( radialSegments + 1 ) * j + ( i - 1 );
-			const c = ( radialSegments + 1 ) * j + i;
-			const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
+				// faces
 
-			// faces
+				indices.push( a, b, d );
+				indices.push( b, c, d );
 
-			indices.push( a, b, d );
-			indices.push( b, c, d );
+			}
 
 		}
 
-	}
+		// build geometry
 
-	// build geometry
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-	this.setIndex( indices );
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+		// this function calculates the current position on the torus curve
 
-	// this function calculates the current position on the torus curve
+		function calculatePositionOnCurve( u, p, q, radius, position ) {
 
-	function calculatePositionOnCurve( u, p, q, radius, position ) {
+			const cu = Math.cos( u );
+			const su = Math.sin( u );
+			const quOverP = q / p * u;
+			const cs = Math.cos( quOverP );
 
-		const cu = Math.cos( u );
-		const su = Math.sin( u );
-		const quOverP = q / p * u;
-		const cs = Math.cos( quOverP );
+			position.x = radius * ( 2 + cs ) * 0.5 * cu;
+			position.y = radius * ( 2 + cs ) * su * 0.5;
+			position.z = radius * Math.sin( quOverP ) * 0.5;
 
-		position.x = radius * ( 2 + cs ) * 0.5 * cu;
-		position.y = radius * ( 2 + cs ) * su * 0.5;
-		position.z = radius * Math.sin( quOverP ) * 0.5;
+		}
 
 	}
 
 }
 
-TorusKnotBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-TorusKnotBufferGeometry.prototype.constructor = TorusKnotBufferGeometry;
-
 
 export { TorusKnotGeometry, TorusKnotBufferGeometry };

+ 123 - 122
src/geometries/TubeGeometry.js

@@ -6,215 +6,216 @@ import { Vector3 } from '../math/Vector3.js';
 
 // TubeGeometry
 
-function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) {
+class TubeGeometry extends Geometry {
 
-	Geometry.call( this );
+	constructor( path, tubularSegments, radius, radialSegments, closed, taper ) {
 
-	this.type = 'TubeGeometry';
+		super();
+		this.type = 'TubeGeometry';
 
-	this.parameters = {
-		path: path,
-		tubularSegments: tubularSegments,
-		radius: radius,
-		radialSegments: radialSegments,
-		closed: closed
-	};
+		this.parameters = {
+			path: path,
+			tubularSegments: tubularSegments,
+			radius: radius,
+			radialSegments: radialSegments,
+			closed: closed
+		};
 
-	if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );
+		if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );
 
-	const bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );
+		const bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );
 
-	// expose internals
+		// expose internals
 
-	this.tangents = bufferGeometry.tangents;
-	this.normals = bufferGeometry.normals;
-	this.binormals = bufferGeometry.binormals;
+		this.tangents = bufferGeometry.tangents;
+		this.normals = bufferGeometry.normals;
+		this.binormals = bufferGeometry.binormals;
 
-	// create geometry
+		// create geometry
 
-	this.fromBufferGeometry( bufferGeometry );
-	this.mergeVertices();
+		this.fromBufferGeometry( bufferGeometry );
+		this.mergeVertices();
+
+	}
 
 }
 
-TubeGeometry.prototype = Object.create( Geometry.prototype );
-TubeGeometry.prototype.constructor = TubeGeometry;
 
 // TubeBufferGeometry
 
-function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) {
+class TubeBufferGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( path, tubularSegments, radius, radialSegments, closed ) {
 
-	this.type = 'TubeBufferGeometry';
+		super();
+		this.type = 'TubeBufferGeometry';
 
-	this.parameters = {
-		path: path,
-		tubularSegments: tubularSegments,
-		radius: radius,
-		radialSegments: radialSegments,
-		closed: closed
-	};
+		this.parameters = {
+			path: path,
+			tubularSegments: tubularSegments,
+			radius: radius,
+			radialSegments: radialSegments,
+			closed: closed
+		};
 
-	tubularSegments = tubularSegments || 64;
-	radius = radius || 1;
-	radialSegments = radialSegments || 8;
-	closed = closed || false;
+		tubularSegments = tubularSegments || 64;
+		radius = radius || 1;
+		radialSegments = radialSegments || 8;
+		closed = closed || false;
 
-	const frames = path.computeFrenetFrames( tubularSegments, closed );
+		const frames = path.computeFrenetFrames( tubularSegments, closed );
 
-	// expose internals
+		// expose internals
 
-	this.tangents = frames.tangents;
-	this.normals = frames.normals;
-	this.binormals = frames.binormals;
+		this.tangents = frames.tangents;
+		this.normals = frames.normals;
+		this.binormals = frames.binormals;
 
-	// helper variables
+		// helper variables
 
-	const vertex = new Vector3();
-	const normal = new Vector3();
-	const uv = new Vector2();
-	let P = new Vector3();
+		const vertex = new Vector3();
+		const normal = new Vector3();
+		const uv = new Vector2();
+		let P = new Vector3();
 
-	// buffer
+		// buffer
 
-	const vertices = [];
-	const normals = [];
-	const uvs = [];
-	const indices = [];
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
+		const indices = [];
 
-	// create buffer data
+		// create buffer data
 
-	generateBufferData();
+		generateBufferData();
 
-	// build geometry
+		// build geometry
 
-	this.setIndex( indices );
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+		this.setIndex( indices );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-	// functions
+		// functions
 
-	function generateBufferData() {
+		function generateBufferData() {
 
-		for ( let i = 0; i < tubularSegments; i ++ ) {
+			for ( let i = 0; i < tubularSegments; i ++ ) {
 
-			generateSegment( i );
+				generateSegment( i );
 
-		}
+			}
 
-		// if the geometry is not closed, generate the last row of vertices and normals
-		// at the regular position on the given path
-		//
-		// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
+			// if the geometry is not closed, generate the last row of vertices and normals
+			// at the regular position on the given path
+			//
+			// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
 
-		generateSegment( ( closed === false ) ? tubularSegments : 0 );
+			generateSegment( ( closed === false ) ? tubularSegments : 0 );
 
-		// uvs are generated in a separate function.
-		// this makes it easy compute correct values for closed geometries
+			// uvs are generated in a separate function.
+			// this makes it easy compute correct values for closed geometries
 
-		generateUVs();
+			generateUVs();
 
-		// finally create faces
+			// finally create faces
 
-		generateIndices();
+			generateIndices();
 
-	}
+		}
 
-	function generateSegment( i ) {
+		function generateSegment( i ) {
 
-		// we use getPointAt to sample evenly distributed points from the given path
+			// we use getPointAt to sample evenly distributed points from the given path
 
-		P = path.getPointAt( i / tubularSegments, P );
+			P = path.getPointAt( i / tubularSegments, P );
 
-		// retrieve corresponding normal and binormal
+			// retrieve corresponding normal and binormal
 
-		const N = frames.normals[ i ];
-		const B = frames.binormals[ i ];
+			const N = frames.normals[ i ];
+			const B = frames.binormals[ i ];
 
-		// generate normals and vertices for the current segment
+			// generate normals and vertices for the current segment
+
+			for ( let j = 0; j <= radialSegments; j ++ ) {
 
-		for ( let j = 0; j <= radialSegments; j ++ ) {
+				const v = j / radialSegments * Math.PI * 2;
 
-			const v = j / radialSegments * Math.PI * 2;
+				const sin = Math.sin( v );
+				const cos = - Math.cos( v );
 
-			const sin = Math.sin( v );
-			const cos = - Math.cos( v );
+				// normal
 
-			// normal
+				normal.x = ( cos * N.x + sin * B.x );
+				normal.y = ( cos * N.y + sin * B.y );
+				normal.z = ( cos * N.z + sin * B.z );
+				normal.normalize();
 
-			normal.x = ( cos * N.x + sin * B.x );
-			normal.y = ( cos * N.y + sin * B.y );
-			normal.z = ( cos * N.z + sin * B.z );
-			normal.normalize();
+				normals.push( normal.x, normal.y, normal.z );
 
-			normals.push( normal.x, normal.y, normal.z );
+				// vertex
 
-			// vertex
+				vertex.x = P.x + radius * normal.x;
+				vertex.y = P.y + radius * normal.y;
+				vertex.z = P.z + radius * normal.z;
 
-			vertex.x = P.x + radius * normal.x;
-			vertex.y = P.y + radius * normal.y;
-			vertex.z = P.z + radius * normal.z;
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			vertices.push( vertex.x, vertex.y, vertex.z );
+			}
 
 		}
 
-	}
+		function generateIndices() {
 
-	function generateIndices() {
+			for ( let j = 1; j <= tubularSegments; j ++ ) {
 
-		for ( let j = 1; j <= tubularSegments; j ++ ) {
+				for ( let i = 1; i <= radialSegments; i ++ ) {
 
-			for ( let i = 1; i <= radialSegments; i ++ ) {
+					const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
+					const b = ( radialSegments + 1 ) * j + ( i - 1 );
+					const c = ( radialSegments + 1 ) * j + i;
+					const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
 
-				const a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
-				const b = ( radialSegments + 1 ) * j + ( i - 1 );
-				const c = ( radialSegments + 1 ) * j + i;
-				const d = ( radialSegments + 1 ) * ( j - 1 ) + i;
+					// faces
 
-				// faces
+					indices.push( a, b, d );
+					indices.push( b, c, d );
 
-				indices.push( a, b, d );
-				indices.push( b, c, d );
+				}
 
 			}
 
 		}
 
-	}
+		function generateUVs() {
 
-	function generateUVs() {
+			for ( let i = 0; i <= tubularSegments; i ++ ) {
 
-		for ( let i = 0; i <= tubularSegments; i ++ ) {
+				for ( let j = 0; j <= radialSegments; j ++ ) {
 
-			for ( let j = 0; j <= radialSegments; j ++ ) {
+					uv.x = i / tubularSegments;
+					uv.y = j / radialSegments;
 
-				uv.x = i / tubularSegments;
-				uv.y = j / radialSegments;
+					uvs.push( uv.x, uv.y );
 
-				uvs.push( uv.x, uv.y );
+				}
 
 			}
 
 		}
 
 	}
+	toJSON() {
 
-}
-
-TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
-TubeBufferGeometry.prototype.constructor = TubeBufferGeometry;
+		const data = BufferGeometry.prototype.toJSON.call( this );
 
-TubeBufferGeometry.prototype.toJSON = function () {
+		data.path = this.parameters.path.toJSON();
 
-	const data = BufferGeometry.prototype.toJSON.call( this );
+		return data;
 
-	data.path = this.parameters.path.toJSON();
+	}
 
-	return data;
+}
 
-};
 
 export { TubeGeometry, TubeBufferGeometry };

+ 83 - 83
src/geometries/WireframeGeometry.js

@@ -2,107 +2,110 @@ import { BufferGeometry } from '../core/BufferGeometry.js';
 import { Float32BufferAttribute } from '../core/BufferAttribute.js';
 import { Vector3 } from '../math/Vector3.js';
 
-function WireframeGeometry( geometry ) {
+class WireframeGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( geometry ) {
 
-	this.type = 'WireframeGeometry';
+		super();
+		this.type = 'WireframeGeometry';
 
-	// buffer
+		// buffer
 
-	const vertices = [];
+		const vertices = [];
 
-	// helper variables
+		// helper variables
 
-	const edge = [ 0, 0 ], edges = {};
-	const keys = [ 'a', 'b', 'c' ];
+		const edge = [ 0, 0 ], edges = {};
+		const keys = [ 'a', 'b', 'c' ];
 
-	// different logic for Geometry and BufferGeometry
+		// different logic for Geometry and BufferGeometry
 
-	if ( geometry && geometry.isGeometry ) {
+		if ( geometry && geometry.isGeometry ) {
 
-		// create a data structure that contains all edges without duplicates
+			// create a data structure that contains all edges without duplicates
 
-		const faces = geometry.faces;
+			const faces = geometry.faces;
 
-		for ( let i = 0, l = faces.length; i < l; i ++ ) {
+			for ( let i = 0, l = faces.length; i < l; i ++ ) {
 
-			const face = faces[ i ];
+				const face = faces[ i ];
 
-			for ( let j = 0; j < 3; j ++ ) {
+				for ( let j = 0; j < 3; j ++ ) {
+
+					const edge1 = face[ keys[ j ] ];
+					const edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
+					edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
+					edge[ 1 ] = Math.max( edge1, edge2 );
 
-				const edge1 = face[ keys[ j ] ];
-				const edge2 = face[ keys[ ( j + 1 ) % 3 ] ];
-				edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
-				edge[ 1 ] = Math.max( edge1, edge2 );
+					const key = edge[ 0 ] + ',' + edge[ 1 ];
 
-				const key = edge[ 0 ] + ',' + edge[ 1 ];
+					if ( edges[ key ] === undefined ) {
 
-				if ( edges[ key ] === undefined ) {
+						edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
 
-					edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
+					}
 
 				}
 
 			}
 
-		}
+			// generate vertices
 
-		// generate vertices
+			for ( const key in edges ) {
 
-		for ( const key in edges ) {
+				const e = edges[ key ];
 
-			const e = edges[ key ];
+				let vertex = geometry.vertices[ e.index1 ];
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			let vertex = geometry.vertices[ e.index1 ];
-			vertices.push( vertex.x, vertex.y, vertex.z );
+				vertex = geometry.vertices[ e.index2 ];
+				vertices.push( vertex.x, vertex.y, vertex.z );
 
-			vertex = geometry.vertices[ e.index2 ];
-			vertices.push( vertex.x, vertex.y, vertex.z );
+			}
 
-		}
+		} else if ( geometry && geometry.isBufferGeometry ) {
 
-	} else if ( geometry && geometry.isBufferGeometry ) {
+			const vertex = new Vector3();
 
-		let vertex = new Vector3();
+			if ( geometry.index !== null ) {
 
-		if ( geometry.index !== null ) {
+				// indexed BufferGeometry
 
-			// indexed BufferGeometry
+				const position = geometry.attributes.position;
+				const indices = geometry.index;
+				let groups = geometry.groups;
 
-			const position = geometry.attributes.position;
-			const indices = geometry.index;
-			let groups = geometry.groups;
+				if ( groups.length === 0 ) {
 
-			if ( groups.length === 0 ) {
+					groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
 
-				groups = [ { start: 0, count: indices.count, materialIndex: 0 } ];
+				}
 
-			}
+				// create a data structure that contains all eges without duplicates
 
-			// create a data structure that contains all eges without duplicates
+				for ( let o = 0, ol = groups.length; o < ol; ++ o ) {
 
-			for ( let o = 0, ol = groups.length; o < ol; ++ o ) {
+					const group = groups[ o ];
 
-				const group = groups[ o ];
+					const start = group.start;
+					const count = group.count;
 
-				const start = group.start;
-				const count = group.count;
+					for ( let i = start, l = ( start + count ); i < l; i += 3 ) {
 
-				for ( let i = start, l = ( start + count ); i < l; i += 3 ) {
+						for ( let j = 0; j < 3; j ++ ) {
 
-					for ( let j = 0; j < 3; j ++ ) {
+							const edge1 = indices.getX( i + j );
+							const edge2 = indices.getX( i + ( j + 1 ) % 3 );
+							edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
+							edge[ 1 ] = Math.max( edge1, edge2 );
 
-						const edge1 = indices.getX( i + j );
-						const edge2 = indices.getX( i + ( j + 1 ) % 3 );
-						edge[ 0 ] = Math.min( edge1, edge2 ); // sorting prevents duplicates
-						edge[ 1 ] = Math.max( edge1, edge2 );
+							const key = edge[ 0 ] + ',' + edge[ 1 ];
 
-						const key = edge[ 0 ] + ',' + edge[ 1 ];
+							if ( edges[ key ] === undefined ) {
 
-						if ( edges[ key ] === undefined ) {
+								edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
 
-							edges[ key ] = { index1: edge[ 0 ], index2: edge[ 1 ] };
+							}
 
 						}
 
@@ -110,42 +113,42 @@ function WireframeGeometry( geometry ) {
 
 				}
 
-			}
+				// generate vertices
 
-			// generate vertices
+				for ( const key in edges ) {
 
-			for ( const key in edges ) {
+					const e = edges[ key ];
 
-				const e = edges[ key ];
+					vertex.fromBufferAttribute( position, e.index1 );
+					vertices.push( vertex.x, vertex.y, vertex.z );
 
-				vertex.fromBufferAttribute( position, e.index1 );
-				vertices.push( vertex.x, vertex.y, vertex.z );
+					vertex.fromBufferAttribute( position, e.index2 );
+					vertices.push( vertex.x, vertex.y, vertex.z );
 
-				vertex.fromBufferAttribute( position, e.index2 );
-				vertices.push( vertex.x, vertex.y, vertex.z );
+				}
 
-			}
+			} else {
 
-		} else {
+				// non-indexed BufferGeometry
 
-			// non-indexed BufferGeometry
+				const position = geometry.attributes.position;
 
-			const position = geometry.attributes.position;
+				for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
 
-			for ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {
+					for ( let j = 0; j < 3; j ++ ) {
 
-				for ( let j = 0; j < 3; j ++ ) {
+						// three edges per triangle, an edge is represented as (index1, index2)
+						// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
 
-					// three edges per triangle, an edge is represented as (index1, index2)
-					// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)
+						const index1 = 3 * i + j;
+						vertex.fromBufferAttribute( position, index1 );
+						vertices.push( vertex.x, vertex.y, vertex.z );
 
-					const index1 = 3 * i + j;
-					vertex.fromBufferAttribute( position, index1 );
-					vertices.push( vertex.x, vertex.y, vertex.z );
+						const index2 = 3 * i + ( ( j + 1 ) % 3 );
+						vertex.fromBufferAttribute( position, index2 );
+						vertices.push( vertex.x, vertex.y, vertex.z );
 
-					const index2 = 3 * i + ( ( j + 1 ) % 3 );
-					vertex.fromBufferAttribute( position, index2 );
-					vertices.push( vertex.x, vertex.y, vertex.z );
+					}
 
 				}
 
@@ -153,16 +156,13 @@ function WireframeGeometry( geometry ) {
 
 		}
 
-	}
+		// build geometry
 
-	// build geometry
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+	}
 
 }
 
-WireframeGeometry.prototype = Object.create( BufferGeometry.prototype );
-WireframeGeometry.prototype.constructor = WireframeGeometry;
-
 
 export { WireframeGeometry };

+ 59 - 58
src/helpers/ArrowHelper.js

@@ -11,103 +11,104 @@ import { Vector3 } from '../math/Vector3.js';
 const _axis = new Vector3();
 let _lineGeometry, _coneGeometry;
 
-function ArrowHelper( dir, origin, length, color, headLength, headWidth ) {
+class ArrowHelper extends Object3D {
 
-	// dir is assumed to be normalized
+	constructor( dir, origin, length, color, headLength, headWidth ) {
 
-	Object3D.call( this );
+		super();
+		// dir is assumed to be normalized
 
-	this.type = 'ArrowHelper';
+		this.type = 'ArrowHelper';
 
-	if ( dir === undefined ) dir = new Vector3( 0, 0, 1 );
-	if ( origin === undefined ) origin = new Vector3( 0, 0, 0 );
-	if ( length === undefined ) length = 1;
-	if ( color === undefined ) color = 0xffff00;
-	if ( headLength === undefined ) headLength = 0.2 * length;
-	if ( headWidth === undefined ) headWidth = 0.2 * headLength;
+		if ( dir === undefined ) dir = new Vector3( 0, 0, 1 );
+		if ( origin === undefined ) origin = new Vector3( 0, 0, 0 );
+		if ( length === undefined ) length = 1;
+		if ( color === undefined ) color = 0xffff00;
+		if ( headLength === undefined ) headLength = 0.2 * length;
+		if ( headWidth === undefined ) headWidth = 0.2 * headLength;
 
-	if ( _lineGeometry === undefined ) {
+		if ( _lineGeometry === undefined ) {
 
-		_lineGeometry = new BufferGeometry();
-		_lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
+			_lineGeometry = new BufferGeometry();
+			_lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );
 
-		_coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
-		_coneGeometry.translate( 0, - 0.5, 0 );
+			_coneGeometry = new CylinderBufferGeometry( 0, 0.5, 1, 5, 1 );
+			_coneGeometry.translate( 0, - 0.5, 0 );
 
-	}
+		}
 
-	this.position.copy( origin );
+		this.position.copy( origin );
 
-	this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
-	this.line.matrixAutoUpdate = false;
-	this.add( this.line );
+		this.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
+		this.line.matrixAutoUpdate = false;
+		this.add( this.line );
 
-	this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) );
-	this.cone.matrixAutoUpdate = false;
-	this.add( this.cone );
+		this.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) );
+		this.cone.matrixAutoUpdate = false;
+		this.add( this.cone );
 
-	this.setDirection( dir );
-	this.setLength( length, headLength, headWidth );
+		this.setDirection( dir );
+		this.setLength( length, headLength, headWidth );
 
-}
+	}
 
-ArrowHelper.prototype = Object.create( Object3D.prototype );
-ArrowHelper.prototype.constructor = ArrowHelper;
+	setDirection( dir ) {
 
-ArrowHelper.prototype.setDirection = function ( dir ) {
+		// dir is assumed to be normalized
 
-	// dir is assumed to be normalized
+		if ( dir.y > 0.99999 ) {
 
-	if ( dir.y > 0.99999 ) {
+			this.quaternion.set( 0, 0, 0, 1 );
 
-		this.quaternion.set( 0, 0, 0, 1 );
+		} else if ( dir.y < - 0.99999 ) {
 
-	} else if ( dir.y < - 0.99999 ) {
+			this.quaternion.set( 1, 0, 0, 0 );
 
-		this.quaternion.set( 1, 0, 0, 0 );
+		} else {
 
-	} else {
+			_axis.set( dir.z, 0, - dir.x ).normalize();
 
-		_axis.set( dir.z, 0, - dir.x ).normalize();
+			const radians = Math.acos( dir.y );
 
-		const radians = Math.acos( dir.y );
+			this.quaternion.setFromAxisAngle( _axis, radians );
 
-		this.quaternion.setFromAxisAngle( _axis, radians );
+		}
 
 	}
 
-};
+	setLength( length, headLength, headWidth ) {
+
+		if ( headLength === undefined ) headLength = 0.2 * length;
+		if ( headWidth === undefined ) headWidth = 0.2 * headLength;
 
-ArrowHelper.prototype.setLength = function ( length, headLength, headWidth ) {
+		this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
+		this.line.updateMatrix();
 
-	if ( headLength === undefined ) headLength = 0.2 * length;
-	if ( headWidth === undefined ) headWidth = 0.2 * headLength;
+		this.cone.scale.set( headWidth, headLength, headWidth );
+		this.cone.position.y = length;
+		this.cone.updateMatrix();
 
-	this.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458
-	this.line.updateMatrix();
+	}
 
-	this.cone.scale.set( headWidth, headLength, headWidth );
-	this.cone.position.y = length;
-	this.cone.updateMatrix();
+	setColor( color ) {
 
-};
+		this.line.material.color.set( color );
+		this.cone.material.color.set( color );
 
-ArrowHelper.prototype.setColor = function ( color ) {
+	}
 
-	this.line.material.color.set( color );
-	this.cone.material.color.set( color );
+	copy( source ) {
 
-};
+		super.copy( source, false );
 
-ArrowHelper.prototype.copy = function ( source ) {
+		this.line.copy( source.line );
+		this.cone.copy( source.cone );
 
-	Object3D.prototype.copy.call( this, source, false );
+		return this;
 
-	this.line.copy( source.line );
-	this.cone.copy( source.cone );
+	}
 
-	return this;
+}
 
-};
 
 export { ArrowHelper };

+ 22 - 21
src/helpers/AxesHelper.js

@@ -3,36 +3,37 @@ import { LineBasicMaterial } from '../materials/LineBasicMaterial.js';
 import { Float32BufferAttribute } from '../core/BufferAttribute.js';
 import { BufferGeometry } from '../core/BufferGeometry.js';
 
-function AxesHelper( size ) {
+class AxesHelper extends LineSegments {
 
-	size = size || 1;
+	constructor( size ) {
 
-	const vertices = [
-		0, 0, 0,	size, 0, 0,
-		0, 0, 0,	0, size, 0,
-		0, 0, 0,	0, 0, size
-	];
+		size = size || 1;
 
-	const colors = [
-		1, 0, 0,	1, 0.6, 0,
-		0, 1, 0,	0.6, 1, 0,
-		0, 0, 1,	0, 0.6, 1
-	];
+		const vertices = [
+			0, 0, 0,	size, 0, 0,
+			0, 0, 0,	0, size, 0,
+			0, 0, 0,	0, 0, size
+		];
 
-	const geometry = new BufferGeometry();
-	geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
+		const colors = [
+			1, 0, 0,	1, 0.6, 0,
+			0, 1, 0,	0.6, 1, 0,
+			0, 0, 1,	0, 0.6, 1
+		];
 
-	const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
+		const geometry = new BufferGeometry();
+		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
 
-	LineSegments.call( this, geometry, material );
+		const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
 
-	this.type = 'AxesHelper';
+		super( geometry, material );
 
-}
+		this.type = 'AxesHelper';
+
+	}
 
-AxesHelper.prototype = Object.create( LineSegments.prototype );
-AxesHelper.prototype.constructor = AxesHelper;
+}
 
 
 export { AxesHelper };

+ 22 - 24
src/helpers/Box3Helper.js

@@ -3,51 +3,49 @@ import { LineBasicMaterial } from '../materials/LineBasicMaterial.js';
 import { BufferAttribute } from '../core/BufferAttribute.js';
 import { Float32BufferAttribute } from '../core/BufferAttribute.js';
 import { BufferGeometry } from '../core/BufferGeometry.js';
-import { Object3D } from '../core/Object3D.js';
 
-function Box3Helper( box, color ) {
+class Box3Helper extends LineSegments {
 
-	this.type = 'Box3Helper';
+	constructor( box, color ) {
 
-	this.box = box;
+		if ( color === undefined ) color = 0xffff00;
 
-	if ( color === undefined ) color = 0xffff00;
+		const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
 
-	const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
+		const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ];
 
-	const positions = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, - 1, - 1, 1, - 1, - 1, - 1, - 1, 1, - 1, - 1 ];
+		const geometry = new BufferGeometry();
 
-	const geometry = new BufferGeometry();
+		geometry.setIndex( new BufferAttribute( indices, 1 ) );
 
-	geometry.setIndex( new BufferAttribute( indices, 1 ) );
+		geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
 
-	geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
+		super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
 
-	LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
+		this.box = box;
 
-	this.type = 'Box3Helper';
+		this.type = 'Box3Helper';
 
-	this.geometry.computeBoundingSphere();
+		this.geometry.computeBoundingSphere();
 
-}
+	}
 
-Box3Helper.prototype = Object.create( LineSegments.prototype );
-Box3Helper.prototype.constructor = Box3Helper;
+	updateMatrixWorld( force ) {
 
-Box3Helper.prototype.updateMatrixWorld = function ( force ) {
+		const box = this.box;
 
-	const box = this.box;
+		if ( box.isEmpty() ) return;
 
-	if ( box.isEmpty() ) return;
+		box.getCenter( this.position );
 
-	box.getCenter( this.position );
+		box.getSize( this.scale );
 
-	box.getSize( this.scale );
+		this.scale.multiplyScalar( 0.5 );
 
-	this.scale.multiplyScalar( 0.5 );
+		super.updateMatrixWorld( force );
 
-	Object3D.prototype.updateMatrixWorld.call( this, force );
+	}
 
-};
+}
 
 export { Box3Helper };

+ 63 - 62
src/helpers/BoxHelper.js

@@ -6,103 +6,104 @@ import { BufferGeometry } from '../core/BufferGeometry.js';
 
 const _box = new Box3();
 
-function BoxHelper( object, color ) {
+class BoxHelper extends LineSegments {
 
-	this.object = object;
+	constructor( object, color ) {
 
-	if ( color === undefined ) color = 0xffff00;
+		if ( color === undefined ) color = 0xffff00;
 
-	const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
-	const positions = new Float32Array( 8 * 3 );
+		const indices = new Uint16Array( [ 0, 1, 1, 2, 2, 3, 3, 0, 4, 5, 5, 6, 6, 7, 7, 4, 0, 4, 1, 5, 2, 6, 3, 7 ] );
+		const positions = new Float32Array( 8 * 3 );
 
-	const geometry = new BufferGeometry();
-	geometry.setIndex( new BufferAttribute( indices, 1 ) );
-	geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
+		const geometry = new BufferGeometry();
+		geometry.setIndex( new BufferAttribute( indices, 1 ) );
+		geometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );
 
-	LineSegments.call( this, geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
+		super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
 
-	this.type = 'BoxHelper';
+		this.object = object;
+		this.type = 'BoxHelper';
 
-	this.matrixAutoUpdate = false;
+		this.matrixAutoUpdate = false;
 
-	this.update();
+		this.update();
 
-}
+	}
 
-BoxHelper.prototype = Object.create( LineSegments.prototype );
-BoxHelper.prototype.constructor = BoxHelper;
+	update( object ) {
 
-BoxHelper.prototype.update = function ( object ) {
+		if ( object !== undefined ) {
 
-	if ( object !== undefined ) {
+			console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );
 
-		console.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );
+		}
 
-	}
+		if ( this.object !== undefined ) {
 
-	if ( this.object !== undefined ) {
+			_box.setFromObject( this.object );
 
-		_box.setFromObject( this.object );
+		}
 
-	}
+		if ( _box.isEmpty() ) return;
 
-	if ( _box.isEmpty() ) return;
+		const min = _box.min;
+		const max = _box.max;
 
-	const min = _box.min;
-	const max = _box.max;
+		/*
+			5____4
+		1/___0/|
+		| 6__|_7
+		2/___3/
 
-	/*
-	  5____4
-	1/___0/|
-	| 6__|_7
-	2/___3/
+		0: max.x, max.y, max.z
+		1: min.x, max.y, max.z
+		2: min.x, min.y, max.z
+		3: max.x, min.y, max.z
+		4: max.x, max.y, min.z
+		5: min.x, max.y, min.z
+		6: min.x, min.y, min.z
+		7: max.x, min.y, min.z
+		*/
 
-	0: max.x, max.y, max.z
-	1: min.x, max.y, max.z
-	2: min.x, min.y, max.z
-	3: max.x, min.y, max.z
-	4: max.x, max.y, min.z
-	5: min.x, max.y, min.z
-	6: min.x, min.y, min.z
-	7: max.x, min.y, min.z
-	*/
+		const position = this.geometry.attributes.position;
+		const array = position.array;
 
-	const position = this.geometry.attributes.position;
-	const array = position.array;
+		array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;
+		array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;
+		array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;
+		array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
+		array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
+		array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
+		array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
+		array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
 
-	array[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;
-	array[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;
-	array[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;
-	array[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;
-	array[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;
-	array[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;
-	array[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;
-	array[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;
+		position.needsUpdate = true;
 
-	position.needsUpdate = true;
+		this.geometry.computeBoundingSphere();
 
-	this.geometry.computeBoundingSphere();
 
+	}
 
-};
+	setFromObject( object ) {
 
-BoxHelper.prototype.setFromObject = function ( object ) {
+		this.object = object;
+		this.update();
 
-	this.object = object;
-	this.update();
+		return this;
 
-	return this;
+	}
+
+	copy( source ) {
 
-};
+		LineSegments.prototype.copy.call( this, source );
 
-BoxHelper.prototype.copy = function ( source ) {
+		this.object = source.object;
 
-	LineSegments.prototype.copy.call( this, source );
+		return this;
 
-	this.object = source.object;
+	}
 
-	return this;
+}
 
-};
 
 export { BoxHelper };

+ 106 - 104
src/helpers/CameraHelper.js

@@ -16,167 +16,169 @@ const _camera = new Camera();
  *		http://evanw.github.com/lightgl.js/tests/shadowmap.html
  */
 
-function CameraHelper( camera ) {
+class CameraHelper extends LineSegments {
 
-	const geometry = new BufferGeometry();
-	const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } );
+	constructor( camera ) {
 
-	const vertices = [];
-	const colors = [];
+		const geometry = new BufferGeometry();
+		const material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } );
 
-	const pointMap = {};
+		const vertices = [];
+		const colors = [];
 
-	// colors
+		const pointMap = {};
 
-	const colorFrustum = new Color( 0xffaa00 );
-	const colorCone = new Color( 0xff0000 );
-	const colorUp = new Color( 0x00aaff );
-	const colorTarget = new Color( 0xffffff );
-	const colorCross = new Color( 0x333333 );
+		// colors
 
-	// near
+		const colorFrustum = new Color( 0xffaa00 );
+		const colorCone = new Color( 0xff0000 );
+		const colorUp = new Color( 0x00aaff );
+		const colorTarget = new Color( 0xffffff );
+		const colorCross = new Color( 0x333333 );
 
-	addLine( 'n1', 'n2', colorFrustum );
-	addLine( 'n2', 'n4', colorFrustum );
-	addLine( 'n4', 'n3', colorFrustum );
-	addLine( 'n3', 'n1', colorFrustum );
+		// near
 
-	// far
+		addLine( 'n1', 'n2', colorFrustum );
+		addLine( 'n2', 'n4', colorFrustum );
+		addLine( 'n4', 'n3', colorFrustum );
+		addLine( 'n3', 'n1', colorFrustum );
 
-	addLine( 'f1', 'f2', colorFrustum );
-	addLine( 'f2', 'f4', colorFrustum );
-	addLine( 'f4', 'f3', colorFrustum );
-	addLine( 'f3', 'f1', colorFrustum );
+		// far
 
-	// sides
+		addLine( 'f1', 'f2', colorFrustum );
+		addLine( 'f2', 'f4', colorFrustum );
+		addLine( 'f4', 'f3', colorFrustum );
+		addLine( 'f3', 'f1', colorFrustum );
 
-	addLine( 'n1', 'f1', colorFrustum );
-	addLine( 'n2', 'f2', colorFrustum );
-	addLine( 'n3', 'f3', colorFrustum );
-	addLine( 'n4', 'f4', colorFrustum );
+		// sides
 
-	// cone
+		addLine( 'n1', 'f1', colorFrustum );
+		addLine( 'n2', 'f2', colorFrustum );
+		addLine( 'n3', 'f3', colorFrustum );
+		addLine( 'n4', 'f4', colorFrustum );
 
-	addLine( 'p', 'n1', colorCone );
-	addLine( 'p', 'n2', colorCone );
-	addLine( 'p', 'n3', colorCone );
-	addLine( 'p', 'n4', colorCone );
+		// cone
 
-	// up
+		addLine( 'p', 'n1', colorCone );
+		addLine( 'p', 'n2', colorCone );
+		addLine( 'p', 'n3', colorCone );
+		addLine( 'p', 'n4', colorCone );
 
-	addLine( 'u1', 'u2', colorUp );
-	addLine( 'u2', 'u3', colorUp );
-	addLine( 'u3', 'u1', colorUp );
+		// up
 
-	// target
+		addLine( 'u1', 'u2', colorUp );
+		addLine( 'u2', 'u3', colorUp );
+		addLine( 'u3', 'u1', colorUp );
 
-	addLine( 'c', 't', colorTarget );
-	addLine( 'p', 'c', colorCross );
+		// target
 
-	// cross
+		addLine( 'c', 't', colorTarget );
+		addLine( 'p', 'c', colorCross );
 
-	addLine( 'cn1', 'cn2', colorCross );
-	addLine( 'cn3', 'cn4', colorCross );
+		// cross
 
-	addLine( 'cf1', 'cf2', colorCross );
-	addLine( 'cf3', 'cf4', colorCross );
+		addLine( 'cn1', 'cn2', colorCross );
+		addLine( 'cn3', 'cn4', colorCross );
 
-	function addLine( a, b, color ) {
+		addLine( 'cf1', 'cf2', colorCross );
+		addLine( 'cf3', 'cf4', colorCross );
 
-		addPoint( a, color );
-		addPoint( b, color );
+		function addLine( a, b, color ) {
 
-	}
+			addPoint( a, color );
+			addPoint( b, color );
 
-	function addPoint( id, color ) {
+		}
 
-		vertices.push( 0, 0, 0 );
-		colors.push( color.r, color.g, color.b );
+		function addPoint( id, color ) {
 
-		if ( pointMap[ id ] === undefined ) {
+			vertices.push( 0, 0, 0 );
+			colors.push( color.r, color.g, color.b );
 
-			pointMap[ id ] = [];
+			if ( pointMap[ id ] === undefined ) {
 
-		}
+				pointMap[ id ] = [];
 
-		pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
+			}
 
-	}
+			pointMap[ id ].push( ( vertices.length / 3 ) - 1 );
 
-	geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
+		}
 
-	LineSegments.call( this, geometry, material );
+		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
 
-	this.type = 'CameraHelper';
+		super( geometry, material );
 
-	this.camera = camera;
-	if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
+		this.type = 'CameraHelper';
 
-	this.matrix = camera.matrixWorld;
-	this.matrixAutoUpdate = false;
+		this.camera = camera;
+		if ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();
 
-	this.pointMap = pointMap;
+		this.matrix = camera.matrixWorld;
+		this.matrixAutoUpdate = false;
 
-	this.update();
+		this.pointMap = pointMap;
 
-}
+		this.update();
 
-CameraHelper.prototype = Object.create( LineSegments.prototype );
-CameraHelper.prototype.constructor = CameraHelper;
+	}
+
+	update() {
 
-CameraHelper.prototype.update = function () {
+		const geometry = this.geometry;
+		const pointMap = this.pointMap;
 
-	const geometry = this.geometry;
-	const pointMap = this.pointMap;
+		const w = 1, h = 1;
 
-	const w = 1, h = 1;
+		// we need just camera projection matrix inverse
+		// world matrix must be identity
 
-	// we need just camera projection matrix inverse
-	// world matrix must be identity
+		_camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );
 
-	_camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );
+		// center / target
 
-	// center / target
+		setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 );
+		setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );
 
-	setPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 );
-	setPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );
+		// near
 
-	// near
+		setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 );
+		setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 );
+		setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 );
+		setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 );
 
-	setPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 );
-	setPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 );
-	setPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 );
-	setPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 );
+		// far
 
-	// far
+		setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 );
+		setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 );
+		setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 );
+		setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 );
 
-	setPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 );
-	setPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 );
-	setPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 );
-	setPoint( 'f4', pointMap, geometry, _camera, w, h, 1 );
+		// up
 
-	// up
+		setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 );
+		setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 );
+		setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 );
 
-	setPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 );
-	setPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 );
-	setPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 );
+		// cross
 
-	// cross
+		setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 );
+		setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 );
+		setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 );
+		setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 );
 
-	setPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 );
-	setPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 );
-	setPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 );
-	setPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 );
+		setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 );
+		setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 );
+		setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 );
+		setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 );
 
-	setPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 );
-	setPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 );
-	setPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 );
-	setPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 );
+		geometry.getAttribute( 'position' ).needsUpdate = true;
 
-	geometry.getAttribute( 'position' ).needsUpdate = true;
+	}
+
+}
 
-};
 
 function setPoint( point, pointMap, geometry, camera, x, y, z ) {
 

+ 48 - 48
src/helpers/DirectionalLightHelper.js

@@ -9,80 +9,80 @@ const _v1 = new Vector3();
 const _v2 = new Vector3();
 const _v3 = new Vector3();
 
-function DirectionalLightHelper( light, size, color ) {
+class DirectionalLightHelper extends Object3D {
 
-	Object3D.call( this );
+	constructor( light, size, color ) {
 
-	this.light = light;
-	this.light.updateMatrixWorld();
+		super();
+		this.light = light;
+		this.light.updateMatrixWorld();
 
-	this.matrix = light.matrixWorld;
-	this.matrixAutoUpdate = false;
+		this.matrix = light.matrixWorld;
+		this.matrixAutoUpdate = false;
 
-	this.color = color;
+		this.color = color;
 
-	if ( size === undefined ) size = 1;
+		if ( size === undefined ) size = 1;
 
-	let geometry = new BufferGeometry();
-	geometry.setAttribute( 'position', new Float32BufferAttribute( [
-		- size, size, 0,
-		size, size, 0,
-		size, - size, 0,
-		- size, - size, 0,
-		- size, size, 0
-	], 3 ) );
+		let geometry = new BufferGeometry();
+		geometry.setAttribute( 'position', new Float32BufferAttribute( [
+			- size, size, 0,
+			size, size, 0,
+			size, - size, 0,
+			- size, - size, 0,
+			- size, size, 0
+		], 3 ) );
 
-	const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
+		const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
 
-	this.lightPlane = new Line( geometry, material );
-	this.add( this.lightPlane );
+		this.lightPlane = new Line( geometry, material );
+		this.add( this.lightPlane );
 
-	geometry = new BufferGeometry();
-	geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
+		geometry = new BufferGeometry();
+		geometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );
 
-	this.targetLine = new Line( geometry, material );
-	this.add( this.targetLine );
+		this.targetLine = new Line( geometry, material );
+		this.add( this.targetLine );
 
-	this.update();
+		this.update();
 
-}
+	}
+
+	dispose() {
 
-DirectionalLightHelper.prototype = Object.create( Object3D.prototype );
-DirectionalLightHelper.prototype.constructor = DirectionalLightHelper;
+		this.lightPlane.geometry.dispose();
+		this.lightPlane.material.dispose();
+		this.targetLine.geometry.dispose();
+		this.targetLine.material.dispose();
 
-DirectionalLightHelper.prototype.dispose = function () {
+	}
 
-	this.lightPlane.geometry.dispose();
-	this.lightPlane.material.dispose();
-	this.targetLine.geometry.dispose();
-	this.targetLine.material.dispose();
+	update() {
 
-};
+		_v1.setFromMatrixPosition( this.light.matrixWorld );
+		_v2.setFromMatrixPosition( this.light.target.matrixWorld );
+		_v3.subVectors( _v2, _v1 );
 
-DirectionalLightHelper.prototype.update = function () {
+		this.lightPlane.lookAt( _v2 );
 
-	_v1.setFromMatrixPosition( this.light.matrixWorld );
-	_v2.setFromMatrixPosition( this.light.target.matrixWorld );
-	_v3.subVectors( _v2, _v1 );
+		if ( this.color !== undefined ) {
 
-	this.lightPlane.lookAt( _v2 );
+			this.lightPlane.material.color.set( this.color );
+			this.targetLine.material.color.set( this.color );
 
-	if ( this.color !== undefined ) {
+		} else {
 
-		this.lightPlane.material.color.set( this.color );
-		this.targetLine.material.color.set( this.color );
+			this.lightPlane.material.color.copy( this.light.color );
+			this.targetLine.material.color.copy( this.light.color );
 
-	} else {
+		}
 
-		this.lightPlane.material.color.copy( this.light.color );
-		this.targetLine.material.color.copy( this.light.color );
+		this.targetLine.lookAt( _v2 );
+		this.targetLine.scale.z = _v3.length();
 
 	}
 
-	this.targetLine.lookAt( _v2 );
-	this.targetLine.scale.z = _v3.length();
-
-};
+}
 
 
 export { DirectionalLightHelper };

+ 28 - 26
src/helpers/GridHelper.js

@@ -4,46 +4,48 @@ import { Float32BufferAttribute } from '../core/BufferAttribute.js';
 import { BufferGeometry } from '../core/BufferGeometry.js';
 import { Color } from '../math/Color.js';
 
-function GridHelper( size, divisions, color1, color2 ) {
+class GridHelper extends LineSegments {
 
-	size = size || 10;
-	divisions = divisions || 10;
-	color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
-	color2 = new Color( color2 !== undefined ? color2 : 0x888888 );
+	constructor( size, divisions, color1, color2 ) {
 
-	const center = divisions / 2;
-	const step = size / divisions;
-	const halfSize = size / 2;
+		size = size || 10;
+		divisions = divisions || 10;
+		color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
+		color2 = new Color( color2 !== undefined ? color2 : 0x888888 );
 
-	const vertices = [], colors = [];
+		const center = divisions / 2;
+		const step = size / divisions;
+		const halfSize = size / 2;
 
-	for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
+		const vertices = [], colors = [];
 
-		vertices.push( - halfSize, 0, k, halfSize, 0, k );
-		vertices.push( k, 0, - halfSize, k, 0, halfSize );
+		for ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {
 
-		const color = i === center ? color1 : color2;
+			vertices.push( - halfSize, 0, k, halfSize, 0, k );
+			vertices.push( k, 0, - halfSize, k, 0, halfSize );
 
-		color.toArray( colors, j ); j += 3;
-		color.toArray( colors, j ); j += 3;
-		color.toArray( colors, j ); j += 3;
-		color.toArray( colors, j ); j += 3;
+			const color = i === center ? color1 : color2;
 
-	}
+			color.toArray( colors, j ); j += 3;
+			color.toArray( colors, j ); j += 3;
+			color.toArray( colors, j ); j += 3;
+			color.toArray( colors, j ); j += 3;
+
+		}
 
-	const geometry = new BufferGeometry();
-	geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
+		const geometry = new BufferGeometry();
+		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
 
-	const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
+		const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
 
-	LineSegments.call( this, geometry, material );
+		super( geometry, material );
 
-	this.type = 'GridHelper';
+		this.type = 'GridHelper';
+
+	}
 
 }
 
-GridHelper.prototype = Object.create( LineSegments.prototype );
-GridHelper.prototype.constructor = GridHelper;
 
 export { GridHelper };

+ 38 - 38
src/helpers/HemisphereLightHelper.js

@@ -10,75 +10,75 @@ const _vector = new Vector3();
 const _color1 = new Color();
 const _color2 = new Color();
 
-function HemisphereLightHelper( light, size, color ) {
+class HemisphereLightHelper extends Object3D {
 
-	Object3D.call( this );
+	constructor( light, size, color ) {
 
-	this.light = light;
-	this.light.updateMatrixWorld();
+		super();
+		this.light = light;
+		this.light.updateMatrixWorld();
 
-	this.matrix = light.matrixWorld;
-	this.matrixAutoUpdate = false;
+		this.matrix = light.matrixWorld;
+		this.matrixAutoUpdate = false;
 
-	this.color = color;
+		this.color = color;
 
-	const geometry = new OctahedronBufferGeometry( size );
-	geometry.rotateY( Math.PI * 0.5 );
+		const geometry = new OctahedronBufferGeometry( size );
+		geometry.rotateY( Math.PI * 0.5 );
 
-	this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
-	if ( this.color === undefined ) this.material.vertexColors = true;
+		this.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
+		if ( this.color === undefined ) this.material.vertexColors = true;
 
-	const position = geometry.getAttribute( 'position' );
-	const colors = new Float32Array( position.count * 3 );
+		const position = geometry.getAttribute( 'position' );
+		const colors = new Float32Array( position.count * 3 );
 
-	geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );
+		geometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );
 
-	this.add( new Mesh( geometry, this.material ) );
+		this.add( new Mesh( geometry, this.material ) );
 
-	this.update();
+		this.update();
 
-}
+	}
+
+	dispose() {
 
-HemisphereLightHelper.prototype = Object.create( Object3D.prototype );
-HemisphereLightHelper.prototype.constructor = HemisphereLightHelper;
+		this.children[ 0 ].geometry.dispose();
+		this.children[ 0 ].material.dispose();
 
-HemisphereLightHelper.prototype.dispose = function () {
+	}
 
-	this.children[ 0 ].geometry.dispose();
-	this.children[ 0 ].material.dispose();
+	update() {
 
-};
+		const mesh = this.children[ 0 ];
 
-HemisphereLightHelper.prototype.update = function () {
+		if ( this.color !== undefined ) {
 
-	const mesh = this.children[ 0 ];
+			this.material.color.set( this.color );
 
-	if ( this.color !== undefined ) {
+		} else {
 
-		this.material.color.set( this.color );
+			const colors = mesh.geometry.getAttribute( 'color' );
 
-	} else {
+			_color1.copy( this.light.color );
+			_color2.copy( this.light.groundColor );
 
-		const colors = mesh.geometry.getAttribute( 'color' );
+			for ( let i = 0, l = colors.count; i < l; i ++ ) {
 
-		_color1.copy( this.light.color );
-		_color2.copy( this.light.groundColor );
+				const color = ( i < ( l / 2 ) ) ? _color1 : _color2;
 
-		for ( let i = 0, l = colors.count; i < l; i ++ ) {
+				colors.setXYZ( i, color.r, color.g, color.b );
 
-			const color = ( i < ( l / 2 ) ) ? _color1 : _color2;
+			}
 
-			colors.setXYZ( i, color.r, color.g, color.b );
+			colors.needsUpdate = true;
 
 		}
 
-		colors.needsUpdate = true;
+		mesh.lookAt( _vector.setFromMatrixPosition( this.light.matrixWorld ).negate() );
 
 	}
 
-	mesh.lookAt( _vector.setFromMatrixPosition( this.light.matrixWorld ).negate() );
-
-};
+}
 
 
 export { HemisphereLightHelper };

+ 27 - 28
src/helpers/PlaneHelper.js

@@ -4,56 +4,55 @@ import { LineBasicMaterial } from '../materials/LineBasicMaterial.js';
 import { MeshBasicMaterial } from '../materials/MeshBasicMaterial.js';
 import { Float32BufferAttribute } from '../core/BufferAttribute.js';
 import { BufferGeometry } from '../core/BufferGeometry.js';
-import { Object3D } from '../core/Object3D.js';
 import { FrontSide, BackSide } from '../constants.js';
 
-function PlaneHelper( plane, size, hex ) {
+class PlaneHelper extends Line {
 
-	this.plane = plane;
+	constructor( plane, size, hex ) {
 
-	this.size = ( size === undefined ) ? 1 : size;
 
-	const color = ( hex !== undefined ) ? hex : 0xffff00;
+		const color = ( hex !== undefined ) ? hex : 0xffff00;
 
-	const positions = [ 1, - 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 ];
+		const positions = [ 1, - 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, - 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0 ];
 
-	const geometry = new BufferGeometry();
-	geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
-	geometry.computeBoundingSphere();
+		const geometry = new BufferGeometry();
+		geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
+		geometry.computeBoundingSphere();
 
-	Line.call( this, geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
+		super( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );
 
-	this.type = 'PlaneHelper';
+		this.type = 'PlaneHelper';
 
-	//
+		this.plane = plane;
 
-	const positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ];
+		this.size = ( size === undefined ) ? 1 : size;
 
-	const geometry2 = new BufferGeometry();
-	geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
-	geometry2.computeBoundingSphere();
+		const positions2 = [ 1, 1, 1, - 1, 1, 1, - 1, - 1, 1, 1, 1, 1, - 1, - 1, 1, 1, - 1, 1 ];
 
-	this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) );
+		const geometry2 = new BufferGeometry();
+		geometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );
+		geometry2.computeBoundingSphere();
 
-}
+		this.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) );
+
+	}
 
-PlaneHelper.prototype = Object.create( Line.prototype );
-PlaneHelper.prototype.constructor = PlaneHelper;
+	updateMatrixWorld( force ) {
 
-PlaneHelper.prototype.updateMatrixWorld = function ( force ) {
+		let scale = - this.plane.constant;
 
-	let scale = - this.plane.constant;
+		if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter
 
-	if ( Math.abs( scale ) < 1e-8 ) scale = 1e-8; // sign does not matter
+		this.scale.set( 0.5 * this.size, 0.5 * this.size, scale );
 
-	this.scale.set( 0.5 * this.size, 0.5 * this.size, scale );
+		this.children[ 0 ].material.side = ( scale < 0 ) ? BackSide : FrontSide; // renderer flips side when determinant < 0; flipping not wanted here
 
-	this.children[ 0 ].material.side = ( scale < 0 ) ? BackSide : FrontSide; // renderer flips side when determinant < 0; flipping not wanted here
+		this.lookAt( this.plane.normal );
 
-	this.lookAt( this.plane.normal );
+		super.updateMatrixWorld( force );
 
-	Object3D.prototype.updateMatrixWorld.call( this, force );
+	}
 
-};
+}
 
 export { PlaneHelper };

+ 36 - 34
src/helpers/PointLightHelper.js

@@ -2,27 +2,30 @@ import { Mesh } from '../objects/Mesh.js';
 import { MeshBasicMaterial } from '../materials/MeshBasicMaterial.js';
 import { SphereBufferGeometry } from '../geometries/SphereGeometry.js';
 
-function PointLightHelper( light, sphereSize, color ) {
+class PointLightHelper extends Mesh {
 
-	this.light = light;
-	this.light.updateMatrixWorld();
+	constructor( light, sphereSize, color ) {
 
-	this.color = color;
+		const geometry = new SphereBufferGeometry( sphereSize, 4, 2 );
+		const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
 
-	const geometry = new SphereBufferGeometry( sphereSize, 4, 2 );
-	const material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );
+		super( geometry, material );
 
-	Mesh.call( this, geometry, material );
+		this.light = light;
+		this.light.updateMatrixWorld();
 
-	this.type = 'PointLightHelper';
+		this.color = color;
 
-	this.matrix = this.light.matrixWorld;
-	this.matrixAutoUpdate = false;
+		this.type = 'PointLightHelper';
 
-	this.update();
+		this.matrix = this.light.matrixWorld;
+		this.matrixAutoUpdate = false;
 
+		this.update();
 
-	/*
+
+		/*
+	// TODO: delete this comment?
 	const distanceGeometry = new THREE.IcosahedronBufferGeometry( 1, 2 );
 	const distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );
 
@@ -44,46 +47,45 @@ function PointLightHelper( light, sphereSize, color ) {
 	this.add( this.lightDistance );
 	*/
 
-}
+	}
 
-PointLightHelper.prototype = Object.create( Mesh.prototype );
-PointLightHelper.prototype.constructor = PointLightHelper;
+	dispose() {
 
-PointLightHelper.prototype.dispose = function () {
+		this.geometry.dispose();
+		this.material.dispose();
 
-	this.geometry.dispose();
-	this.material.dispose();
+	}
 
-};
+	update() {
 
-PointLightHelper.prototype.update = function () {
+		if ( this.color !== undefined ) {
 
-	if ( this.color !== undefined ) {
+			this.material.color.set( this.color );
 
-		this.material.color.set( this.color );
+		} else {
 
-	} else {
+			this.material.color.copy( this.light.color );
 
-		this.material.color.copy( this.light.color );
+		}
 
-	}
+		/*
+		const d = this.light.distance;
 
-	/*
-	const d = this.light.distance;
+		if ( d === 0.0 ) {
 
-	if ( d === 0.0 ) {
+			this.lightDistance.visible = false;
 
-		this.lightDistance.visible = false;
+		} else {
 
-	} else {
+			this.lightDistance.visible = true;
+			this.lightDistance.scale.set( d, d, d );
 
-		this.lightDistance.visible = true;
-		this.lightDistance.scale.set( d, d, d );
+		}
+		*/
 
 	}
-	*/
 
-};
+}
 
 
 export { PointLightHelper };

+ 48 - 46
src/helpers/PolarGridHelper.js

@@ -4,84 +4,86 @@ import { Float32BufferAttribute } from '../core/BufferAttribute.js';
 import { BufferGeometry } from '../core/BufferGeometry.js';
 import { Color } from '../math/Color.js';
 
-function PolarGridHelper( radius, radials, circles, divisions, color1, color2 ) {
+class PolarGridHelper extends LineSegments {
 
-	radius = radius || 10;
-	radials = radials || 16;
-	circles = circles || 8;
-	divisions = divisions || 64;
-	color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
-	color2 = new Color( color2 !== undefined ? color2 : 0x888888 );
+	constructor( radius, radials, circles, divisions, color1, color2 ) {
 
-	const vertices = [];
-	const colors = [];
+		radius = radius || 10;
+		radials = radials || 16;
+		circles = circles || 8;
+		divisions = divisions || 64;
+		color1 = new Color( color1 !== undefined ? color1 : 0x444444 );
+		color2 = new Color( color2 !== undefined ? color2 : 0x888888 );
 
-	// create the radials
+		const vertices = [];
+		const colors = [];
 
-	for ( let i = 0; i <= radials; i ++ ) {
+		// create the radials
 
-		const v = ( i / radials ) * ( Math.PI * 2 );
+		for ( let i = 0; i <= radials; i ++ ) {
 
-		const x = Math.sin( v ) * radius;
-		const z = Math.cos( v ) * radius;
+			const v = ( i / radials ) * ( Math.PI * 2 );
 
-		vertices.push( 0, 0, 0 );
-		vertices.push( x, 0, z );
+			const x = Math.sin( v ) * radius;
+			const z = Math.cos( v ) * radius;
 
-		const color = ( i & 1 ) ? color1 : color2;
+			vertices.push( 0, 0, 0 );
+			vertices.push( x, 0, z );
 
-		colors.push( color.r, color.g, color.b );
-		colors.push( color.r, color.g, color.b );
+			const color = ( i & 1 ) ? color1 : color2;
 
-	}
+			colors.push( color.r, color.g, color.b );
+			colors.push( color.r, color.g, color.b );
 
-	// create the circles
+		}
 
-	for ( let i = 0; i <= circles; i ++ ) {
+		// create the circles
 
-		const color = ( i & 1 ) ? color1 : color2;
+		for ( let i = 0; i <= circles; i ++ ) {
 
-		const r = radius - ( radius / circles * i );
+			const color = ( i & 1 ) ? color1 : color2;
 
-		for ( let j = 0; j < divisions; j ++ ) {
+			const r = radius - ( radius / circles * i );
 
-			// first vertex
+			for ( let j = 0; j < divisions; j ++ ) {
 
-			let v = ( j / divisions ) * ( Math.PI * 2 );
+				// first vertex
 
-			let x = Math.sin( v ) * r;
-			let z = Math.cos( v ) * r;
+				let v = ( j / divisions ) * ( Math.PI * 2 );
 
-			vertices.push( x, 0, z );
-			colors.push( color.r, color.g, color.b );
+				let x = Math.sin( v ) * r;
+				let z = Math.cos( v ) * r;
 
-			// second vertex
+				vertices.push( x, 0, z );
+				colors.push( color.r, color.g, color.b );
 
-			v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
+				// second vertex
 
-			x = Math.sin( v ) * r;
-			z = Math.cos( v ) * r;
+				v = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );
 
-			vertices.push( x, 0, z );
-			colors.push( color.r, color.g, color.b );
+				x = Math.sin( v ) * r;
+				z = Math.cos( v ) * r;
+
+				vertices.push( x, 0, z );
+				colors.push( color.r, color.g, color.b );
+
+			}
 
 		}
 
-	}
+		const geometry = new BufferGeometry();
+		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
 
-	const geometry = new BufferGeometry();
-	geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
+		const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
 
-	const material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );
+		super( geometry, material );
 
-	LineSegments.call( this, geometry, material );
+		this.type = 'PolarGridHelper';
 
-	this.type = 'PolarGridHelper';
+	}
 
 }
 
-PolarGridHelper.prototype = Object.create( LineSegments.prototype );
-PolarGridHelper.prototype.constructor = PolarGridHelper;
 
 export { PolarGridHelper };

+ 61 - 59
src/helpers/SkeletonHelper.js

@@ -5,114 +5,116 @@ import { Color } from '../math/Color.js';
 import { Vector3 } from '../math/Vector3.js';
 import { BufferGeometry } from '../core/BufferGeometry.js';
 import { Float32BufferAttribute } from '../core/BufferAttribute.js';
-import { Object3D } from '../core/Object3D.js';
 
 const _vector = new Vector3();
 const _boneMatrix = new Matrix4();
 const _matrixWorldInv = new Matrix4();
 
-function getBoneList( object ) {
-
-	const boneList = [];
 
-	if ( object && object.isBone ) {
+class SkeletonHelper extends LineSegments {
 
-		boneList.push( object );
+	constructor( object ) {
 
-	}
+		const bones = getBoneList( object );
 
-	for ( let i = 0; i < object.children.length; i ++ ) {
+		const geometry = new BufferGeometry();
 
-		boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
+		const vertices = [];
+		const colors = [];
 
-	}
+		const color1 = new Color( 0, 0, 1 );
+		const color2 = new Color( 0, 1, 0 );
 
-	return boneList;
+		for ( let i = 0; i < bones.length; i ++ ) {
 
-}
+			const bone = bones[ i ];
 
-function SkeletonHelper( object ) {
+			if ( bone.parent && bone.parent.isBone ) {
 
-	const bones = getBoneList( object );
+				vertices.push( 0, 0, 0 );
+				vertices.push( 0, 0, 0 );
+				colors.push( color1.r, color1.g, color1.b );
+				colors.push( color2.r, color2.g, color2.b );
 
-	const geometry = new BufferGeometry();
+			}
 
-	const vertices = [];
-	const colors = [];
+		}
 
-	const color1 = new Color( 0, 0, 1 );
-	const color2 = new Color( 0, 1, 0 );
+		geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
 
-	for ( let i = 0; i < bones.length; i ++ ) {
+		const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );
 
-		const bone = bones[ i ];
+		super( geometry, material );
 
-		if ( bone.parent && bone.parent.isBone ) {
+		this.type = 'SkeletonHelper';
+		this.isSkeletonHelper = true;
 
-			vertices.push( 0, 0, 0 );
-			vertices.push( 0, 0, 0 );
-			colors.push( color1.r, color1.g, color1.b );
-			colors.push( color2.r, color2.g, color2.b );
+		this.root = object;
+		this.bones = bones;
 
-		}
+		this.matrix = object.matrixWorld;
+		this.matrixAutoUpdate = false;
 
 	}
 
-	geometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	geometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );
+	updateMatrixWorld( force ) {
 
-	const material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );
+		const bones = this.bones;
 
-	LineSegments.call( this, geometry, material );
+		const geometry = this.geometry;
+		const position = geometry.getAttribute( 'position' );
 
-	this.type = 'SkeletonHelper';
+		_matrixWorldInv.getInverse( this.root.matrixWorld );
 
-	this.root = object;
-	this.bones = bones;
+		for ( let i = 0, j = 0; i < bones.length; i ++ ) {
 
-	this.matrix = object.matrixWorld;
-	this.matrixAutoUpdate = false;
+			const bone = bones[ i ];
 
-}
+			if ( bone.parent && bone.parent.isBone ) {
 
-SkeletonHelper.prototype = Object.create( LineSegments.prototype );
-SkeletonHelper.prototype.constructor = SkeletonHelper;
+				_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );
+				_vector.setFromMatrixPosition( _boneMatrix );
+				position.setXYZ( j, _vector.x, _vector.y, _vector.z );
 
-SkeletonHelper.prototype.isSkeletonHelper = true;
+				_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );
+				_vector.setFromMatrixPosition( _boneMatrix );
+				position.setXYZ( j + 1, _vector.x, _vector.y, _vector.z );
 
-SkeletonHelper.prototype.updateMatrixWorld = function ( force ) {
+				j += 2;
 
-	const bones = this.bones;
+			}
 
-	const geometry = this.geometry;
-	const position = geometry.getAttribute( 'position' );
+		}
 
-	_matrixWorldInv.getInverse( this.root.matrixWorld );
+		geometry.getAttribute( 'position' ).needsUpdate = true;
 
-	for ( let i = 0, j = 0; i < bones.length; i ++ ) {
+		super.updateMatrixWorld( force );
 
-		const bone = bones[ i ];
+	}
 
-		if ( bone.parent && bone.parent.isBone ) {
+}
 
-			_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );
-			_vector.setFromMatrixPosition( _boneMatrix );
-			position.setXYZ( j, _vector.x, _vector.y, _vector.z );
 
-			_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );
-			_vector.setFromMatrixPosition( _boneMatrix );
-			position.setXYZ( j + 1, _vector.x, _vector.y, _vector.z );
+function getBoneList( object ) {
 
-			j += 2;
+	const boneList = [];
 
-		}
+	if ( object && object.isBone ) {
+
+		boneList.push( object );
 
 	}
 
-	geometry.getAttribute( 'position' ).needsUpdate = true;
+	for ( let i = 0; i < object.children.length; i ++ ) {
 
-	Object3D.prototype.updateMatrixWorld.call( this, force );
+		boneList.push.apply( boneList, getBoneList( object.children[ i ] ) );
+
+	}
+
+	return boneList;
+
+}
 
-};
 
 export { SkeletonHelper };

+ 47 - 47
src/helpers/SpotLightHelper.js

@@ -7,85 +7,85 @@ import { BufferGeometry } from '../core/BufferGeometry.js';
 
 const _vector = new Vector3();
 
-function SpotLightHelper( light, color ) {
+class SpotLightHelper extends Object3D {
 
-	Object3D.call( this );
+	constructor( light, color ) {
 
-	this.light = light;
-	this.light.updateMatrixWorld();
+		super();
+		this.light = light;
+		this.light.updateMatrixWorld();
 
-	this.matrix = light.matrixWorld;
-	this.matrixAutoUpdate = false;
+		this.matrix = light.matrixWorld;
+		this.matrixAutoUpdate = false;
 
-	this.color = color;
+		this.color = color;
 
-	const geometry = new BufferGeometry();
+		const geometry = new BufferGeometry();
 
-	const positions = [
-		0, 0, 0, 	0, 0, 1,
-		0, 0, 0, 	1, 0, 1,
-		0, 0, 0,	- 1, 0, 1,
-		0, 0, 0, 	0, 1, 1,
-		0, 0, 0, 	0, - 1, 1
-	];
+		const positions = [
+			0, 0, 0, 	0, 0, 1,
+			0, 0, 0, 	1, 0, 1,
+			0, 0, 0,	- 1, 0, 1,
+			0, 0, 0, 	0, 1, 1,
+			0, 0, 0, 	0, - 1, 1
+		];
 
-	for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
+		for ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {
 
-		const p1 = ( i / l ) * Math.PI * 2;
-		const p2 = ( j / l ) * Math.PI * 2;
+			const p1 = ( i / l ) * Math.PI * 2;
+			const p2 = ( j / l ) * Math.PI * 2;
 
-		positions.push(
-			Math.cos( p1 ), Math.sin( p1 ), 1,
-			Math.cos( p2 ), Math.sin( p2 ), 1
-		);
+			positions.push(
+				Math.cos( p1 ), Math.sin( p1 ), 1,
+				Math.cos( p2 ), Math.sin( p2 ), 1
+			);
 
-	}
+		}
 
-	geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
+		geometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );
 
-	const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
+		const material = new LineBasicMaterial( { fog: false, toneMapped: false } );
 
-	this.cone = new LineSegments( geometry, material );
-	this.add( this.cone );
+		this.cone = new LineSegments( geometry, material );
+		this.add( this.cone );
 
-	this.update();
+		this.update();
 
-}
+	}
 
-SpotLightHelper.prototype = Object.create( Object3D.prototype );
-SpotLightHelper.prototype.constructor = SpotLightHelper;
+	dispose() {
 
-SpotLightHelper.prototype.dispose = function () {
+		this.cone.geometry.dispose();
+		this.cone.material.dispose();
 
-	this.cone.geometry.dispose();
-	this.cone.material.dispose();
+	}
 
-};
+	update() {
 
-SpotLightHelper.prototype.update = function () {
+		this.light.updateMatrixWorld();
 
-	this.light.updateMatrixWorld();
+		const coneLength = this.light.distance ? this.light.distance : 1000;
+		const coneWidth = coneLength * Math.tan( this.light.angle );
 
-	const coneLength = this.light.distance ? this.light.distance : 1000;
-	const coneWidth = coneLength * Math.tan( this.light.angle );
+		this.cone.scale.set( coneWidth, coneWidth, coneLength );
 
-	this.cone.scale.set( coneWidth, coneWidth, coneLength );
+		_vector.setFromMatrixPosition( this.light.target.matrixWorld );
 
-	_vector.setFromMatrixPosition( this.light.target.matrixWorld );
+		this.cone.lookAt( _vector );
 
-	this.cone.lookAt( _vector );
+		if ( this.color !== undefined ) {
 
-	if ( this.color !== undefined ) {
+			this.cone.material.color.set( this.color );
 
-		this.cone.material.color.set( this.color );
+		} else {
 
-	} else {
+			this.cone.material.color.copy( this.light.color );
 
-		this.cone.material.color.copy( this.light.color );
+		}
 
 	}
 
-};
+}
 
 
 export { SpotLightHelper };

+ 2 - 2
src/materials/MeshPhysicalMaterial.d.ts

@@ -10,9 +10,9 @@ export interface MeshPhysicalMaterialParameters
 	extends MeshStandardMaterialParameters {
 
 	clearcoat?: number;
-	clearcoatMap: Texture | null;
+	clearcoatMap?: Texture | null;
 	clearcoatRoughness?: number;
-	clearcoatRoughnessMap: Texture | null;
+	clearcoatRoughnessMap?: Texture | null;
 	clearcoatNormalScale?: Vector2;
 	clearcoatNormalMap?: Texture | null;
 

+ 2 - 3
src/math/Interpolant.js

@@ -35,9 +35,8 @@ Object.assign( Interpolant.prototype, {
 
 	evaluate: function ( t ) {
 
-		let pp = this.parameterPositions,
-			i1 = this._cachedIndex,
-
+		const pp = this.parameterPositions;
+		let i1 = this._cachedIndex,
 			t1 = pp[ i1 ],
 			t0 = pp[ i1 - 1 ];
 

+ 2 - 2
src/math/Matrix4.js

@@ -729,8 +729,8 @@ Object.assign( Matrix4.prototype, {
 		const te = this.elements;
 
 		let sx = _v1.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();
-		let sy = _v1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
-		let sz = _v1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
+		const sy = _v1.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();
+		const sz = _v1.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();
 
 		// if determine is negative, we need to invert one scale
 		const det = this.determinant();

+ 2 - 4
src/math/Quaternion.js

@@ -33,10 +33,8 @@ Object.assign( Quaternion, {
 
 		if ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {
 
-			let s = 1 - t,
-
-				cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
-
+			let s = 1 - t;
+			const cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,
 				dir = ( cos >= 0 ? 1 : - 1 ),
 				sqrSin = 1 - cos * cos;
 

+ 45 - 45
src/math/Ray.js

@@ -9,40 +9,40 @@ const _edge1 = new Vector3();
 const _edge2 = new Vector3();
 const _normal = new Vector3();
 
-function Ray( origin, direction ) {
+class Ray {
 
-	this.origin = ( origin !== undefined ) ? origin : new Vector3();
-	this.direction = ( direction !== undefined ) ? direction : new Vector3( 0, 0, - 1 );
+	constructor( origin, direction ) {
 
-}
+		this.origin = ( origin !== undefined ) ? origin : new Vector3();
+		this.direction = ( direction !== undefined ) ? direction : new Vector3( 0, 0, - 1 );
 
-Object.assign( Ray.prototype, {
+	}
 
-	set: function ( origin, direction ) {
+	set( origin, direction ) {
 
 		this.origin.copy( origin );
 		this.direction.copy( direction );
 
 		return this;
 
-	},
+	}
 
-	clone: function () {
+	clone() {
 
 		return new this.constructor().copy( this );
 
-	},
+	}
 
-	copy: function ( ray ) {
+	copy( ray ) {
 
 		this.origin.copy( ray.origin );
 		this.direction.copy( ray.direction );
 
 		return this;
 
-	},
+	}
 
-	at: function ( t, target ) {
+	at( t, target ) {
 
 		if ( target === undefined ) {
 
@@ -53,25 +53,25 @@ Object.assign( Ray.prototype, {
 
 		return target.copy( this.direction ).multiplyScalar( t ).add( this.origin );
 
-	},
+	}
 
-	lookAt: function ( v ) {
+	lookAt( v ) {
 
 		this.direction.copy( v ).sub( this.origin ).normalize();
 
 		return this;
 
-	},
+	}
 
-	recast: function ( t ) {
+	recast( t ) {
 
 		this.origin.copy( this.at( t, _vector ) );
 
 		return this;
 
-	},
+	}
 
-	closestPointToPoint: function ( point, target ) {
+	closestPointToPoint( point, target ) {
 
 		if ( target === undefined ) {
 
@@ -92,15 +92,15 @@ Object.assign( Ray.prototype, {
 
 		return target.copy( this.direction ).multiplyScalar( directionDistance ).add( this.origin );
 
-	},
+	}
 
-	distanceToPoint: function ( point ) {
+	distanceToPoint( point ) {
 
 		return Math.sqrt( this.distanceSqToPoint( point ) );
 
-	},
+	}
 
-	distanceSqToPoint: function ( point ) {
+	distanceSqToPoint( point ) {
 
 		const directionDistance = _vector.subVectors( point, this.origin ).dot( this.direction );
 
@@ -116,9 +116,9 @@ Object.assign( Ray.prototype, {
 
 		return _vector.distanceToSquared( point );
 
-	},
+	}
 
-	distanceSqToSegment: function ( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
+	distanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {
 
 		// from http://www.geometrictools.com/GTEngine/Include/Mathematics/GteDistRaySegment.h
 		// It returns the min distance between the ray and the segment
@@ -235,9 +235,9 @@ Object.assign( Ray.prototype, {
 
 		return sqrDist;
 
-	},
+	}
 
-	intersectSphere: function ( sphere, target ) {
+	intersectSphere( sphere, target ) {
 
 		_vector.subVectors( sphere.center, this.origin );
 		const tca = _vector.dot( this.direction );
@@ -265,15 +265,15 @@ Object.assign( Ray.prototype, {
 		// else t0 is in front of the ray, so return the first collision point scaled by t0
 		return this.at( t0, target );
 
-	},
+	}
 
-	intersectsSphere: function ( sphere ) {
+	intersectsSphere( sphere ) {
 
 		return this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );
 
-	},
+	}
 
-	distanceToPlane: function ( plane ) {
+	distanceToPlane( plane ) {
 
 		const denominator = plane.normal.dot( this.direction );
 
@@ -298,9 +298,9 @@ Object.assign( Ray.prototype, {
 
 		return t >= 0 ? t : null;
 
-	},
+	}
 
-	intersectPlane: function ( plane, target ) {
+	intersectPlane( plane, target ) {
 
 		const t = this.distanceToPlane( plane );
 
@@ -312,9 +312,9 @@ Object.assign( Ray.prototype, {
 
 		return this.at( t, target );
 
-	},
+	}
 
-	intersectsPlane: function ( plane ) {
+	intersectsPlane( plane ) {
 
 		// check if the ray lies on the plane first
 
@@ -338,9 +338,9 @@ Object.assign( Ray.prototype, {
 
 		return false;
 
-	},
+	}
 
-	intersectBox: function ( box, target ) {
+	intersectBox( box, target ) {
 
 		let tmin, tmax, tymin, tymax, tzmin, tzmax;
 
@@ -407,15 +407,15 @@ Object.assign( Ray.prototype, {
 
 		return this.at( tmin >= 0 ? tmin : tmax, target );
 
-	},
+	}
 
-	intersectsBox: function ( box ) {
+	intersectsBox( box ) {
 
 		return this.intersectBox( box, _vector ) !== null;
 
-	},
+	}
 
-	intersectTriangle: function ( a, b, c, backfaceCulling, target ) {
+	intersectTriangle( a, b, c, backfaceCulling, target ) {
 
 		// Compute the offset origin, edges, and normal.
 
@@ -488,24 +488,24 @@ Object.assign( Ray.prototype, {
 		// Ray intersects triangle.
 		return this.at( QdN / DdN, target );
 
-	},
+	}
 
-	applyMatrix4: function ( matrix4 ) {
+	applyMatrix4( matrix4 ) {
 
 		this.origin.applyMatrix4( matrix4 );
 		this.direction.transformDirection( matrix4 );
 
 		return this;
 
-	},
+	}
 
-	equals: function ( ray ) {
+	equals( ray ) {
 
 		return ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );
 
 	}
 
-} );
+}
 
 
 export { Ray };

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

@@ -34,8 +34,8 @@ CubicInterpolant.prototype = Object.assign( Object.create( Interpolant.prototype
 
 	intervalChanged_: function ( i1, t0, t1 ) {
 
-		let pp = this.parameterPositions,
-			iPrev = i1 - 2,
+		const pp = this.parameterPositions;
+		let iPrev = i1 - 2,
 			iNext = i1 + 1,
 
 			tPrev = pp[ iPrev ],

+ 13 - 0
src/objects/InstancedMesh.js

@@ -14,6 +14,7 @@ function InstancedMesh( geometry, material, count ) {
 	Mesh.call( this, geometry, material );
 
 	this.instanceMatrix = new BufferAttribute( new Float32Array( count * 16 ), 16 );
+	this.instanceColor = null;
 
 	this.count = count;
 
@@ -38,6 +39,18 @@ InstancedMesh.prototype = Object.assign( Object.create( Mesh.prototype ), {
 
 	},
 
+	setColorAt: function ( index, color ) {
+
+		if ( this.instanceColor === null ) {
+
+			this.instanceColor = new BufferAttribute( new Float32Array( this.count * 3 ), 3 );
+
+		}
+
+		color.toArray( this.instanceColor.array, index * 3 );
+
+	},
+
 	getMatrixAt: function ( index, matrix ) {
 
 		matrix.fromArray( this.instanceMatrix.array, index * 16 );

+ 2 - 2
src/renderers/WebGLRenderer.js

@@ -894,7 +894,7 @@ function WebGLRenderer( parameters ) {
 
 		scene.traverse( function ( object ) {
 
-			let material = object.material;
+			const material = object.material;
 
 			if ( material ) {
 
@@ -902,7 +902,7 @@ function WebGLRenderer( parameters ) {
 
 					for ( let i = 0; i < material.length; i ++ ) {
 
-						let material2 = material[ i ];
+						const material2 = material[ i ];
 
 						if ( compiled.has( material2 ) === false ) {
 

+ 5 - 5
src/renderers/shaders/ShaderChunk/bsdfs.glsl.js

@@ -154,9 +154,9 @@ vec3 BRDF_Specular_GGX( const in IncidentLight incidentLight, const in vec3 view
 
 vec2 LTC_Uv( const in vec3 N, const in vec3 V, const in float roughness ) {
 
-	const float LUT_SIZE  = 64.0;
+	const float LUT_SIZE = 64.0;
 	const float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;
-	const float LUT_BIAS  = 0.5 / LUT_SIZE;
+	const float LUT_BIAS = 0.5 / LUT_SIZE;
 
 	float dotNV = saturate( dot( N, V ) );
 
@@ -244,9 +244,9 @@ vec3 LTC_Evaluate( const in vec3 N, const in vec3 V, const in vec3 P, const in m
 	float len = length( vectorFormFactor );
 	float z = vectorFormFactor.z / len;
 
-	const float LUT_SIZE  = 64.0;
+	const float LUT_SIZE = 64.0;
 	const float LUT_SCALE = ( LUT_SIZE - 1.0 ) / LUT_SIZE;
-	const float LUT_BIAS  = 0.5 / LUT_SIZE;
+	const float LUT_BIAS = 0.5 / LUT_SIZE;
 
 	// tabulated horizon-clipped sphere, apparently...
 	vec2 uv = vec2( z * 0.5 + 0.5, len );
@@ -342,7 +342,7 @@ float BlinnExponentToGGXRoughness( const in float blinnExponent ) {
 // https://github.com/google/filament/blob/master/shaders/src/brdf.fs#L94
 float D_Charlie(float roughness, float NoH) {
 	// Estevez and Kulla 2017, "Production Friendly Microfacet Sheen BRDF"
-	float invAlpha  = 1.0 / roughness;
+	float invAlpha = 1.0 / roughness;
 	float cos2h = NoH * NoH;
 	float sin2h = max(1.0 - cos2h, 0.0078125); // 2^(-14/2), so sin2h^2 > 0 in fp16
 	return (2.0 + invAlpha) * pow(sin2h, invAlpha * 0.5) / (2.0 * PI);

+ 1 - 1
src/renderers/shaders/ShaderChunk/color_pars_vertex.glsl.js

@@ -1,5 +1,5 @@
 export default /* glsl */`
-#ifdef USE_COLOR
+#if defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR )
 
 	varying vec3 vColor;
 

Unele fișiere nu au fost afișate deoarece prea multe fișiere au fost modificate în acest diff