Bläddra i källkod

Examples: Convert cameras and geometries to ES6. (#21589)

* Examples: Convert cameras and geometries to ES6.

* Examples: Clean up.
Michael Herzog 4 år sedan
förälder
incheckning
2ea5cc9826

+ 117 - 119
examples/js/cameras/CinematicCamera.js

@@ -1,163 +1,161 @@
 ( function () {
 
-	var CinematicCamera = function ( fov, aspect, near, far ) {
-
-		THREE.PerspectiveCamera.call( this, fov, aspect, near, far );
-		this.type = 'CinematicCamera';
-		this.postprocessing = {
-			enabled: true
-		};
-		this.shaderSettings = {
-			rings: 3,
-			samples: 4
-		};
-		var depthShader = THREE.BokehDepthShader;
-		this.materialDepth = new THREE.ShaderMaterial( {
-			uniforms: depthShader.uniforms,
-			vertexShader: depthShader.vertexShader,
-			fragmentShader: depthShader.fragmentShader
-		} );
-		this.materialDepth.uniforms[ 'mNear' ].value = near;
-		this.materialDepth.uniforms[ 'mFar' ].value = far; // In case of cinematicCamera, having a default lens set is important
-
-		this.setLens();
-		this.initPostProcessing();
-
-	};
-
-	CinematicCamera.prototype = Object.create( THREE.PerspectiveCamera.prototype );
-	CinematicCamera.prototype.constructor = CinematicCamera; // providing fnumber and coc(Circle of Confusion) as extra arguments
-
-	CinematicCamera.prototype.setLens = function ( focalLength, filmGauge, fNumber, coc ) {
+	class CinematicCamera extends THREE.PerspectiveCamera {
 
+		constructor( fov, aspect, near, far ) {
+
+			super( fov, aspect, near, far );
+			this.type = 'CinematicCamera';
+			this.postprocessing = {
+				enabled: true
+			};
+			this.shaderSettings = {
+				rings: 3,
+				samples: 4
+			};
+			const depthShader = THREE.BokehDepthShader;
+			this.materialDepth = new THREE.ShaderMaterial( {
+				uniforms: depthShader.uniforms,
+				vertexShader: depthShader.vertexShader,
+				fragmentShader: depthShader.fragmentShader
+			} );
+			this.materialDepth.uniforms[ 'mNear' ].value = near;
+			this.materialDepth.uniforms[ 'mFar' ].value = far; // In case of cinematicCamera, having a default lens set is important
+
+			this.setLens();
+			this.initPostProcessing();
+
+		} // providing fnumber and coc(Circle of Confusion) as extra arguments
 		// In case of cinematicCamera, having a default lens set is important
-		if ( focalLength === undefined ) focalLength = 35;
-		if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
-		this.setFocalLength( focalLength ); // if fnumber and coc are not provided, cinematicCamera tries to act as a basic THREE.PerspectiveCamera
+		// if fnumber and coc are not provided, cinematicCamera tries to act as a basic THREE.PerspectiveCamera
 
-		if ( fNumber === undefined ) fNumber = 8;
-		if ( coc === undefined ) coc = 0.019;
-		this.fNumber = fNumber;
-		this.coc = coc; // fNumber is focalLength by aperture
 
-		this.aperture = focalLength / this.fNumber; // hyperFocal is required to calculate depthOfField when a lens tries to focus at a distance with given fNumber and focalLength
+		setLens( focalLength = 35, filmGauge = 35, fNumber = 8, coc = 0.019 ) {
 
-		this.hyperFocal = focalLength * focalLength / ( this.aperture * this.coc );
+			this.filmGauge = filmGauge;
+			this.setFocalLength( focalLength );
+			this.fNumber = fNumber;
+			this.coc = coc; // fNumber is focalLength by aperture
 
-	};
+			this.aperture = focalLength / this.fNumber; // hyperFocal is required to calculate depthOfField when a lens tries to focus at a distance with given fNumber and focalLength
 
-	CinematicCamera.prototype.linearize = function ( depth ) {
+			this.hyperFocal = focalLength * focalLength / ( this.aperture * this.coc );
 
-		var zfar = this.far;
-		var znear = this.near;
-		return - zfar * znear / ( depth * ( zfar - znear ) - zfar );
+		}
 
-	};
+		linearize( depth ) {
 
-	CinematicCamera.prototype.smoothstep = function ( near, far, depth ) {
+			const zfar = this.far;
+			const znear = this.near;
+			return - zfar * znear / ( depth * ( zfar - znear ) - zfar );
 
-		var x = this.saturate( ( depth - near ) / ( far - near ) );
-		return x * x * ( 3 - 2 * x );
+		}
 
-	};
+		smoothstep( near, far, depth ) {
 
-	CinematicCamera.prototype.saturate = function ( x ) {
+			const x = this.saturate( ( depth - near ) / ( far - near ) );
+			return x * x * ( 3 - 2 * x );
 
-		return Math.max( 0, Math.min( 1, x ) );
+		}
 
-	}; // function for focusing at a distance from the camera
+		saturate( x ) {
 
+			return Math.max( 0, Math.min( 1, x ) );
 
-	CinematicCamera.prototype.focusAt = function ( focusDistance ) {
+		} // function for focusing at a distance from the camera
 
-		if ( focusDistance === undefined ) focusDistance = 20;
-		var focalLength = this.getFocalLength(); // distance from the camera (normal to frustrum) to focus on
 
-		this.focus = focusDistance; // the nearest point from the camera which is in focus (unused)
+		focusAt( focusDistance = 20 ) {
 
-		this.nearPoint = this.hyperFocal * this.focus / ( this.hyperFocal + ( this.focus - focalLength ) ); // the farthest point from the camera which is in focus (unused)
+			const focalLength = this.getFocalLength(); // distance from the camera (normal to frustrum) to focus on
 
-		this.farPoint = this.hyperFocal * this.focus / ( this.hyperFocal - ( this.focus - focalLength ) ); // the gap or width of the space in which is everything is in focus (unused)
+			this.focus = focusDistance; // the nearest point from the camera which is in focus (unused)
 
-		this.depthOfField = this.farPoint - this.nearPoint; // Considering minimum distance of focus for a standard lens (unused)
+			this.nearPoint = this.hyperFocal * this.focus / ( this.hyperFocal + ( this.focus - focalLength ) ); // the farthest point from the camera which is in focus (unused)
 
-		if ( this.depthOfField < 0 ) this.depthOfField = 0;
-		this.sdistance = this.smoothstep( this.near, this.far, this.focus );
-		this.ldistance = this.linearize( 1 - this.sdistance );
-		this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = this.ldistance;
+			this.farPoint = this.hyperFocal * this.focus / ( this.hyperFocal - ( this.focus - focalLength ) ); // the gap or width of the space in which is everything is in focus (unused)
 
-	};
+			this.depthOfField = this.farPoint - this.nearPoint; // Considering minimum distance of focus for a standard lens (unused)
 
-	CinematicCamera.prototype.initPostProcessing = function () {
+			if ( this.depthOfField < 0 ) this.depthOfField = 0;
+			this.sdistance = this.smoothstep( this.near, this.far, this.focus );
+			this.ldistance = this.linearize( 1 - this.sdistance );
+			this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = this.ldistance;
 
-		if ( this.postprocessing.enabled ) {
+		}
 
-			this.postprocessing.scene = new THREE.Scene();
-			this.postprocessing.camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, - 10000, 10000 );
-			this.postprocessing.scene.add( this.postprocessing.camera );
-			var pars = {
-				minFilter: THREE.LinearFilter,
-				magFilter: THREE.LinearFilter,
-				format: THREE.RGBFormat
-			};
-			this.postprocessing.rtTextureDepth = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );
-			this.postprocessing.rtTextureColor = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );
-			var bokeh_shader = THREE.BokehShader;
-			this.postprocessing.bokeh_uniforms = THREE.UniformsUtils.clone( bokeh_shader.uniforms );
-			this.postprocessing.bokeh_uniforms[ 'tColor' ].value = this.postprocessing.rtTextureColor.texture;
-			this.postprocessing.bokeh_uniforms[ 'tDepth' ].value = this.postprocessing.rtTextureDepth.texture;
-			this.postprocessing.bokeh_uniforms[ 'manualdof' ].value = 0;
-			this.postprocessing.bokeh_uniforms[ 'shaderFocus' ].value = 0;
-			this.postprocessing.bokeh_uniforms[ 'fstop' ].value = 2.8;
-			this.postprocessing.bokeh_uniforms[ 'showFocus' ].value = 1;
-			this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = 0.1; //console.log( this.postprocessing.bokeh_uniforms[ "focalDepth" ].value );
-
-			this.postprocessing.bokeh_uniforms[ 'znear' ].value = this.near;
-			this.postprocessing.bokeh_uniforms[ 'zfar' ].value = this.near;
-			this.postprocessing.bokeh_uniforms[ 'textureWidth' ].value = window.innerWidth;
-			this.postprocessing.bokeh_uniforms[ 'textureHeight' ].value = window.innerHeight;
-			this.postprocessing.materialBokeh = new THREE.ShaderMaterial( {
-				uniforms: this.postprocessing.bokeh_uniforms,
-				vertexShader: bokeh_shader.vertexShader,
-				fragmentShader: bokeh_shader.fragmentShader,
-				defines: {
-					RINGS: this.shaderSettings.rings,
-					SAMPLES: this.shaderSettings.samples,
-					DEPTH_PACKING: 1
-				}
-			} );
-			this.postprocessing.quad = new THREE.Mesh( new THREE.PlaneGeometry( window.innerWidth, window.innerHeight ), this.postprocessing.materialBokeh );
-			this.postprocessing.quad.position.z = - 500;
-			this.postprocessing.scene.add( this.postprocessing.quad );
+		initPostProcessing() {
+
+			if ( this.postprocessing.enabled ) {
+
+				this.postprocessing.scene = new THREE.Scene();
+				this.postprocessing.camera = new THREE.OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2, window.innerHeight / 2, window.innerHeight / - 2, - 10000, 10000 );
+				this.postprocessing.scene.add( this.postprocessing.camera );
+				const pars = {
+					minFilter: THREE.LinearFilter,
+					magFilter: THREE.LinearFilter,
+					format: THREE.RGBFormat
+				};
+				this.postprocessing.rtTextureDepth = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );
+				this.postprocessing.rtTextureColor = new THREE.WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );
+				const bokeh_shader = THREE.BokehShader;
+				this.postprocessing.bokeh_uniforms = THREE.UniformsUtils.clone( bokeh_shader.uniforms );
+				this.postprocessing.bokeh_uniforms[ 'tColor' ].value = this.postprocessing.rtTextureColor.texture;
+				this.postprocessing.bokeh_uniforms[ 'tDepth' ].value = this.postprocessing.rtTextureDepth.texture;
+				this.postprocessing.bokeh_uniforms[ 'manualdof' ].value = 0;
+				this.postprocessing.bokeh_uniforms[ 'shaderFocus' ].value = 0;
+				this.postprocessing.bokeh_uniforms[ 'fstop' ].value = 2.8;
+				this.postprocessing.bokeh_uniforms[ 'showFocus' ].value = 1;
+				this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = 0.1; //console.log( this.postprocessing.bokeh_uniforms[ "focalDepth" ].value );
+
+				this.postprocessing.bokeh_uniforms[ 'znear' ].value = this.near;
+				this.postprocessing.bokeh_uniforms[ 'zfar' ].value = this.near;
+				this.postprocessing.bokeh_uniforms[ 'textureWidth' ].value = window.innerWidth;
+				this.postprocessing.bokeh_uniforms[ 'textureHeight' ].value = window.innerHeight;
+				this.postprocessing.materialBokeh = new THREE.ShaderMaterial( {
+					uniforms: this.postprocessing.bokeh_uniforms,
+					vertexShader: bokeh_shader.vertexShader,
+					fragmentShader: bokeh_shader.fragmentShader,
+					defines: {
+						RINGS: this.shaderSettings.rings,
+						SAMPLES: this.shaderSettings.samples,
+						DEPTH_PACKING: 1
+					}
+				} );
+				this.postprocessing.quad = new THREE.Mesh( new THREE.PlaneGeometry( window.innerWidth, window.innerHeight ), this.postprocessing.materialBokeh );
+				this.postprocessing.quad.position.z = - 500;
+				this.postprocessing.scene.add( this.postprocessing.quad );
+
+			}
 
 		}
 
-	};
+		renderCinematic( scene, renderer ) {
 
-	CinematicCamera.prototype.renderCinematic = function ( scene, renderer ) {
+			if ( this.postprocessing.enabled ) {
 
-		if ( this.postprocessing.enabled ) {
+				const currentRenderTarget = renderer.getRenderTarget();
+				renderer.clear(); // Render scene into texture
 
-			var currentRenderTarget = renderer.getRenderTarget();
-			renderer.clear(); // Render scene into texture
+				scene.overrideMaterial = null;
+				renderer.setRenderTarget( this.postprocessing.rtTextureColor );
+				renderer.clear();
+				renderer.render( scene, this ); // Render depth into texture
 
-			scene.overrideMaterial = null;
-			renderer.setRenderTarget( this.postprocessing.rtTextureColor );
-			renderer.clear();
-			renderer.render( scene, this ); // Render depth into texture
+				scene.overrideMaterial = this.materialDepth;
+				renderer.setRenderTarget( this.postprocessing.rtTextureDepth );
+				renderer.clear();
+				renderer.render( scene, this ); // Render bokeh composite
 
-			scene.overrideMaterial = this.materialDepth;
-			renderer.setRenderTarget( this.postprocessing.rtTextureDepth );
-			renderer.clear();
-			renderer.render( scene, this ); // Render bokeh composite
+				renderer.setRenderTarget( null );
+				renderer.render( this.postprocessing.scene, this.postprocessing.camera );
+				renderer.setRenderTarget( currentRenderTarget );
 
-			renderer.setRenderTarget( null );
-			renderer.render( this.postprocessing.scene, this.postprocessing.camera );
-			renderer.setRenderTarget( currentRenderTarget );
+			}
 
 		}
 
-	};
+	}
 
 	THREE.CinematicCamera = CinematicCamera;
 

+ 44 - 46
examples/js/geometries/BoxLineGeometry.js

@@ -1,61 +1,59 @@
 ( function () {
 
-	var BoxLineGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {
-
-		THREE.BufferGeometry.call( this );
-		width = width || 1;
-		height = height || 1;
-		depth = depth || 1;
-		widthSegments = Math.floor( widthSegments ) || 1;
-		heightSegments = Math.floor( heightSegments ) || 1;
-		depthSegments = Math.floor( depthSegments ) || 1;
-		var widthHalf = width / 2;
-		var heightHalf = height / 2;
-		var depthHalf = depth / 2;
-		var segmentWidth = width / widthSegments;
-		var segmentHeight = height / heightSegments;
-		var segmentDepth = depth / depthSegments;
-		var vertices = [];
-		var x = - widthHalf,
-			y = - heightHalf,
-			z = - depthHalf;
-
-		for ( var i = 0; i <= widthSegments; i ++ ) {
-
-			vertices.push( x, - heightHalf, - depthHalf, x, heightHalf, - depthHalf );
-			vertices.push( x, heightHalf, - depthHalf, x, heightHalf, depthHalf );
-			vertices.push( x, heightHalf, depthHalf, x, - heightHalf, depthHalf );
-			vertices.push( x, - heightHalf, depthHalf, x, - heightHalf, - depthHalf );
-			x += segmentWidth;
+	class BoxLineGeometry extends THREE.BufferGeometry {
 
-		}
+		constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
 
-		for ( var i = 0; i <= heightSegments; i ++ ) {
+			super();
+			widthSegments = Math.floor( widthSegments );
+			heightSegments = Math.floor( heightSegments );
+			depthSegments = Math.floor( depthSegments );
+			const widthHalf = width / 2;
+			const heightHalf = height / 2;
+			const depthHalf = depth / 2;
+			const segmentWidth = width / widthSegments;
+			const segmentHeight = height / heightSegments;
+			const segmentDepth = depth / depthSegments;
+			const vertices = [];
+			let x = - widthHalf;
+			let y = - heightHalf;
+			let z = - depthHalf;
 
-			vertices.push( - widthHalf, y, - depthHalf, widthHalf, y, - depthHalf );
-			vertices.push( widthHalf, y, - depthHalf, widthHalf, y, depthHalf );
-			vertices.push( widthHalf, y, depthHalf, - widthHalf, y, depthHalf );
-			vertices.push( - widthHalf, y, depthHalf, - widthHalf, y, - depthHalf );
-			y += segmentHeight;
+			for ( let i = 0; i <= widthSegments; i ++ ) {
 
-		}
+				vertices.push( x, - heightHalf, - depthHalf, x, heightHalf, - depthHalf );
+				vertices.push( x, heightHalf, - depthHalf, x, heightHalf, depthHalf );
+				vertices.push( x, heightHalf, depthHalf, x, - heightHalf, depthHalf );
+				vertices.push( x, - heightHalf, depthHalf, x, - heightHalf, - depthHalf );
+				x += segmentWidth;
 
-		for ( var i = 0; i <= depthSegments; i ++ ) {
+			}
 
-			vertices.push( - widthHalf, - heightHalf, z, - widthHalf, heightHalf, z );
-			vertices.push( - widthHalf, heightHalf, z, widthHalf, heightHalf, z );
-			vertices.push( widthHalf, heightHalf, z, widthHalf, - heightHalf, z );
-			vertices.push( widthHalf, - heightHalf, z, - widthHalf, - heightHalf, z );
-			z += segmentDepth;
+			for ( let i = 0; i <= heightSegments; i ++ ) {
 
-		}
+				vertices.push( - widthHalf, y, - depthHalf, widthHalf, y, - depthHalf );
+				vertices.push( widthHalf, y, - depthHalf, widthHalf, y, depthHalf );
+				vertices.push( widthHalf, y, depthHalf, - widthHalf, y, depthHalf );
+				vertices.push( - widthHalf, y, depthHalf, - widthHalf, y, - depthHalf );
+				y += segmentHeight;
+
+			}
 
-		this.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
+			for ( let i = 0; i <= depthSegments; i ++ ) {
 
-	};
+				vertices.push( - widthHalf, - heightHalf, z, - widthHalf, heightHalf, z );
+				vertices.push( - widthHalf, heightHalf, z, widthHalf, heightHalf, z );
+				vertices.push( widthHalf, heightHalf, z, widthHalf, - heightHalf, z );
+				vertices.push( widthHalf, - heightHalf, z, - widthHalf, - heightHalf, z );
+				z += segmentDepth;
+
+			}
+
+			this.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
+
+		}
 
-	BoxLineGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
-	BoxLineGeometry.prototype.constructor = BoxLineGeometry;
+	}
 
 	THREE.BoxLineGeometry = BoxLineGeometry;
 

+ 25 - 24
examples/js/geometries/ConvexGeometry.js

@@ -1,46 +1,47 @@
 ( function () {
 
-	var ConvexGeometry = function ( points ) {
+	class ConvexGeometry extends THREE.BufferGeometry {
 
-		THREE.BufferGeometry.call( this ); // buffers
+		constructor( points ) {
 
-		var vertices = [];
-		var normals = [];
+			super(); // buffers
 
-		if ( THREE.ConvexHull === undefined ) {
+			const vertices = [];
+			const normals = [];
 
-			console.error( 'THREE.ConvexBufferGeometry: ConvexBufferGeometry relies on THREE.ConvexHull' );
+			if ( THREE.ConvexHull === undefined ) {
 
-		}
+				console.error( 'THREE.ConvexBufferGeometry: ConvexBufferGeometry relies on THREE.ConvexHull' );
+
+			}
 
-		var convexHull = new THREE.ConvexHull().setFromPoints( points ); // generate vertices and normals
+			const convexHull = new THREE.ConvexHull().setFromPoints( points ); // generate vertices and normals
 
-		var faces = convexHull.faces;
+			const faces = convexHull.faces;
 
-		for ( var i = 0; i < faces.length; i ++ ) {
+			for ( let i = 0; i < faces.length; i ++ ) {
 
-			var face = faces[ i ];
-			var edge = face.edge; // we move along a doubly-connected edge list to access all face points (see HalfEdge docs)
+				const face = faces[ i ];
+				let edge = face.edge; // we move along a doubly-connected edge list to access all face points (see HalfEdge docs)
 
-			do {
+				do {
 
-				var point = edge.head().point;
-				vertices.push( point.x, point.y, point.z );
-				normals.push( face.normal.x, face.normal.y, face.normal.z );
-				edge = edge.next;
+					const point = edge.head().point;
+					vertices.push( point.x, point.y, point.z );
+					normals.push( face.normal.x, face.normal.y, face.normal.z );
+					edge = edge.next;
 
-			} while ( edge !== face.edge );
+				} while ( edge !== face.edge );
 
-		} // build geometry
+			} // build geometry
 
 
-		this.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
-		this.setAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
+			this.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
+			this.setAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
 
-	};
+		}
 
-	ConvexGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
-	ConvexGeometry.prototype.constructor = ConvexGeometry;
+	}
 
 	THREE.ConvexGeometry = ConvexGeometry;
 

+ 183 - 178
examples/js/geometries/DecalGeometry.js

@@ -15,277 +15,282 @@
  *
  */
 
-	var DecalGeometry = function ( mesh, position, orientation, size ) {
+	class DecalGeometry extends THREE.BufferGeometry {
 
-		THREE.BufferGeometry.call( this ); // buffers
+		constructor( mesh, position, orientation, size ) {
 
-		var vertices = [];
-		var normals = [];
-		var uvs = []; // helpers
+			super(); // buffers
 
-		var plane = new THREE.Vector3(); // this matrix represents the transformation of the decal projector
+			const vertices = [];
+			const normals = [];
+			const uvs = []; // helpers
 
-		var projectorMatrix = new THREE.Matrix4();
-		projectorMatrix.makeRotationFromEuler( orientation );
-		projectorMatrix.setPosition( position );
-		var projectorMatrixInverse = new THREE.Matrix4();
-		projectorMatrixInverse.copy( projectorMatrix ).invert(); // generate buffers
+			const plane = new THREE.Vector3(); // this matrix represents the transformation of the decal projector
 
-		generate(); // build geometry
+			const projectorMatrix = new THREE.Matrix4();
+			projectorMatrix.makeRotationFromEuler( orientation );
+			projectorMatrix.setPosition( position );
+			const projectorMatrixInverse = new THREE.Matrix4();
+			projectorMatrixInverse.copy( projectorMatrix ).invert(); // generate buffers
 
-		this.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
-		this.setAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
-		this.setAttribute( 'uv', new THREE.Float32BufferAttribute( uvs, 2 ) );
+			generate(); // build geometry
 
-		function generate() {
+			this.setAttribute( 'position', new THREE.Float32BufferAttribute( vertices, 3 ) );
+			this.setAttribute( 'normal', new THREE.Float32BufferAttribute( normals, 3 ) );
+			this.setAttribute( 'uv', new THREE.Float32BufferAttribute( uvs, 2 ) );
 
-			var i;
-			var decalVertices = [];
-			var vertex = new THREE.Vector3();
-			var normal = new THREE.Vector3(); // handle different geometry types
+			function generate() {
 
-			if ( mesh.geometry.isGeometry === true ) {
+				let decalVertices = [];
+				const vertex = new THREE.Vector3();
+				const normal = new THREE.Vector3(); // handle different geometry types
 
-				console.error( 'THREE.DecalGeometry no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
-				return;
+				if ( mesh.geometry.isGeometry === true ) {
 
-			}
+					console.error( 'THREE.DecalGeometry no longer supports THREE.Geometry. Use THREE.BufferGeometry instead.' );
+					return;
 
-			var geometry = mesh.geometry;
-			var positionAttribute = geometry.attributes.position;
-			var normalAttribute = geometry.attributes.normal; // first, create an array of 'DecalVertex' objects
-			// three consecutive 'DecalVertex' objects represent a single face
-			//
-			// this data structure will be later used to perform the clipping
+				}
 
-			if ( geometry.index !== null ) {
+				const geometry = mesh.geometry;
+				const positionAttribute = geometry.attributes.position;
+				const normalAttribute = geometry.attributes.normal; // first, create an array of 'DecalVertex' objects
+				// three consecutive 'DecalVertex' objects represent a single face
+				//
+				// this data structure will be later used to perform the clipping
 
-				// indexed THREE.BufferGeometry
-				var index = geometry.index;
+				if ( geometry.index !== null ) {
 
-				for ( i = 0; i < index.count; i ++ ) {
+					// indexed THREE.BufferGeometry
+					const index = geometry.index;
 
-					vertex.fromBufferAttribute( positionAttribute, index.getX( i ) );
-					normal.fromBufferAttribute( normalAttribute, index.getX( i ) );
-					pushDecalVertex( decalVertices, vertex, normal );
+					for ( let i = 0; i < index.count; i ++ ) {
 
-				}
+						vertex.fromBufferAttribute( positionAttribute, index.getX( i ) );
+						normal.fromBufferAttribute( normalAttribute, index.getX( i ) );
+						pushDecalVertex( decalVertices, vertex, normal );
 
-			} else {
+					}
 
-				// non-indexed THREE.BufferGeometry
-				for ( i = 0; i < positionAttribute.count; i ++ ) {
+				} else {
 
-					vertex.fromBufferAttribute( positionAttribute, i );
-					normal.fromBufferAttribute( normalAttribute, i );
-					pushDecalVertex( decalVertices, vertex, normal );
+					// non-indexed THREE.BufferGeometry
+					for ( let i = 0; i < positionAttribute.count; i ++ ) {
 
-				}
+						vertex.fromBufferAttribute( positionAttribute, i );
+						normal.fromBufferAttribute( normalAttribute, i );
+						pushDecalVertex( decalVertices, vertex, normal );
+
+					}
+
+				} // second, clip the geometry so that it doesn't extend out from the projector
 
-			} // second, clip the geometry so that it doesn't extend out from the projector
 
+				decalVertices = clipGeometry( decalVertices, plane.set( 1, 0, 0 ) );
+				decalVertices = clipGeometry( decalVertices, plane.set( - 1, 0, 0 ) );
+				decalVertices = clipGeometry( decalVertices, plane.set( 0, 1, 0 ) );
+				decalVertices = clipGeometry( decalVertices, plane.set( 0, - 1, 0 ) );
+				decalVertices = clipGeometry( decalVertices, plane.set( 0, 0, 1 ) );
+				decalVertices = clipGeometry( decalVertices, plane.set( 0, 0, - 1 ) ); // third, generate final vertices, normals and uvs
 
-			decalVertices = clipGeometry( decalVertices, plane.set( 1, 0, 0 ) );
-			decalVertices = clipGeometry( decalVertices, plane.set( - 1, 0, 0 ) );
-			decalVertices = clipGeometry( decalVertices, plane.set( 0, 1, 0 ) );
-			decalVertices = clipGeometry( decalVertices, plane.set( 0, - 1, 0 ) );
-			decalVertices = clipGeometry( decalVertices, plane.set( 0, 0, 1 ) );
-			decalVertices = clipGeometry( decalVertices, plane.set( 0, 0, - 1 ) ); // third, generate final vertices, normals and uvs
+				for ( let i = 0; i < decalVertices.length; i ++ ) {
 
-			for ( i = 0; i < decalVertices.length; i ++ ) {
+					const decalVertex = decalVertices[ i ]; // create texture coordinates (we are still in projector space)
 
-				var decalVertex = decalVertices[ i ]; // create texture coordinates (we are still in projector space)
+					uvs.push( 0.5 + decalVertex.position.x / size.x, 0.5 + decalVertex.position.y / size.y ); // transform the vertex back to world space
 
-				uvs.push( 0.5 + decalVertex.position.x / size.x, 0.5 + decalVertex.position.y / size.y ); // transform the vertex back to world space
+					decalVertex.position.applyMatrix4( projectorMatrix ); // now create vertex and normal buffer data
 
-				decalVertex.position.applyMatrix4( projectorMatrix ); // now create vertex and normal buffer data
+					vertices.push( decalVertex.position.x, decalVertex.position.y, decalVertex.position.z );
+					normals.push( decalVertex.normal.x, decalVertex.normal.y, decalVertex.normal.z );
 
-				vertices.push( decalVertex.position.x, decalVertex.position.y, decalVertex.position.z );
-				normals.push( decalVertex.normal.x, decalVertex.normal.y, decalVertex.normal.z );
+				}
 
 			}
 
-		}
+			function pushDecalVertex( decalVertices, vertex, normal ) {
 
-		function pushDecalVertex( decalVertices, vertex, normal ) {
+				// transform the vertex to world space, then to projector space
+				vertex.applyMatrix4( mesh.matrixWorld );
+				vertex.applyMatrix4( projectorMatrixInverse );
+				normal.transformDirection( mesh.matrixWorld );
+				decalVertices.push( new DecalVertex( vertex.clone(), normal.clone() ) );
 
-			// transform the vertex to world space, then to projector space
-			vertex.applyMatrix4( mesh.matrixWorld );
-			vertex.applyMatrix4( projectorMatrixInverse );
-			normal.transformDirection( mesh.matrixWorld );
-			decalVertices.push( new DecalVertex( vertex.clone(), normal.clone() ) );
+			}
 
-		}
+			function clipGeometry( inVertices, plane ) {
 
-		function clipGeometry( inVertices, plane ) {
+				const outVertices = [];
+				const s = 0.5 * Math.abs( size.dot( plane ) ); // a single iteration clips one face,
+				// which consists of three consecutive 'DecalVertex' objects
 
-			var outVertices = [];
-			var s = 0.5 * Math.abs( size.dot( plane ) ); // a single iteration clips one face,
-			// which consists of three consecutive 'DecalVertex' objects
+				for ( let i = 0; i < inVertices.length; i += 3 ) {
 
-			for ( var i = 0; i < inVertices.length; i += 3 ) {
+					let total = 0;
+					let nV1;
+					let nV2;
+					let nV3;
+					let nV4;
+					const d1 = inVertices[ i + 0 ].position.dot( plane ) - s;
+					const d2 = inVertices[ i + 1 ].position.dot( plane ) - s;
+					const d3 = inVertices[ i + 2 ].position.dot( plane ) - s;
+					const v1Out = d1 > 0;
+					const v2Out = d2 > 0;
+					const v3Out = d3 > 0; // calculate, how many vertices of the face lie outside of the clipping plane
 
-				var v1Out,
-					v2Out,
-					v3Out,
-					total = 0;
-				var nV1, nV2, nV3, nV4;
-				var d1 = inVertices[ i + 0 ].position.dot( plane ) - s;
-				var d2 = inVertices[ i + 1 ].position.dot( plane ) - s;
-				var d3 = inVertices[ i + 2 ].position.dot( plane ) - s;
-				v1Out = d1 > 0;
-				v2Out = d2 > 0;
-				v3Out = d3 > 0; // calculate, how many vertices of the face lie outside of the clipping plane
+					total = ( v1Out ? 1 : 0 ) + ( v2Out ? 1 : 0 ) + ( v3Out ? 1 : 0 );
 
-				total = ( v1Out ? 1 : 0 ) + ( v2Out ? 1 : 0 ) + ( v3Out ? 1 : 0 );
+					switch ( total ) {
 
-				switch ( total ) {
+						case 0:
+						{
 
-					case 0:
-					{
+							// the entire face lies inside of the plane, no clipping needed
+							outVertices.push( inVertices[ i ] );
+							outVertices.push( inVertices[ i + 1 ] );
+							outVertices.push( inVertices[ i + 2 ] );
+							break;
 
-						// the entire face lies inside of the plane, no clipping needed
-						outVertices.push( inVertices[ i ] );
-						outVertices.push( inVertices[ i + 1 ] );
-						outVertices.push( inVertices[ i + 2 ] );
-						break;
+						}
 
-					}
+						case 1:
+						{
 
-					case 1:
-					{
+							// one vertex lies outside of the plane, perform clipping
+							if ( v1Out ) {
 
-						// one vertex lies outside of the plane, perform clipping
-						if ( v1Out ) {
+								nV1 = inVertices[ i + 1 ];
+								nV2 = inVertices[ i + 2 ];
+								nV3 = clip( inVertices[ i ], nV1, plane, s );
+								nV4 = clip( inVertices[ i ], nV2, plane, s );
 
-							nV1 = inVertices[ i + 1 ];
-							nV2 = inVertices[ i + 2 ];
-							nV3 = clip( inVertices[ i ], nV1, plane, s );
-							nV4 = clip( inVertices[ i ], nV2, plane, s );
+							}
 
-						}
+							if ( v2Out ) {
 
-						if ( v2Out ) {
+								nV1 = inVertices[ i ];
+								nV2 = inVertices[ i + 2 ];
+								nV3 = clip( inVertices[ i + 1 ], nV1, plane, s );
+								nV4 = clip( inVertices[ i + 1 ], nV2, plane, s );
+								outVertices.push( nV3 );
+								outVertices.push( nV2.clone() );
+								outVertices.push( nV1.clone() );
+								outVertices.push( nV2.clone() );
+								outVertices.push( nV3.clone() );
+								outVertices.push( nV4 );
+								break;
+
+							}
+
+							if ( v3Out ) {
+
+								nV1 = inVertices[ i ];
+								nV2 = inVertices[ i + 1 ];
+								nV3 = clip( inVertices[ i + 2 ], nV1, plane, s );
+								nV4 = clip( inVertices[ i + 2 ], nV2, plane, s );
+
+							}
 
-							nV1 = inVertices[ i ];
-							nV2 = inVertices[ i + 2 ];
-							nV3 = clip( inVertices[ i + 1 ], nV1, plane, s );
-							nV4 = clip( inVertices[ i + 1 ], nV2, plane, s );
-							outVertices.push( nV3 );
-							outVertices.push( nV2.clone() );
 							outVertices.push( nV1.clone() );
 							outVertices.push( nV2.clone() );
-							outVertices.push( nV3.clone() );
+							outVertices.push( nV3 );
 							outVertices.push( nV4 );
+							outVertices.push( nV3.clone() );
+							outVertices.push( nV2.clone() );
 							break;
 
 						}
 
-						if ( v3Out ) {
+						case 2:
+						{
 
-							nV1 = inVertices[ i ];
-							nV2 = inVertices[ i + 1 ];
-							nV3 = clip( inVertices[ i + 2 ], nV1, plane, s );
-							nV4 = clip( inVertices[ i + 2 ], nV2, plane, s );
+							// two vertices lies outside of the plane, perform clipping
+							if ( ! v1Out ) {
 
-						}
+								nV1 = inVertices[ i ].clone();
+								nV2 = clip( nV1, inVertices[ i + 1 ], plane, s );
+								nV3 = clip( nV1, inVertices[ i + 2 ], plane, s );
+								outVertices.push( nV1 );
+								outVertices.push( nV2 );
+								outVertices.push( nV3 );
 
-						outVertices.push( nV1.clone() );
-						outVertices.push( nV2.clone() );
-						outVertices.push( nV3 );
-						outVertices.push( nV4 );
-						outVertices.push( nV3.clone() );
-						outVertices.push( nV2.clone() );
-						break;
+							}
 
-					}
+							if ( ! v2Out ) {
 
-					case 2:
-					{
+								nV1 = inVertices[ i + 1 ].clone();
+								nV2 = clip( nV1, inVertices[ i + 2 ], plane, s );
+								nV3 = clip( nV1, inVertices[ i ], plane, s );
+								outVertices.push( nV1 );
+								outVertices.push( nV2 );
+								outVertices.push( nV3 );
 
-						// two vertices lies outside of the plane, perform clipping
-						if ( ! v1Out ) {
+							}
 
-							nV1 = inVertices[ i ].clone();
-							nV2 = clip( nV1, inVertices[ i + 1 ], plane, s );
-							nV3 = clip( nV1, inVertices[ i + 2 ], plane, s );
-							outVertices.push( nV1 );
-							outVertices.push( nV2 );
-							outVertices.push( nV3 );
+							if ( ! v3Out ) {
 
-						}
+								nV1 = inVertices[ i + 2 ].clone();
+								nV2 = clip( nV1, inVertices[ i ], plane, s );
+								nV3 = clip( nV1, inVertices[ i + 1 ], plane, s );
+								outVertices.push( nV1 );
+								outVertices.push( nV2 );
+								outVertices.push( nV3 );
 
-						if ( ! v2Out ) {
+							}
 
-							nV1 = inVertices[ i + 1 ].clone();
-							nV2 = clip( nV1, inVertices[ i + 2 ], plane, s );
-							nV3 = clip( nV1, inVertices[ i ], plane, s );
-							outVertices.push( nV1 );
-							outVertices.push( nV2 );
-							outVertices.push( nV3 );
+							break;
 
 						}
 
-						if ( ! v3Out ) {
+						case 3:
+						{
 
-							nV1 = inVertices[ i + 2 ].clone();
-							nV2 = clip( nV1, inVertices[ i ], plane, s );
-							nV3 = clip( nV1, inVertices[ i + 1 ], plane, s );
-							outVertices.push( nV1 );
-							outVertices.push( nV2 );
-							outVertices.push( nV3 );
+							// the entire face lies outside of the plane, so let's discard the corresponding vertices
+							break;
 
 						}
 
-						break;
-
-					}
-
-					case 3:
-					{
-
-						// the entire face lies outside of the plane, so let's discard the corresponding vertices
-						break;
-
 					}
 
 				}
 
-			}
+				return outVertices;
 
-			return outVertices;
+			}
 
-		}
+			function clip( v0, v1, p, s ) {
 
-		function clip( v0, v1, p, s ) {
+				const d0 = v0.position.dot( p ) - s;
+				const d1 = v1.position.dot( p ) - s;
+				const s0 = d0 / ( d0 - d1 );
+				const v = new DecalVertex( new THREE.Vector3( v0.position.x + s0 * ( v1.position.x - v0.position.x ), v0.position.y + s0 * ( v1.position.y - v0.position.y ), v0.position.z + s0 * ( v1.position.z - v0.position.z ) ), new THREE.Vector3( v0.normal.x + s0 * ( v1.normal.x - v0.normal.x ), v0.normal.y + s0 * ( v1.normal.y - v0.normal.y ), v0.normal.z + s0 * ( v1.normal.z - v0.normal.z ) ) ); // need to clip more values (texture coordinates)? do it this way:
+				// intersectpoint.value = a.value + s * ( b.value - a.value );
 
-			var d0 = v0.position.dot( p ) - s;
-			var d1 = v1.position.dot( p ) - s;
-			var s0 = d0 / ( d0 - d1 );
-			var v = new DecalVertex( new THREE.Vector3( v0.position.x + s0 * ( v1.position.x - v0.position.x ), v0.position.y + s0 * ( v1.position.y - v0.position.y ), v0.position.z + s0 * ( v1.position.z - v0.position.z ) ), new THREE.Vector3( v0.normal.x + s0 * ( v1.normal.x - v0.normal.x ), v0.normal.y + s0 * ( v1.normal.y - v0.normal.y ), v0.normal.z + s0 * ( v1.normal.z - v0.normal.z ) ) ); // need to clip more values (texture coordinates)? do it this way:
-			// intersectpoint.value = a.value + s * ( b.value - a.value );
+				return v;
 
-			return v;
+			}
 
 		}
 
-	};
+	} // helper
+
 
-	DecalGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
-	DecalGeometry.prototype.constructor = DecalGeometry; // helper
+	class DecalVertex {
 
-	var DecalVertex = function ( position, normal ) {
+		constructor( position, normal ) {
 
-		this.position = position;
-		this.normal = normal;
+			this.position = position;
+			this.normal = normal;
 
-	};
+		}
 
-	DecalVertex.prototype.clone = function () {
+		clone() {
 
-		return new this.constructor( this.position.clone(), this.normal.clone() );
+			return new this.constructor( this.position.clone(), this.normal.clone() );
+
+		}
 
-	};
+	}
 
 	THREE.DecalGeometry = DecalGeometry;
 	THREE.DecalVertex = DecalVertex;

+ 597 - 599
examples/js/geometries/LightningStrike.js

@@ -101,775 +101,773 @@
  *
 */
 
-	var LightningStrike = function ( rayParameters ) {
+	class LightningStrike extends THREE.BufferGeometry {
 
-		THREE.BufferGeometry.call( this );
-		this.type = 'LightningStrike'; // Set parameters, and set undefined parameters to default values
+		constructor( rayParameters = {} ) {
 
-		rayParameters = rayParameters || {};
-		this.init( LightningStrike.copyParameters( rayParameters, rayParameters ) ); // Creates and populates the mesh
+			super();
+			this.type = 'LightningStrike'; // Set parameters, and set undefined parameters to default values
 
-		this.createMesh();
+			this.init( LightningStrike.copyParameters( rayParameters, rayParameters ) ); // Creates and populates the mesh
 
-	};
+			this.createMesh();
 
-	LightningStrike.prototype = Object.create( THREE.BufferGeometry.prototype );
-	LightningStrike.prototype.constructor = LightningStrike;
-	LightningStrike.prototype.isLightningStrike = true; // Ray states
-
-	LightningStrike.RAY_INITIALIZED = 0;
-	LightningStrike.RAY_UNBORN = 1;
-	LightningStrike.RAY_PROPAGATING = 2;
-	LightningStrike.RAY_STEADY = 3;
-	LightningStrike.RAY_VANISHING = 4;
-	LightningStrike.RAY_EXTINGUISHED = 5;
-	LightningStrike.COS30DEG = Math.cos( 30 * Math.PI / 180 );
-	LightningStrike.SIN30DEG = Math.sin( 30 * Math.PI / 180 );
+		}
 
-	LightningStrike.createRandomGenerator = function () {
+		static createRandomGenerator() {
 
-		var numSeeds = 2053;
-		var seeds = [];
+			const numSeeds = 2053;
+			const seeds = [];
 
-		for ( var i = 0; i < numSeeds; i ++ ) {
+			for ( let i = 0; i < numSeeds; i ++ ) {
 
-			seeds.push( Math.random() );
+				seeds.push( Math.random() );
 
-		}
+			}
 
-		var generator = {
-			currentSeed: 0,
-			random: function () {
+			const generator = {
+				currentSeed: 0,
+				random: function () {
 
-				var value = seeds[ generator.currentSeed ];
-				generator.currentSeed = ( generator.currentSeed + 1 ) % numSeeds;
-				return value;
+					const value = seeds[ generator.currentSeed ];
+					generator.currentSeed = ( generator.currentSeed + 1 ) % numSeeds;
+					return value;
 
-			},
-			getSeed: function () {
+				},
+				getSeed: function () {
 
-				return generator.currentSeed / numSeeds;
+					return generator.currentSeed / numSeeds;
 
-			},
-			setSeed: function ( seed ) {
+				},
+				setSeed: function ( seed ) {
 
-				generator.currentSeed = Math.floor( seed * numSeeds ) % numSeeds;
+					generator.currentSeed = Math.floor( seed * numSeeds ) % numSeeds;
 
-			}
-		};
-		return generator;
+				}
+			};
+			return generator;
 
-	};
+		}
 
-	LightningStrike.copyParameters = function ( dest, source ) {
+		static copyParameters( dest = {}, source = {} ) {
 
-		source = source || {};
-		dest = dest || {};
+			const vecCopy = function ( v ) {
 
-		var vecCopy = function ( v ) {
+				if ( source === dest ) {
 
-			if ( source === dest ) {
+					return v;
 
-				return v;
+				} else {
 
-			} else {
+					return v.clone();
 
-				return v.clone();
+				}
 
-			}
+			};
 
-		};
+			dest.sourceOffset = source.sourceOffset !== undefined ? vecCopy( source.sourceOffset ) : new THREE.Vector3( 0, 100, 0 ), dest.destOffset = source.destOffset !== undefined ? vecCopy( source.destOffset ) : new THREE.Vector3( 0, 0, 0 ), dest.timeScale = source.timeScale !== undefined ? source.timeScale : 1, dest.roughness = source.roughness !== undefined ? source.roughness : 0.9, dest.straightness = source.straightness !== undefined ? source.straightness : 0.7, dest.up0 = source.up0 !== undefined ? vecCopy( source.up0 ) : new THREE.Vector3( 0, 0, 1 );
+			dest.up1 = source.up1 !== undefined ? vecCopy( source.up1 ) : new THREE.Vector3( 0, 0, 1 ), dest.radius0 = source.radius0 !== undefined ? source.radius0 : 1, dest.radius1 = source.radius1 !== undefined ? source.radius1 : 1, dest.radius0Factor = source.radius0Factor !== undefined ? source.radius0Factor : 0.5, dest.radius1Factor = source.radius1Factor !== undefined ? source.radius1Factor : 0.2, dest.minRadius = source.minRadius !== undefined ? source.minRadius : 0.2, // These parameters should not be changed after lightning creation. They can be changed but the ray will change its form abruptly:
+			dest.isEternal = source.isEternal !== undefined ? source.isEternal : source.birthTime === undefined || source.deathTime === undefined, dest.birthTime = source.birthTime, dest.deathTime = source.deathTime, dest.propagationTimeFactor = source.propagationTimeFactor !== undefined ? source.propagationTimeFactor : 0.1, dest.vanishingTimeFactor = source.vanishingTimeFactor !== undefined ? source.vanishingTimeFactor : 0.9, dest.subrayPeriod = source.subrayPeriod !== undefined ? source.subrayPeriod : 4, dest.subrayDutyCycle = source.subrayDutyCycle !== undefined ? source.subrayDutyCycle : 0.6; // These parameters cannot change after lightning creation:
 
-		dest.sourceOffset = source.sourceOffset !== undefined ? vecCopy( source.sourceOffset ) : new THREE.Vector3( 0, 100, 0 ), dest.destOffset = source.destOffset !== undefined ? vecCopy( source.destOffset ) : new THREE.Vector3( 0, 0, 0 ), dest.timeScale = source.timeScale !== undefined ? source.timeScale : 1, dest.roughness = source.roughness !== undefined ? source.roughness : 0.9, dest.straightness = source.straightness !== undefined ? source.straightness : 0.7, dest.up0 = source.up0 !== undefined ? vecCopy( source.up0 ) : new THREE.Vector3( 0, 0, 1 );
-		dest.up1 = source.up1 !== undefined ? vecCopy( source.up1 ) : new THREE.Vector3( 0, 0, 1 ), dest.radius0 = source.radius0 !== undefined ? source.radius0 : 1, dest.radius1 = source.radius1 !== undefined ? source.radius1 : 1, dest.radius0Factor = source.radius0Factor !== undefined ? source.radius0Factor : 0.5, dest.radius1Factor = source.radius1Factor !== undefined ? source.radius1Factor : 0.2, dest.minRadius = source.minRadius !== undefined ? source.minRadius : 0.2, // These parameters should not be changed after lightning creation. They can be changed but the ray will change its form abruptly:
-		dest.isEternal = source.isEternal !== undefined ? source.isEternal : source.birthTime === undefined || source.deathTime === undefined, dest.birthTime = source.birthTime, dest.deathTime = source.deathTime, dest.propagationTimeFactor = source.propagationTimeFactor !== undefined ? source.propagationTimeFactor : 0.1, dest.vanishingTimeFactor = source.vanishingTimeFactor !== undefined ? source.vanishingTimeFactor : 0.9, dest.subrayPeriod = source.subrayPeriod !== undefined ? source.subrayPeriod : 4, dest.subrayDutyCycle = source.subrayDutyCycle !== undefined ? source.subrayDutyCycle : 0.6; // These parameters cannot change after lightning creation:
+			dest.maxIterations = source.maxIterations !== undefined ? source.maxIterations : 9;
+			dest.isStatic = source.isStatic !== undefined ? source.isStatic : false;
+			dest.ramification = source.ramification !== undefined ? source.ramification : 5;
+			dest.maxSubrayRecursion = source.maxSubrayRecursion !== undefined ? source.maxSubrayRecursion : 3;
+			dest.recursionProbability = source.recursionProbability !== undefined ? source.recursionProbability : 0.6;
+			dest.generateUVs = source.generateUVs !== undefined ? source.generateUVs : false;
+			dest.randomGenerator = source.randomGenerator, dest.noiseSeed = source.noiseSeed, dest.onDecideSubrayCreation = source.onDecideSubrayCreation, dest.onSubrayCreation = source.onSubrayCreation;
+			return dest;
 
-		dest.maxIterations = source.maxIterations !== undefined ? source.maxIterations : 9;
-		dest.isStatic = source.isStatic !== undefined ? source.isStatic : false;
-		dest.ramification = source.ramification !== undefined ? source.ramification : 5;
-		dest.maxSubrayRecursion = source.maxSubrayRecursion !== undefined ? source.maxSubrayRecursion : 3;
-		dest.recursionProbability = source.recursionProbability !== undefined ? source.recursionProbability : 0.6;
-		dest.generateUVs = source.generateUVs !== undefined ? source.generateUVs : false;
-		dest.randomGenerator = source.randomGenerator, dest.noiseSeed = source.noiseSeed, dest.onDecideSubrayCreation = source.onDecideSubrayCreation, dest.onSubrayCreation = source.onSubrayCreation;
-		return dest;
+		}
 
-	};
+		update( time ) {
 
-	LightningStrike.prototype.update = function ( time ) {
+			if ( this.isStatic ) return;
 
-		if ( this.isStatic ) return;
+			if ( this.rayParameters.isEternal || this.rayParameters.birthTime <= time && time <= this.rayParameters.deathTime ) {
 
-		if ( this.rayParameters.isEternal || this.rayParameters.birthTime <= time && time <= this.rayParameters.deathTime ) {
+				this.updateMesh( time );
 
-			this.updateMesh( time );
+				if ( time < this.subrays[ 0 ].endPropagationTime ) {
 
-			if ( time < this.subrays[ 0 ].endPropagationTime ) {
+					this.state = LightningStrike.RAY_PROPAGATING;
 
-				this.state = LightningStrike.RAY_PROPAGATING;
+				} else if ( time > this.subrays[ 0 ].beginVanishingTime ) {
 
-			} else if ( time > this.subrays[ 0 ].beginVanishingTime ) {
+					this.state = LightningStrike.RAY_VANISHING;
 
-				this.state = LightningStrike.RAY_VANISHING;
+				} else {
 
-			} else {
+					this.state = LightningStrike.RAY_STEADY;
 
-				this.state = LightningStrike.RAY_STEADY;
+				}
 
-			}
+				this.visible = true;
 
-			this.visible = true;
+			} else {
 
-		} else {
+				this.visible = false;
 
-			this.visible = false;
+				if ( time < this.rayParameters.birthTime ) {
 
-			if ( time < this.rayParameters.birthTime ) {
+					this.state = LightningStrike.RAY_UNBORN;
 
-				this.state = LightningStrike.RAY_UNBORN;
+				} else {
 
-			} else {
+					this.state = LightningStrike.RAY_EXTINGUISHED;
 
-				this.state = LightningStrike.RAY_EXTINGUISHED;
+				}
 
 			}
 
 		}
 
-	};
+		init( rayParameters ) {
 
-	LightningStrike.prototype.init = function ( rayParameters ) {
+			// Init all the state from the parameters
+			this.rayParameters = rayParameters; // These parameters cannot change after lightning creation:
 
-		// Init all the state from the parameters
-		this.rayParameters = rayParameters; // These parameters cannot change after lightning creation:
+			this.maxIterations = rayParameters.maxIterations !== undefined ? Math.floor( rayParameters.maxIterations ) : 9;
+			rayParameters.maxIterations = this.maxIterations;
+			this.isStatic = rayParameters.isStatic !== undefined ? rayParameters.isStatic : false;
+			rayParameters.isStatic = this.isStatic;
+			this.ramification = rayParameters.ramification !== undefined ? Math.floor( rayParameters.ramification ) : 5;
+			rayParameters.ramification = this.ramification;
+			this.maxSubrayRecursion = rayParameters.maxSubrayRecursion !== undefined ? Math.floor( rayParameters.maxSubrayRecursion ) : 3;
+			rayParameters.maxSubrayRecursion = this.maxSubrayRecursion;
+			this.recursionProbability = rayParameters.recursionProbability !== undefined ? rayParameters.recursionProbability : 0.6;
+			rayParameters.recursionProbability = this.recursionProbability;
+			this.generateUVs = rayParameters.generateUVs !== undefined ? rayParameters.generateUVs : false;
+			rayParameters.generateUVs = this.generateUVs; // Random generator
 
-		this.maxIterations = rayParameters.maxIterations !== undefined ? Math.floor( rayParameters.maxIterations ) : 9;
-		rayParameters.maxIterations = this.maxIterations;
-		this.isStatic = rayParameters.isStatic !== undefined ? rayParameters.isStatic : false;
-		rayParameters.isStatic = this.isStatic;
-		this.ramification = rayParameters.ramification !== undefined ? Math.floor( rayParameters.ramification ) : 5;
-		rayParameters.ramification = this.ramification;
-		this.maxSubrayRecursion = rayParameters.maxSubrayRecursion !== undefined ? Math.floor( rayParameters.maxSubrayRecursion ) : 3;
-		rayParameters.maxSubrayRecursion = this.maxSubrayRecursion;
-		this.recursionProbability = rayParameters.recursionProbability !== undefined ? rayParameters.recursionProbability : 0.6;
-		rayParameters.recursionProbability = this.recursionProbability;
-		this.generateUVs = rayParameters.generateUVs !== undefined ? rayParameters.generateUVs : false;
-		rayParameters.generateUVs = this.generateUVs; // Random generator
+			if ( rayParameters.randomGenerator !== undefined ) {
 
-		if ( rayParameters.randomGenerator !== undefined ) {
+				this.randomGenerator = rayParameters.randomGenerator;
+				this.seedGenerator = rayParameters.randomGenerator;
 
-			this.randomGenerator = rayParameters.randomGenerator;
-			this.seedGenerator = rayParameters.randomGenerator;
+				if ( rayParameters.noiseSeed !== undefined ) {
 
-			if ( rayParameters.noiseSeed !== undefined ) {
+					this.seedGenerator.setSeed( rayParameters.noiseSeed );
 
-				this.seedGenerator.setSeed( rayParameters.noiseSeed );
+				}
 
-			}
+			} else {
 
-		} else {
+				this.randomGenerator = LightningStrike.createRandomGenerator();
+				this.seedGenerator = Math;
 
-			this.randomGenerator = LightningStrike.createRandomGenerator();
-			this.seedGenerator = Math;
+			} // Ray creation callbacks
 
-		} // Ray creation callbacks
 
+			if ( rayParameters.onDecideSubrayCreation !== undefined ) {
 
-		if ( rayParameters.onDecideSubrayCreation !== undefined ) {
+				this.onDecideSubrayCreation = rayParameters.onDecideSubrayCreation;
 
-			this.onDecideSubrayCreation = rayParameters.onDecideSubrayCreation;
+			} else {
 
-		} else {
+				this.createDefaultSubrayCreationCallbacks();
 
-			this.createDefaultSubrayCreationCallbacks();
+				if ( rayParameters.onSubrayCreation !== undefined ) {
 
-			if ( rayParameters.onSubrayCreation !== undefined ) {
+					this.onSubrayCreation = rayParameters.onSubrayCreation;
 
-				this.onSubrayCreation = rayParameters.onSubrayCreation;
+				}
 
-			}
+			} // Internal state
 
-		} // Internal state
 
+			this.state = LightningStrike.RAY_INITIALIZED;
+			this.maxSubrays = Math.ceil( 1 + Math.pow( this.ramification, Math.max( 0, this.maxSubrayRecursion - 1 ) ) );
+			rayParameters.maxSubrays = this.maxSubrays;
+			this.maxRaySegments = 2 * ( 1 << this.maxIterations );
+			this.subrays = [];
 
-		this.state = LightningStrike.RAY_INITIALIZED;
-		this.maxSubrays = Math.ceil( 1 + Math.pow( this.ramification, Math.max( 0, this.maxSubrayRecursion - 1 ) ) );
-		rayParameters.maxSubrays = this.maxSubrays;
-		this.maxRaySegments = 2 * ( 1 << this.maxIterations );
-		this.subrays = [];
+			for ( let i = 0; i < this.maxSubrays; i ++ ) {
 
-		for ( var i = 0; i < this.maxSubrays; i ++ ) {
+				this.subrays.push( this.createSubray() );
 
-			this.subrays.push( this.createSubray() );
+			}
 
-		}
+			this.raySegments = [];
 
-		this.raySegments = [];
+			for ( let i = 0; i < this.maxRaySegments; i ++ ) {
 
-		for ( var i = 0; i < this.maxRaySegments; i ++ ) {
+				this.raySegments.push( this.createSegment() );
+
+			}
 
-			this.raySegments.push( this.createSegment() );
+			this.time = 0;
+			this.timeFraction = 0;
+			this.currentSegmentCallback = null;
+			this.currentCreateTriangleVertices = this.generateUVs ? this.createTriangleVerticesWithUVs : this.createTriangleVerticesWithoutUVs;
+			this.numSubrays = 0;
+			this.currentSubray = null;
+			this.currentSegmentIndex = 0;
+			this.isInitialSegment = false;
+			this.subrayProbability = 0;
+			this.currentVertex = 0;
+			this.currentIndex = 0;
+			this.currentCoordinate = 0;
+			this.currentUVCoordinate = 0;
+			this.vertices = null;
+			this.uvs = null;
+			this.indices = null;
+			this.positionAttribute = null;
+			this.uvsAttribute = null;
+			this.simplexX = new THREE.SimplexNoise( this.seedGenerator );
+			this.simplexY = new THREE.SimplexNoise( this.seedGenerator );
+			this.simplexZ = new THREE.SimplexNoise( this.seedGenerator ); // Temp vectors
+
+			this.forwards = new THREE.Vector3();
+			this.forwardsFill = new THREE.Vector3();
+			this.side = new THREE.Vector3();
+			this.down = new THREE.Vector3();
+			this.middlePos = new THREE.Vector3();
+			this.middleLinPos = new THREE.Vector3();
+			this.newPos = new THREE.Vector3();
+			this.vPos = new THREE.Vector3();
+			this.cross1 = new THREE.Vector3();
 
 		}
 
-		this.time = 0;
-		this.timeFraction = 0;
-		this.currentSegmentCallback = null;
-		this.currentCreateTriangleVertices = this.generateUVs ? this.createTriangleVerticesWithUVs : this.createTriangleVerticesWithoutUVs;
-		this.numSubrays = 0;
-		this.currentSubray = null;
-		this.currentSegmentIndex = 0;
-		this.isInitialSegment = false;
-		this.subrayProbability = 0;
-		this.currentVertex = 0;
-		this.currentIndex = 0;
-		this.currentCoordinate = 0;
-		this.currentUVCoordinate = 0;
-		this.vertices = null;
-		this.uvs = null;
-		this.indices = null;
-		this.positionAttribute = null;
-		this.uvsAttribute = null;
-		this.simplexX = new THREE.SimplexNoise( this.seedGenerator );
-		this.simplexY = new THREE.SimplexNoise( this.seedGenerator );
-		this.simplexZ = new THREE.SimplexNoise( this.seedGenerator ); // Temp vectors
-
-		this.forwards = new THREE.Vector3();
-		this.forwardsFill = new THREE.Vector3();
-		this.side = new THREE.Vector3();
-		this.down = new THREE.Vector3();
-		this.middlePos = new THREE.Vector3();
-		this.middleLinPos = new THREE.Vector3();
-		this.newPos = new THREE.Vector3();
-		this.vPos = new THREE.Vector3();
-		this.cross1 = new THREE.Vector3();
-
-	};
-
-	LightningStrike.prototype.createMesh = function () {
-
-		var maxDrawableSegmentsPerSubRay = 1 << this.maxIterations;
-		var maxVerts = 3 * ( maxDrawableSegmentsPerSubRay + 1 ) * this.maxSubrays;
-		var maxIndices = 18 * maxDrawableSegmentsPerSubRay * this.maxSubrays;
-		this.vertices = new Float32Array( maxVerts * 3 );
-		this.indices = new Uint32Array( maxIndices );
-
-		if ( this.generateUVs ) {
-
-			this.uvs = new Float32Array( maxVerts * 2 );
-
-		} // Populate the mesh
-
-
-		this.fillMesh( 0 );
-		this.setIndex( new THREE.Uint32BufferAttribute( this.indices, 1 ) );
-		this.positionAttribute = new THREE.Float32BufferAttribute( this.vertices, 3 );
-		this.setAttribute( 'position', this.positionAttribute );
-
-		if ( this.generateUVs ) {
-
-			this.uvsAttribute = new THREE.Float32BufferAttribute( new Float32Array( this.uvs ), 2 );
-			this.setAttribute( 'uv', this.uvsAttribute );
+		createMesh() {
 
-		}
+			const maxDrawableSegmentsPerSubRay = 1 << this.maxIterations;
+			const maxVerts = 3 * ( maxDrawableSegmentsPerSubRay + 1 ) * this.maxSubrays;
+			const maxIndices = 18 * maxDrawableSegmentsPerSubRay * this.maxSubrays;
+			this.vertices = new Float32Array( maxVerts * 3 );
+			this.indices = new Uint32Array( maxIndices );
+
+			if ( this.generateUVs ) {
+
+				this.uvs = new Float32Array( maxVerts * 2 );
 
-		if ( ! this.isStatic ) {
+			} // Populate the mesh
 
-			this.index.usage = THREE.DynamicDrawUsage;
-			this.positionAttribute.usage = THREE.DynamicDrawUsage;
+
+			this.fillMesh( 0 );
+			this.setIndex( new THREE.Uint32BufferAttribute( this.indices, 1 ) );
+			this.positionAttribute = new THREE.Float32BufferAttribute( this.vertices, 3 );
+			this.setAttribute( 'position', this.positionAttribute );
 
 			if ( this.generateUVs ) {
 
-				this.uvsAttribute.usage = THREE.DynamicDrawUsage;
+				this.uvsAttribute = new THREE.Float32BufferAttribute( new Float32Array( this.uvs ), 2 );
+				this.setAttribute( 'uv', this.uvsAttribute );
 
 			}
 
-		} // Store buffers for later modification
+			if ( ! this.isStatic ) {
 
+				this.index.usage = THREE.DynamicDrawUsage;
+				this.positionAttribute.usage = THREE.DynamicDrawUsage;
 
-		this.vertices = this.positionAttribute.array;
-		this.indices = this.index.array;
+				if ( this.generateUVs ) {
 
-		if ( this.generateUVs ) {
+					this.uvsAttribute.usage = THREE.DynamicDrawUsage;
 
-			this.uvs = this.uvsAttribute.array;
+				}
 
-		}
+			} // Store buffers for later modification
 
-	};
 
-	LightningStrike.prototype.updateMesh = function ( time ) {
+			this.vertices = this.positionAttribute.array;
+			this.indices = this.index.array;
 
-		this.fillMesh( time );
-		this.drawRange.count = this.currentIndex;
-		this.index.needsUpdate = true;
-		this.positionAttribute.needsUpdate = true;
+			if ( this.generateUVs ) {
 
-		if ( this.generateUVs ) {
+				this.uvs = this.uvsAttribute.array;
 
-			this.uvsAttribute.needsUpdate = true;
+			}
 
 		}
 
-	};
+		updateMesh( time ) {
 
-	LightningStrike.prototype.fillMesh = function ( time ) {
+			this.fillMesh( time );
+			this.drawRange.count = this.currentIndex;
+			this.index.needsUpdate = true;
+			this.positionAttribute.needsUpdate = true;
 
-		var scope = this;
-		this.currentVertex = 0;
-		this.currentIndex = 0;
-		this.currentCoordinate = 0;
-		this.currentUVCoordinate = 0;
-		this.fractalRay( time, function fillVertices( segment ) {
+			if ( this.generateUVs ) {
 
-			var subray = scope.currentSubray;
+				this.uvsAttribute.needsUpdate = true;
 
-			if ( time < subray.birthTime ) {
+			}
 
-				//&& ( ! this.rayParameters.isEternal || scope.currentSubray.recursion > 0 ) ) {
-				return;
+		}
+
+		fillMesh( time ) {
 
-			} else if ( this.rayParameters.isEternal && scope.currentSubray.recursion == 0 ) {
+			const scope = this;
+			this.currentVertex = 0;
+			this.currentIndex = 0;
+			this.currentCoordinate = 0;
+			this.currentUVCoordinate = 0;
+			this.fractalRay( time, function fillVertices( segment ) {
 
-				// Eternal rays don't propagate nor vanish, but its subrays do
-				scope.createPrism( segment );
-				scope.onDecideSubrayCreation( segment, scope );
+				const subray = scope.currentSubray;
 
-			} else if ( time < subray.endPropagationTime ) {
+				if ( time < subray.birthTime ) {
 
-				if ( scope.timeFraction >= segment.fraction0 * subray.propagationTimeFactor ) {
+					//&& ( ! this.rayParameters.isEternal || scope.currentSubray.recursion > 0 ) ) {
+					return;
 
-					// Ray propagation has arrived to this segment
+				} else if ( this.rayParameters.isEternal && scope.currentSubray.recursion == 0 ) {
+
+					// Eternal rays don't propagate nor vanish, but its subrays do
 					scope.createPrism( segment );
 					scope.onDecideSubrayCreation( segment, scope );
 
-				}
+				} else if ( time < subray.endPropagationTime ) {
 
-			} else if ( time < subray.beginVanishingTime ) {
+					if ( scope.timeFraction >= segment.fraction0 * subray.propagationTimeFactor ) {
 
-				// Ray is steady (nor propagating nor vanishing)
-				scope.createPrism( segment );
-				scope.onDecideSubrayCreation( segment, scope );
+						// Ray propagation has arrived to this segment
+						scope.createPrism( segment );
+						scope.onDecideSubrayCreation( segment, scope );
 
-			} else {
+					}
 
-				if ( scope.timeFraction <= subray.vanishingTimeFactor + segment.fraction1 * ( 1 - subray.vanishingTimeFactor ) ) {
+				} else if ( time < subray.beginVanishingTime ) {
 
-					// Segment has not yet vanished
+					// Ray is steady (nor propagating nor vanishing)
 					scope.createPrism( segment );
+					scope.onDecideSubrayCreation( segment, scope );
+
+				} else {
+
+					if ( scope.timeFraction <= subray.vanishingTimeFactor + segment.fraction1 * ( 1 - subray.vanishingTimeFactor ) ) {
+
+						// Segment has not yet vanished
+						scope.createPrism( segment );
+
+					}
+
+					scope.onDecideSubrayCreation( segment, scope );
 
 				}
 
-				scope.onDecideSubrayCreation( segment, scope );
+			} );
 
-			}
+		}
+
+		addNewSubray( ) {
 
-		} );
+			return this.subrays[ this.numSubrays ++ ];
 
-	};
+		}
 
-	LightningStrike.prototype.addNewSubray = function ( ) {
+		initSubray( subray, rayParameters ) {
+
+			subray.pos0.copy( rayParameters.sourceOffset );
+			subray.pos1.copy( rayParameters.destOffset );
+			subray.up0.copy( rayParameters.up0 );
+			subray.up1.copy( rayParameters.up1 );
+			subray.radius0 = rayParameters.radius0;
+			subray.radius1 = rayParameters.radius1;
+			subray.birthTime = rayParameters.birthTime;
+			subray.deathTime = rayParameters.deathTime;
+			subray.timeScale = rayParameters.timeScale;
+			subray.roughness = rayParameters.roughness;
+			subray.straightness = rayParameters.straightness;
+			subray.propagationTimeFactor = rayParameters.propagationTimeFactor;
+			subray.vanishingTimeFactor = rayParameters.vanishingTimeFactor;
+			subray.maxIterations = this.maxIterations;
+			subray.seed = rayParameters.noiseSeed !== undefined ? rayParameters.noiseSeed : 0;
+			subray.recursion = 0;
 
-		return this.subrays[ this.numSubrays ++ ];
+		}
 
-	};
+		fractalRay( time, segmentCallback ) {
+
+			this.time = time;
+			this.currentSegmentCallback = segmentCallback;
+			this.numSubrays = 0; // Add the top level subray
+
+			this.initSubray( this.addNewSubray(), this.rayParameters ); // Process all subrays that are being generated until consuming all of them
+
+			for ( let subrayIndex = 0; subrayIndex < this.numSubrays; subrayIndex ++ ) {
+
+				const subray = this.subrays[ subrayIndex ];
+				this.currentSubray = subray;
+				this.randomGenerator.setSeed( subray.seed );
+				subray.endPropagationTime = THREE.MathUtils.lerp( subray.birthTime, subray.deathTime, subray.propagationTimeFactor );
+				subray.beginVanishingTime = THREE.MathUtils.lerp( subray.deathTime, subray.birthTime, 1 - subray.vanishingTimeFactor );
+				const random1 = this.randomGenerator.random;
+				subray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+				subray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+				this.timeFraction = ( time - subray.birthTime ) / ( subray.deathTime - subray.birthTime );
+				this.currentSegmentIndex = 0;
+				this.isInitialSegment = true;
+				const segment = this.getNewSegment();
+				segment.iteration = 0;
+				segment.pos0.copy( subray.pos0 );
+				segment.pos1.copy( subray.pos1 );
+				segment.linPos0.copy( subray.linPos0 );
+				segment.linPos1.copy( subray.linPos1 );
+				segment.up0.copy( subray.up0 );
+				segment.up1.copy( subray.up1 );
+				segment.radius0 = subray.radius0;
+				segment.radius1 = subray.radius1;
+				segment.fraction0 = 0;
+				segment.fraction1 = 1;
+				segment.positionVariationFactor = 1 - subray.straightness;
+				this.subrayProbability = this.ramification * Math.pow( this.recursionProbability, subray.recursion ) / ( 1 << subray.maxIterations );
+				this.fractalRayRecursive( segment );
 
-	LightningStrike.prototype.initSubray = function ( subray, rayParameters ) {
+			}
 
-		subray.pos0.copy( rayParameters.sourceOffset );
-		subray.pos1.copy( rayParameters.destOffset );
-		subray.up0.copy( rayParameters.up0 );
-		subray.up1.copy( rayParameters.up1 );
-		subray.radius0 = rayParameters.radius0;
-		subray.radius1 = rayParameters.radius1;
-		subray.birthTime = rayParameters.birthTime;
-		subray.deathTime = rayParameters.deathTime;
-		subray.timeScale = rayParameters.timeScale;
-		subray.roughness = rayParameters.roughness;
-		subray.straightness = rayParameters.straightness;
-		subray.propagationTimeFactor = rayParameters.propagationTimeFactor;
-		subray.vanishingTimeFactor = rayParameters.vanishingTimeFactor;
-		subray.maxIterations = this.maxIterations;
-		subray.seed = rayParameters.noiseSeed !== undefined ? rayParameters.noiseSeed : 0;
-		subray.recursion = 0;
+			this.currentSegmentCallback = null;
+			this.currentSubray = null;
 
-	};
+		}
 
-	LightningStrike.prototype.fractalRay = function ( time, segmentCallback ) {
+		fractalRayRecursive( segment ) {
 
-		this.time = time;
-		this.currentSegmentCallback = segmentCallback;
-		this.numSubrays = 0; // Add the top level subray
+			// Leave recursion condition
+			if ( segment.iteration >= this.currentSubray.maxIterations ) {
 
-		this.initSubray( this.addNewSubray(), this.rayParameters ); // Process all subrays that are being generated until consuming all of them
+				this.currentSegmentCallback( segment );
+				return;
 
-		for ( var subrayIndex = 0; subrayIndex < this.numSubrays; subrayIndex ++ ) {
+			} // Interpolation
 
-			var subray = this.subrays[ subrayIndex ];
-			this.currentSubray = subray;
-			this.randomGenerator.setSeed( subray.seed );
-			subray.endPropagationTime = THREE.MathUtils.lerp( subray.birthTime, subray.deathTime, subray.propagationTimeFactor );
-			subray.beginVanishingTime = THREE.MathUtils.lerp( subray.deathTime, subray.birthTime, 1 - subray.vanishingTimeFactor );
-			var random1 = this.randomGenerator.random;
-			subray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
-			subray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
-			this.timeFraction = ( time - subray.birthTime ) / ( subray.deathTime - subray.birthTime );
-			this.currentSegmentIndex = 0;
-			this.isInitialSegment = true;
-			var segment = this.getNewSegment();
-			segment.iteration = 0;
-			segment.pos0.copy( subray.pos0 );
-			segment.pos1.copy( subray.pos1 );
-			segment.linPos0.copy( subray.linPos0 );
-			segment.linPos1.copy( subray.linPos1 );
-			segment.up0.copy( subray.up0 );
-			segment.up1.copy( subray.up1 );
-			segment.radius0 = subray.radius0;
-			segment.radius1 = subray.radius1;
-			segment.fraction0 = 0;
-			segment.fraction1 = 1;
-			segment.positionVariationFactor = 1 - subray.straightness;
-			this.subrayProbability = this.ramification * Math.pow( this.recursionProbability, subray.recursion ) / ( 1 << subray.maxIterations );
-			this.fractalRayRecursive( segment );
+
+			this.forwards.subVectors( segment.pos1, segment.pos0 );
+			let lForwards = this.forwards.length();
+
+			if ( lForwards < 0.000001 ) {
+
+				this.forwards.set( 0, 0, 0.01 );
+				lForwards = this.forwards.length();
+
+			}
+
+			const middleRadius = ( segment.radius0 + segment.radius1 ) * 0.5;
+			const middleFraction = ( segment.fraction0 + segment.fraction1 ) * 0.5;
+			const timeDimension = this.time * this.currentSubray.timeScale * Math.pow( 2, segment.iteration );
+			this.middlePos.lerpVectors( segment.pos0, segment.pos1, 0.5 );
+			this.middleLinPos.lerpVectors( segment.linPos0, segment.linPos1, 0.5 );
+			const p = this.middleLinPos; // Noise
+
+			this.newPos.set( this.simplexX.noise4d( p.x, p.y, p.z, timeDimension ), this.simplexY.noise4d( p.x, p.y, p.z, timeDimension ), this.simplexZ.noise4d( p.x, p.y, p.z, timeDimension ) );
+			this.newPos.multiplyScalar( segment.positionVariationFactor * lForwards );
+			this.newPos.add( this.middlePos ); // Recursion
+
+			const newSegment1 = this.getNewSegment();
+			newSegment1.pos0.copy( segment.pos0 );
+			newSegment1.pos1.copy( this.newPos );
+			newSegment1.linPos0.copy( segment.linPos0 );
+			newSegment1.linPos1.copy( this.middleLinPos );
+			newSegment1.up0.copy( segment.up0 );
+			newSegment1.up1.copy( segment.up1 );
+			newSegment1.radius0 = segment.radius0;
+			newSegment1.radius1 = middleRadius;
+			newSegment1.fraction0 = segment.fraction0;
+			newSegment1.fraction1 = middleFraction;
+			newSegment1.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
+			newSegment1.iteration = segment.iteration + 1;
+			const newSegment2 = this.getNewSegment();
+			newSegment2.pos0.copy( this.newPos );
+			newSegment2.pos1.copy( segment.pos1 );
+			newSegment2.linPos0.copy( this.middleLinPos );
+			newSegment2.linPos1.copy( segment.linPos1 );
+			this.cross1.crossVectors( segment.up0, this.forwards.normalize() );
+			newSegment2.up0.crossVectors( this.forwards, this.cross1 ).normalize();
+			newSegment2.up1.copy( segment.up1 );
+			newSegment2.radius0 = middleRadius;
+			newSegment2.radius1 = segment.radius1;
+			newSegment2.fraction0 = middleFraction;
+			newSegment2.fraction1 = segment.fraction1;
+			newSegment2.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
+			newSegment2.iteration = segment.iteration + 1;
+			this.fractalRayRecursive( newSegment1 );
+			this.fractalRayRecursive( newSegment2 );
 
 		}
 
-		this.currentSegmentCallback = null;
-		this.currentSubray = null;
+		createPrism( segment ) {
 
-	};
+			// Creates one triangular prism and its vertices at the segment
+			this.forwardsFill.subVectors( segment.pos1, segment.pos0 ).normalize();
 
-	LightningStrike.prototype.fractalRayRecursive = function ( segment ) {
+			if ( this.isInitialSegment ) {
 
-		// Leave recursion condition
-		if ( segment.iteration >= this.currentSubray.maxIterations ) {
+				this.currentCreateTriangleVertices( segment.pos0, segment.up0, this.forwardsFill, segment.radius0, 0 );
+				this.isInitialSegment = false;
 
-			this.currentSegmentCallback( segment );
-			return;
+			}
 
-		} // Interpolation
+			this.currentCreateTriangleVertices( segment.pos1, segment.up0, this.forwardsFill, segment.radius1, segment.fraction1 );
+			this.createPrismFaces();
 
+		}
 
-		this.forwards.subVectors( segment.pos1, segment.pos0 );
-		var lForwards = this.forwards.length();
+		createTriangleVerticesWithoutUVs( pos, up, forwards, radius ) {
+
+			// Create an equilateral triangle (only vertices)
+			this.side.crossVectors( up, forwards ).multiplyScalar( radius * LightningStrike.COS30DEG );
+			this.down.copy( up ).multiplyScalar( - radius * LightningStrike.SIN30DEG );
+			const p = this.vPos;
+			const v = this.vertices;
+			p.copy( pos ).sub( this.side ).add( this.down );
+			v[ this.currentCoordinate ++ ] = p.x;
+			v[ this.currentCoordinate ++ ] = p.y;
+			v[ this.currentCoordinate ++ ] = p.z;
+			p.copy( pos ).add( this.side ).add( this.down );
+			v[ this.currentCoordinate ++ ] = p.x;
+			v[ this.currentCoordinate ++ ] = p.y;
+			v[ this.currentCoordinate ++ ] = p.z;
+			p.copy( up ).multiplyScalar( radius ).add( pos );
+			v[ this.currentCoordinate ++ ] = p.x;
+			v[ this.currentCoordinate ++ ] = p.y;
+			v[ this.currentCoordinate ++ ] = p.z;
+			this.currentVertex += 3;
 
-		if ( lForwards < 0.000001 ) {
+		}
 
-			this.forwards.set( 0, 0, 0.01 );
-			lForwards = this.forwards.length();
+		createTriangleVerticesWithUVs( pos, up, forwards, radius, u ) {
+
+			// Create an equilateral triangle (only vertices)
+			this.side.crossVectors( up, forwards ).multiplyScalar( radius * LightningStrike.COS30DEG );
+			this.down.copy( up ).multiplyScalar( - radius * LightningStrike.SIN30DEG );
+			const p = this.vPos;
+			const v = this.vertices;
+			const uv = this.uvs;
+			p.copy( pos ).sub( this.side ).add( this.down );
+			v[ this.currentCoordinate ++ ] = p.x;
+			v[ this.currentCoordinate ++ ] = p.y;
+			v[ this.currentCoordinate ++ ] = p.z;
+			uv[ this.currentUVCoordinate ++ ] = u;
+			uv[ this.currentUVCoordinate ++ ] = 0;
+			p.copy( pos ).add( this.side ).add( this.down );
+			v[ this.currentCoordinate ++ ] = p.x;
+			v[ this.currentCoordinate ++ ] = p.y;
+			v[ this.currentCoordinate ++ ] = p.z;
+			uv[ this.currentUVCoordinate ++ ] = u;
+			uv[ this.currentUVCoordinate ++ ] = 0.5;
+			p.copy( up ).multiplyScalar( radius ).add( pos );
+			v[ this.currentCoordinate ++ ] = p.x;
+			v[ this.currentCoordinate ++ ] = p.y;
+			v[ this.currentCoordinate ++ ] = p.z;
+			uv[ this.currentUVCoordinate ++ ] = u;
+			uv[ this.currentUVCoordinate ++ ] = 1;
+			this.currentVertex += 3;
 
 		}
 
-		var middleRadius = ( segment.radius0 + segment.radius1 ) * 0.5;
-		var middleFraction = ( segment.fraction0 + segment.fraction1 ) * 0.5;
-		var timeDimension = this.time * this.currentSubray.timeScale * Math.pow( 2, segment.iteration );
-		this.middlePos.lerpVectors( segment.pos0, segment.pos1, 0.5 );
-		this.middleLinPos.lerpVectors( segment.linPos0, segment.linPos1, 0.5 );
-		var p = this.middleLinPos; // Noise
-
-		this.newPos.set( this.simplexX.noise4d( p.x, p.y, p.z, timeDimension ), this.simplexY.noise4d( p.x, p.y, p.z, timeDimension ), this.simplexZ.noise4d( p.x, p.y, p.z, timeDimension ) );
-		this.newPos.multiplyScalar( segment.positionVariationFactor * lForwards );
-		this.newPos.add( this.middlePos ); // Recursion
-
-		var newSegment1 = this.getNewSegment();
-		newSegment1.pos0.copy( segment.pos0 );
-		newSegment1.pos1.copy( this.newPos );
-		newSegment1.linPos0.copy( segment.linPos0 );
-		newSegment1.linPos1.copy( this.middleLinPos );
-		newSegment1.up0.copy( segment.up0 );
-		newSegment1.up1.copy( segment.up1 );
-		newSegment1.radius0 = segment.radius0;
-		newSegment1.radius1 = middleRadius;
-		newSegment1.fraction0 = segment.fraction0;
-		newSegment1.fraction1 = middleFraction;
-		newSegment1.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
-		newSegment1.iteration = segment.iteration + 1;
-		var newSegment2 = this.getNewSegment();
-		newSegment2.pos0.copy( this.newPos );
-		newSegment2.pos1.copy( segment.pos1 );
-		newSegment2.linPos0.copy( this.middleLinPos );
-		newSegment2.linPos1.copy( segment.linPos1 );
-		this.cross1.crossVectors( segment.up0, this.forwards.normalize() );
-		newSegment2.up0.crossVectors( this.forwards, this.cross1 ).normalize();
-		newSegment2.up1.copy( segment.up1 );
-		newSegment2.radius0 = middleRadius;
-		newSegment2.radius1 = segment.radius1;
-		newSegment2.fraction0 = middleFraction;
-		newSegment2.fraction1 = segment.fraction1;
-		newSegment2.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
-		newSegment2.iteration = segment.iteration + 1;
-		this.fractalRayRecursive( newSegment1 );
-		this.fractalRayRecursive( newSegment2 );
-
-	};
-
-	LightningStrike.prototype.createPrism = function ( segment ) {
-
-		// Creates one triangular prism and its vertices at the segment
-		this.forwardsFill.subVectors( segment.pos1, segment.pos0 ).normalize();
-
-		if ( this.isInitialSegment ) {
-
-			this.currentCreateTriangleVertices( segment.pos0, segment.up0, this.forwardsFill, segment.radius0, 0 );
-			this.isInitialSegment = false;
+		createPrismFaces( vertex
+			/*, index*/
+		) {
+
+			const indices = this.indices;
+			vertex = this.currentVertex - 6;
+			indices[ this.currentIndex ++ ] = vertex + 1;
+			indices[ this.currentIndex ++ ] = vertex + 2;
+			indices[ this.currentIndex ++ ] = vertex + 5;
+			indices[ this.currentIndex ++ ] = vertex + 1;
+			indices[ this.currentIndex ++ ] = vertex + 5;
+			indices[ this.currentIndex ++ ] = vertex + 4;
+			indices[ this.currentIndex ++ ] = vertex + 0;
+			indices[ this.currentIndex ++ ] = vertex + 1;
+			indices[ this.currentIndex ++ ] = vertex + 4;
+			indices[ this.currentIndex ++ ] = vertex + 0;
+			indices[ this.currentIndex ++ ] = vertex + 4;
+			indices[ this.currentIndex ++ ] = vertex + 3;
+			indices[ this.currentIndex ++ ] = vertex + 2;
+			indices[ this.currentIndex ++ ] = vertex + 0;
+			indices[ this.currentIndex ++ ] = vertex + 3;
+			indices[ this.currentIndex ++ ] = vertex + 2;
+			indices[ this.currentIndex ++ ] = vertex + 3;
+			indices[ this.currentIndex ++ ] = vertex + 5;
 
 		}
 
-		this.currentCreateTriangleVertices( segment.pos1, segment.up0, this.forwardsFill, segment.radius1, segment.fraction1 );
-		this.createPrismFaces();
-
-	};
-
-	LightningStrike.prototype.createTriangleVerticesWithoutUVs = function ( pos, up, forwards, radius ) {
-
-		// Create an equilateral triangle (only vertices)
-		this.side.crossVectors( up, forwards ).multiplyScalar( radius * LightningStrike.COS30DEG );
-		this.down.copy( up ).multiplyScalar( - radius * LightningStrike.SIN30DEG );
-		var p = this.vPos;
-		var v = this.vertices;
-		p.copy( pos ).sub( this.side ).add( this.down );
-		v[ this.currentCoordinate ++ ] = p.x;
-		v[ this.currentCoordinate ++ ] = p.y;
-		v[ this.currentCoordinate ++ ] = p.z;
-		p.copy( pos ).add( this.side ).add( this.down );
-		v[ this.currentCoordinate ++ ] = p.x;
-		v[ this.currentCoordinate ++ ] = p.y;
-		v[ this.currentCoordinate ++ ] = p.z;
-		p.copy( up ).multiplyScalar( radius ).add( pos );
-		v[ this.currentCoordinate ++ ] = p.x;
-		v[ this.currentCoordinate ++ ] = p.y;
-		v[ this.currentCoordinate ++ ] = p.z;
-		this.currentVertex += 3;
-
-	};
-
-	LightningStrike.prototype.createTriangleVerticesWithUVs = function ( pos, up, forwards, radius, u ) {
-
-		// Create an equilateral triangle (only vertices)
-		this.side.crossVectors( up, forwards ).multiplyScalar( radius * LightningStrike.COS30DEG );
-		this.down.copy( up ).multiplyScalar( - radius * LightningStrike.SIN30DEG );
-		var p = this.vPos;
-		var v = this.vertices;
-		var uv = this.uvs;
-		p.copy( pos ).sub( this.side ).add( this.down );
-		v[ this.currentCoordinate ++ ] = p.x;
-		v[ this.currentCoordinate ++ ] = p.y;
-		v[ this.currentCoordinate ++ ] = p.z;
-		uv[ this.currentUVCoordinate ++ ] = u;
-		uv[ this.currentUVCoordinate ++ ] = 0;
-		p.copy( pos ).add( this.side ).add( this.down );
-		v[ this.currentCoordinate ++ ] = p.x;
-		v[ this.currentCoordinate ++ ] = p.y;
-		v[ this.currentCoordinate ++ ] = p.z;
-		uv[ this.currentUVCoordinate ++ ] = u;
-		uv[ this.currentUVCoordinate ++ ] = 0.5;
-		p.copy( up ).multiplyScalar( radius ).add( pos );
-		v[ this.currentCoordinate ++ ] = p.x;
-		v[ this.currentCoordinate ++ ] = p.y;
-		v[ this.currentCoordinate ++ ] = p.z;
-		uv[ this.currentUVCoordinate ++ ] = u;
-		uv[ this.currentUVCoordinate ++ ] = 1;
-		this.currentVertex += 3;
-
-	};
-
-	LightningStrike.prototype.createPrismFaces = function ( vertex
-		/*, index*/
-	) {
-
-		var indices = this.indices;
-		var vertex = this.currentVertex - 6;
-		indices[ this.currentIndex ++ ] = vertex + 1;
-		indices[ this.currentIndex ++ ] = vertex + 2;
-		indices[ this.currentIndex ++ ] = vertex + 5;
-		indices[ this.currentIndex ++ ] = vertex + 1;
-		indices[ this.currentIndex ++ ] = vertex + 5;
-		indices[ this.currentIndex ++ ] = vertex + 4;
-		indices[ this.currentIndex ++ ] = vertex + 0;
-		indices[ this.currentIndex ++ ] = vertex + 1;
-		indices[ this.currentIndex ++ ] = vertex + 4;
-		indices[ this.currentIndex ++ ] = vertex + 0;
-		indices[ this.currentIndex ++ ] = vertex + 4;
-		indices[ this.currentIndex ++ ] = vertex + 3;
-		indices[ this.currentIndex ++ ] = vertex + 2;
-		indices[ this.currentIndex ++ ] = vertex + 0;
-		indices[ this.currentIndex ++ ] = vertex + 3;
-		indices[ this.currentIndex ++ ] = vertex + 2;
-		indices[ this.currentIndex ++ ] = vertex + 3;
-		indices[ this.currentIndex ++ ] = vertex + 5;
-
-	};
-
-	LightningStrike.prototype.createDefaultSubrayCreationCallbacks = function () {
-
-		var random1 = this.randomGenerator.random;
-
-		this.onDecideSubrayCreation = function ( segment, lightningStrike ) {
-
-			// Decide subrays creation at parent (sub)ray segment
-			var subray = lightningStrike.currentSubray;
-			var period = lightningStrike.rayParameters.subrayPeriod;
-			var dutyCycle = lightningStrike.rayParameters.subrayDutyCycle;
-			var phase0 = lightningStrike.rayParameters.isEternal && subray.recursion == 0 ? - random1() * period : THREE.MathUtils.lerp( subray.birthTime, subray.endPropagationTime, segment.fraction0 ) - random1() * period;
-			var phase = lightningStrike.time - phase0;
-			var currentCycle = Math.floor( phase / period );
-			var childSubraySeed = random1() * ( currentCycle + 1 );
-			var isActive = phase % period <= dutyCycle * period;
-			var probability = 0;
-
-			if ( isActive ) {
-
-				probability = lightningStrike.subrayProbability; // Distribution test: probability *= segment.fraction0 > 0.5 && segment.fraction0 < 0.9 ? 1 / 0.4 : 0;
+		createDefaultSubrayCreationCallbacks() {
 
-			}
+			const random1 = this.randomGenerator.random;
 
-			if ( subray.recursion < lightningStrike.maxSubrayRecursion && lightningStrike.numSubrays < lightningStrike.maxSubrays && random1() < probability ) {
+			this.onDecideSubrayCreation = function ( segment, lightningStrike ) {
 
-				var childSubray = lightningStrike.addNewSubray();
-				var parentSeed = lightningStrike.randomGenerator.getSeed();
-				childSubray.seed = childSubraySeed;
-				lightningStrike.randomGenerator.setSeed( childSubraySeed );
-				childSubray.recursion = subray.recursion + 1;
-				childSubray.maxIterations = Math.max( 1, subray.maxIterations - 1 );
-				childSubray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
-				childSubray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
-				childSubray.up0.copy( subray.up0 );
-				childSubray.up1.copy( subray.up1 );
-				childSubray.radius0 = segment.radius0 * lightningStrike.rayParameters.radius0Factor;
-				childSubray.radius1 = Math.min( lightningStrike.rayParameters.minRadius, segment.radius1 * lightningStrike.rayParameters.radius1Factor );
-				childSubray.birthTime = phase0 + currentCycle * period;
-				childSubray.deathTime = childSubray.birthTime + period * dutyCycle;
+				// Decide subrays creation at parent (sub)ray segment
+				const subray = lightningStrike.currentSubray;
+				const period = lightningStrike.rayParameters.subrayPeriod;
+				const dutyCycle = lightningStrike.rayParameters.subrayDutyCycle;
+				const phase0 = lightningStrike.rayParameters.isEternal && subray.recursion == 0 ? - random1() * period : THREE.MathUtils.lerp( subray.birthTime, subray.endPropagationTime, segment.fraction0 ) - random1() * period;
+				const phase = lightningStrike.time - phase0;
+				const currentCycle = Math.floor( phase / period );
+				const childSubraySeed = random1() * ( currentCycle + 1 );
+				const isActive = phase % period <= dutyCycle * period;
+				let probability = 0;
 
-				if ( ! lightningStrike.rayParameters.isEternal && subray.recursion == 0 ) {
+				if ( isActive ) {
 
-					childSubray.birthTime = Math.max( childSubray.birthTime, subray.birthTime );
-					childSubray.deathTime = Math.min( childSubray.deathTime, subray.deathTime );
+					probability = lightningStrike.subrayProbability; // Distribution test: probability *= segment.fraction0 > 0.5 && segment.fraction0 < 0.9 ? 1 / 0.4 : 0;
 
 				}
 
-				childSubray.timeScale = subray.timeScale * 2;
-				childSubray.roughness = subray.roughness;
-				childSubray.straightness = subray.straightness;
-				childSubray.propagationTimeFactor = subray.propagationTimeFactor;
-				childSubray.vanishingTimeFactor = subray.vanishingTimeFactor;
-				lightningStrike.onSubrayCreation( segment, subray, childSubray, lightningStrike );
-				lightningStrike.randomGenerator.setSeed( parentSeed );
+				if ( subray.recursion < lightningStrike.maxSubrayRecursion && lightningStrike.numSubrays < lightningStrike.maxSubrays && random1() < probability ) {
+
+					const childSubray = lightningStrike.addNewSubray();
+					const parentSeed = lightningStrike.randomGenerator.getSeed();
+					childSubray.seed = childSubraySeed;
+					lightningStrike.randomGenerator.setSeed( childSubraySeed );
+					childSubray.recursion = subray.recursion + 1;
+					childSubray.maxIterations = Math.max( 1, subray.maxIterations - 1 );
+					childSubray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+					childSubray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+					childSubray.up0.copy( subray.up0 );
+					childSubray.up1.copy( subray.up1 );
+					childSubray.radius0 = segment.radius0 * lightningStrike.rayParameters.radius0Factor;
+					childSubray.radius1 = Math.min( lightningStrike.rayParameters.minRadius, segment.radius1 * lightningStrike.rayParameters.radius1Factor );
+					childSubray.birthTime = phase0 + currentCycle * period;
+					childSubray.deathTime = childSubray.birthTime + period * dutyCycle;
+
+					if ( ! lightningStrike.rayParameters.isEternal && subray.recursion == 0 ) {
+
+						childSubray.birthTime = Math.max( childSubray.birthTime, subray.birthTime );
+						childSubray.deathTime = Math.min( childSubray.deathTime, subray.deathTime );
+
+					}
+
+					childSubray.timeScale = subray.timeScale * 2;
+					childSubray.roughness = subray.roughness;
+					childSubray.straightness = subray.straightness;
+					childSubray.propagationTimeFactor = subray.propagationTimeFactor;
+					childSubray.vanishingTimeFactor = subray.vanishingTimeFactor;
+					lightningStrike.onSubrayCreation( segment, subray, childSubray, lightningStrike );
+					lightningStrike.randomGenerator.setSeed( parentSeed );
 
-			}
+				}
+
+			};
+
+			const vec1Pos = new THREE.Vector3();
+			const vec2Forward = new THREE.Vector3();
+			const vec3Side = new THREE.Vector3();
+			const vec4Up = new THREE.Vector3();
+
+			this.onSubrayCreation = function ( segment, parentSubray, childSubray, lightningStrike ) {
+
+				// Decide childSubray origin and destination positions (pos0 and pos1) and possibly other properties of childSubray
+				// Just use the default cone position generator
+				lightningStrike.subrayCylinderPosition( segment, parentSubray, childSubray, 0.5, 0.6, 0.2 );
+
+			};
+
+			this.subrayConePosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
+
+				// Sets childSubray pos0 and pos1 in a cone
+				childSubray.pos0.copy( segment.pos0 );
+				vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
+				vec2Forward.copy( vec1Pos ).normalize();
+				vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( random1() * heightFactor ) );
+				const length = vec1Pos.length();
+				vec3Side.crossVectors( parentSubray.up0, vec2Forward );
+				const angle = 2 * Math.PI * random1();
+				vec3Side.multiplyScalar( Math.cos( angle ) );
+				vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin( angle ) );
+				childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
+
+			};
+
+			this.subrayCylinderPosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
+
+				// Sets childSubray pos0 and pos1 in a cylinder
+				childSubray.pos0.copy( segment.pos0 );
+				vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
+				vec2Forward.copy( vec1Pos ).normalize();
+				vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( ( 2 * random1() - 1 ) * heightFactor ) );
+				const length = vec1Pos.length();
+				vec3Side.crossVectors( parentSubray.up0, vec2Forward );
+				const angle = 2 * Math.PI * random1();
+				vec3Side.multiplyScalar( Math.cos( angle ) );
+				vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin( angle ) );
+				childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
+
+			};
 
-		};
-
-		var vec1Pos = new THREE.Vector3();
-		var vec2Forward = new THREE.Vector3();
-		var vec3Side = new THREE.Vector3();
-		var vec4Up = new THREE.Vector3();
-
-		this.onSubrayCreation = function ( segment, parentSubray, childSubray, lightningStrike ) {
-
-			// Decide childSubray origin and destination positions (pos0 and pos1) and possibly other properties of childSubray
-			// Just use the default cone position generator
-			lightningStrike.subrayCylinderPosition( segment, parentSubray, childSubray, 0.5, 0.6, 0.2 );
-
-		};
-
-		this.subrayConePosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
-
-			// Sets childSubray pos0 and pos1 in a cone
-			childSubray.pos0.copy( segment.pos0 );
-			vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
-			vec2Forward.copy( vec1Pos ).normalize();
-			vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( random1() * heightFactor ) );
-			var length = vec1Pos.length();
-			vec3Side.crossVectors( parentSubray.up0, vec2Forward );
-			var angle = 2 * Math.PI * random1();
-			vec3Side.multiplyScalar( Math.cos( angle ) );
-			vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin( angle ) );
-			childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
-
-		};
-
-		this.subrayCylinderPosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
-
-			// Sets childSubray pos0 and pos1 in a cylinder
-			childSubray.pos0.copy( segment.pos0 );
-			vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
-			vec2Forward.copy( vec1Pos ).normalize();
-			vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( ( 2 * random1() - 1 ) * heightFactor ) );
-			var length = vec1Pos.length();
-			vec3Side.crossVectors( parentSubray.up0, vec2Forward );
-			var angle = 2 * Math.PI * random1();
-			vec3Side.multiplyScalar( Math.cos( angle ) );
-			vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin( angle ) );
-			childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
-
-		};
-
-	};
-
-	LightningStrike.prototype.createSubray = function () {
-
-		return {
-			seed: 0,
-			maxIterations: 0,
-			recursion: 0,
-			pos0: new THREE.Vector3(),
-			pos1: new THREE.Vector3(),
-			linPos0: new THREE.Vector3(),
-			linPos1: new THREE.Vector3(),
-			up0: new THREE.Vector3(),
-			up1: new THREE.Vector3(),
-			radius0: 0,
-			radius1: 0,
-			birthTime: 0,
-			deathTime: 0,
-			timeScale: 0,
-			roughness: 0,
-			straightness: 0,
-			propagationTimeFactor: 0,
-			vanishingTimeFactor: 0,
-			endPropagationTime: 0,
-			beginVanishingTime: 0
-		};
-
-	};
-
-	LightningStrike.prototype.createSegment = function () {
-
-		return {
-			iteration: 0,
-			pos0: new THREE.Vector3(),
-			pos1: new THREE.Vector3(),
-			linPos0: new THREE.Vector3(),
-			linPos1: new THREE.Vector3(),
-			up0: new THREE.Vector3(),
-			up1: new THREE.Vector3(),
-			radius0: 0,
-			radius1: 0,
-			fraction0: 0,
-			fraction1: 0,
-			positionVariationFactor: 0
-		};
-
-	};
-
-	LightningStrike.prototype.getNewSegment = function () {
-
-		return this.raySegments[ this.currentSegmentIndex ++ ];
-
-	};
-
-	LightningStrike.prototype.copy = function ( source ) {
-
-		THREE.BufferGeometry.prototype.copy.call( this, source );
-		this.init( LightningStrike.copyParameters( {}, source.rayParameters ) );
-		return this;
-
-	};
-
-	LightningStrike.prototype.clone = function () {
-
-		return new this.constructor( LightningStrike.copyParameters( {}, this.rayParameters ) );
-
-	};
+		}
+
+		createSubray() {
+
+			return {
+				seed: 0,
+				maxIterations: 0,
+				recursion: 0,
+				pos0: new THREE.Vector3(),
+				pos1: new THREE.Vector3(),
+				linPos0: new THREE.Vector3(),
+				linPos1: new THREE.Vector3(),
+				up0: new THREE.Vector3(),
+				up1: new THREE.Vector3(),
+				radius0: 0,
+				radius1: 0,
+				birthTime: 0,
+				deathTime: 0,
+				timeScale: 0,
+				roughness: 0,
+				straightness: 0,
+				propagationTimeFactor: 0,
+				vanishingTimeFactor: 0,
+				endPropagationTime: 0,
+				beginVanishingTime: 0
+			};
+
+		}
+
+		createSegment() {
+
+			return {
+				iteration: 0,
+				pos0: new THREE.Vector3(),
+				pos1: new THREE.Vector3(),
+				linPos0: new THREE.Vector3(),
+				linPos1: new THREE.Vector3(),
+				up0: new THREE.Vector3(),
+				up1: new THREE.Vector3(),
+				radius0: 0,
+				radius1: 0,
+				fraction0: 0,
+				fraction1: 0,
+				positionVariationFactor: 0
+			};
+
+		}
+
+		getNewSegment() {
+
+			return this.raySegments[ this.currentSegmentIndex ++ ];
+
+		}
+
+		copy( source ) {
+
+			super.copy( source );
+			this.init( LightningStrike.copyParameters( {}, source.rayParameters ) );
+			return this;
+
+		}
+
+		clone() {
+
+			return new this.constructor( LightningStrike.copyParameters( {}, this.rayParameters ) );
+
+		}
+
+	}
+
+	LightningStrike.prototype.isLightningStrike = true; // Ray states
+
+	LightningStrike.RAY_INITIALIZED = 0;
+	LightningStrike.RAY_UNBORN = 1;
+	LightningStrike.RAY_PROPAGATING = 2;
+	LightningStrike.RAY_STEADY = 3;
+	LightningStrike.RAY_VANISHING = 4;
+	LightningStrike.RAY_EXTINGUISHED = 5;
+	LightningStrike.COS30DEG = Math.cos( 30 * Math.PI / 180 );
+	LightningStrike.SIN30DEG = Math.sin( 30 * Math.PI / 180 );
 
 	THREE.LightningStrike = LightningStrike;
 

+ 99 - 105
examples/js/geometries/ParametricGeometries.js

@@ -4,13 +4,13 @@
  * Experimenting of primitive geometry creation using Surface Parametric equations
  */
 
-	var ParametricGeometries = {
+	const ParametricGeometries = {
 		klein: function ( v, u, target ) {
 
 			u *= Math.PI;
 			v *= 2 * Math.PI;
 			u = u * 2;
-			var x, y, z;
+			let x, z;
 
 			if ( u < Math.PI ) {
 
@@ -24,7 +24,7 @@
 
 			}
 
-			y = - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( v );
+			const y = - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( v );
 			target.set( x, y, z );
 
 		},
@@ -32,9 +32,9 @@
 
 			return function ( u, v, target ) {
 
-				var x = u * width;
-				var y = 0;
-				var z = v * height;
+				const x = u * width;
+				const y = 0;
+				const z = v * height;
 				target.set( x, y, z );
 
 			};
@@ -45,12 +45,11 @@
 			// flat mobius strip
 			// http://www.wolframalpha.com/input/?i=M%C3%B6bius+strip+parametric+equations&lk=1&a=ClashPrefs_*Surface.MoebiusStrip.SurfaceProperty.ParametricEquations-
 			u = u - 0.5;
-			var v = 2 * Math.PI * t;
-			var x, y, z;
-			var a = 2;
-			x = Math.cos( v ) * ( a + u * Math.cos( v / 2 ) );
-			y = Math.sin( v ) * ( a + u * Math.cos( v / 2 ) );
-			z = u * Math.sin( v / 2 );
+			const v = 2 * Math.PI * t;
+			const a = 2;
+			const x = Math.cos( v ) * ( a + u * Math.cos( v / 2 ) );
+			const y = Math.sin( v ) * ( a + u * Math.cos( v / 2 ) );
+			const z = u * Math.sin( v / 2 );
 			target.set( x, y, z );
 
 		},
@@ -60,14 +59,13 @@
 			u *= Math.PI;
 			t *= 2 * Math.PI;
 			u = u * 2;
-			var phi = u / 2;
-			var major = 2.25,
+			const phi = u / 2;
+			const major = 2.25,
 				a = 0.125,
 				b = 0.65;
-			var x, y, z;
-			x = a * Math.cos( t ) * Math.cos( phi ) - b * Math.sin( t ) * Math.sin( phi );
-			z = a * Math.cos( t ) * Math.sin( phi ) + b * Math.sin( t ) * Math.cos( phi );
-			y = ( major + x ) * Math.sin( u );
+			let x = a * Math.cos( t ) * Math.cos( phi ) - b * Math.sin( t ) * Math.sin( phi );
+			const z = a * Math.cos( t ) * Math.sin( phi ) + b * Math.sin( t ) * Math.cos( phi );
+			const y = ( major + x ) * Math.sin( u );
 			x = ( major + x ) * Math.cos( u );
 			target.set( x, y, z );
 
@@ -79,142 +77,138 @@
  *
  *********************************************/
 
-	ParametricGeometries.TubeGeometry = function ( path, segments, radius, segmentsRadius, closed ) {
+	ParametricGeometries.TubeGeometry = class TubeGeometry extends THREE.ParametricGeometry {
 
-		this.path = path;
-		this.segments = segments || 64;
-		this.radius = radius || 1;
-		this.segmentsRadius = segmentsRadius || 8;
-		this.closed = closed || false;
-		var scope = this,
-			numpoints = this.segments + 1;
-		var frames = path.computeFrenetFrames( segments, closed ),
-			tangents = frames.tangents,
-			normals = frames.normals,
-			binormals = frames.binormals; // proxy internals
+		constructor( path, segments = 64, radius = 1, segmentsRadius = 8, closed = false ) {
 
-		this.tangents = tangents;
-		this.normals = normals;
-		this.binormals = binormals;
-		var position = new THREE.Vector3();
+			const numpoints = segments + 1;
+			const frames = path.computeFrenetFrames( segments, closed ),
+				tangents = frames.tangents,
+				normals = frames.normals,
+				binormals = frames.binormals;
+			const position = new THREE.Vector3();
 
-		var ParametricTube = function ( u, v, target ) {
+			function ParametricTube( u, v, target ) {
 
-			v *= 2 * Math.PI;
-			var i = u * ( numpoints - 1 );
-			i = Math.floor( i );
-			path.getPointAt( u, position );
-			var normal = normals[ i ];
-			var binormal = binormals[ i ];
-			var cx = - scope.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
+				v *= 2 * Math.PI;
+				const i = Math.floor( u * ( numpoints - 1 ) );
+				path.getPointAt( u, position );
+				const normal = normals[ i ];
+				const binormal = binormals[ i ];
+				const cx = - radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
+
+				const cy = radius * Math.sin( v );
+				position.x += cx * normal.x + cy * binormal.x;
+				position.y += cx * normal.y + cy * binormal.y;
+				position.z += cx * normal.z + cy * binormal.z;
+				target.copy( position );
 
-			var cy = scope.radius * Math.sin( v );
-			position.x += cx * normal.x + cy * binormal.x;
-			position.y += cx * normal.y + cy * binormal.y;
-			position.z += cx * normal.z + cy * binormal.z;
-			target.copy( position );
+			}
 
-		};
+			super( ParametricTube, segments, segmentsRadius ); // proxy internals
 
-		THREE.ParametricGeometry.call( this, ParametricTube, segments, segmentsRadius );
+			this.tangents = tangents;
+			this.normals = normals;
+			this.binormals = binormals;
+			this.path = path;
+			this.segments = segments;
+			this.radius = radius;
+			this.segmentsRadius = segmentsRadius;
+			this.closed = closed;
 
-	};
+		}
 
-	ParametricGeometries.TubeGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
-	ParametricGeometries.TubeGeometry.prototype.constructor = ParametricGeometries.TubeGeometry;
+	};
 	/*********************************************
 	*
 	* Parametric Replacement for TorusKnotGeometry
 	*
 	*********************************************/
 
-	ParametricGeometries.TorusKnotGeometry = function ( radius, tube, segmentsT, segmentsR, p, q ) {
+	ParametricGeometries.TorusKnotGeometry = class TorusKnotGeometry extends ParametricGeometries.TubeGeometry {
 
-		this.radius = radius || 200;
-		this.tube = tube || 40;
-		this.segmentsT = segmentsT || 64;
-		this.segmentsR = segmentsR || 8;
-		this.p = p || 2;
-		this.q = q || 3;
+		constructor( radius = 200, tube = 40, segmentsT = 64, segmentsR = 8, p = 2, q = 3 ) {
 
-		function TorusKnotCurve() {
+			class TorusKnotCurve extends THREE.Curve {
 
-			THREE.Curve.call( this );
-
-		}
+				getPoint( t, optionalTarget = new THREE.Vector3() ) {
 
-		TorusKnotCurve.prototype = Object.create( THREE.Curve.prototype );
-		TorusKnotCurve.prototype.constructor = TorusKnotCurve;
+					const point = optionalTarget;
+					t *= Math.PI * 2;
+					const r = 0.5;
+					const x = ( 1 + r * Math.cos( q * t ) ) * Math.cos( p * t );
+					const y = ( 1 + r * Math.cos( q * t ) ) * Math.sin( p * t );
+					const z = r * Math.sin( q * t );
+					return point.set( x, y, z ).multiplyScalar( radius );
 
-		TorusKnotCurve.prototype.getPoint = function ( t, optionalTarget ) {
+				}
 
-			var point = optionalTarget || new THREE.Vector3();
-			t *= Math.PI * 2;
-			var r = 0.5;
-			var x = ( 1 + r * Math.cos( q * t ) ) * Math.cos( p * t );
-			var y = ( 1 + r * Math.cos( q * t ) ) * Math.sin( p * t );
-			var z = r * Math.sin( q * t );
-			return point.set( x, y, z ).multiplyScalar( radius );
+			}
 
-		};
+			const segments = segmentsT;
+			const radiusSegments = segmentsR;
+			const extrudePath = new TorusKnotCurve();
+			super( extrudePath, segments, tube, radiusSegments, true, false );
+			this.radius = radius;
+			this.tube = tube;
+			this.segmentsT = segmentsT;
+			this.segmentsR = segmentsR;
+			this.p = p;
+			this.q = q;
 
-		var segments = segmentsT;
-		var radiusSegments = segmentsR;
-		var extrudePath = new TorusKnotCurve();
-		ParametricGeometries.TubeGeometry.call( this, extrudePath, segments, tube, radiusSegments, true, false );
+		}
 
 	};
-
-	ParametricGeometries.TorusKnotGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
-	ParametricGeometries.TorusKnotGeometry.prototype.constructor = ParametricGeometries.TorusKnotGeometry;
 	/*********************************************
 	*
 	* Parametric Replacement for SphereGeometry
 	*
 	*********************************************/
 
-	ParametricGeometries.SphereGeometry = function ( size, u, v ) {
+	ParametricGeometries.SphereGeometry = class SphereGeometry extends THREE.ParametricGeometry {
 
-		function sphere( u, v, target ) {
+		constructor( size, u, v ) {
 
-			u *= Math.PI;
-			v *= 2 * Math.PI;
-			var x = size * Math.sin( u ) * Math.cos( v );
-			var y = size * Math.sin( u ) * Math.sin( v );
-			var z = size * Math.cos( u );
-			target.set( x, y, z );
+			function sphere( u, v, target ) {
 
-		}
+				u *= Math.PI;
+				v *= 2 * Math.PI;
+				var x = size * Math.sin( u ) * Math.cos( v );
+				var y = size * Math.sin( u ) * Math.sin( v );
+				var z = size * Math.cos( u );
+				target.set( x, y, z );
 
-		THREE.ParametricGeometry.call( this, sphere, u, v );
+			}
 
-	};
+			super( sphere, u, v );
 
-	ParametricGeometries.SphereGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
-	ParametricGeometries.SphereGeometry.prototype.constructor = ParametricGeometries.SphereGeometry;
+		}
+
+	};
 	/*********************************************
 	*
 	* Parametric Replacement for PlaneGeometry
 	*
 	*********************************************/
 
-	ParametricGeometries.PlaneGeometry = function ( width, depth, segmentsWidth, segmentsDepth ) {
+	ParametricGeometries.PlaneGeometry = class PlaneGeometry extends THREE.ParametricGeometry {
 
-		function plane( u, v, target ) {
+		constructor( width, depth, segmentsWidth, segmentsDepth ) {
 
-			var x = u * width;
-			var y = 0;
-			var z = v * depth;
-			target.set( x, y, z );
+			function plane( u, v, target ) {
 
-		}
+				const x = u * width;
+				const y = 0;
+				const z = v * depth;
+				target.set( x, y, z );
 
-		THREE.ParametricGeometry.call( this, plane, segmentsWidth, segmentsDepth );
+			}
 
-	};
+			super( plane, segmentsWidth, segmentsDepth );
 
-	ParametricGeometries.PlaneGeometry.prototype = Object.create( THREE.BufferGeometry.prototype );
-	ParametricGeometries.PlaneGeometry.prototype.constructor = ParametricGeometries.PlaneGeometry;
+		}
+
+	};
 
 	THREE.ParametricGeometries = ParametricGeometries;
 

+ 9 - 6
examples/js/geometries/RoundedBoxGeometry.js

@@ -1,6 +1,6 @@
 ( function () {
 
-	const tempNormal = new THREE.Vector3();
+	const _tempNormal = new THREE.Vector3();
 
 	function getUv( faceDirVector, normal, uvAxis, projectionAxis, radius, sideLength ) {
 
@@ -9,15 +9,18 @@
 		const centerLength = Math.max( sideLength - 2 * radius, 0 );
 		const halfArc = Math.PI / 4; // Get the vector projected onto the Y plane
 
-		tempNormal.copy( normal );
-		tempNormal[ projectionAxis ] = 0;
-		tempNormal.normalize(); // total amount of UV space alloted to a single arc
+		_tempNormal.copy( normal );
+
+		_tempNormal[ projectionAxis ] = 0;
+
+		_tempNormal.normalize(); // total amount of UV space alloted to a single arc
+
 
 		const arcUvRatio = 0.5 * totArcLength / ( totArcLength + centerLength ); // the distance along one arc the point is at
 
-		const arcAngleRatio = 1.0 - tempNormal.angleTo( faceDirVector ) / halfArc;
+		const arcAngleRatio = 1.0 - _tempNormal.angleTo( faceDirVector ) / halfArc;
 
-		if ( Math.sign( tempNormal[ uvAxis ] ) === 1 ) {
+		if ( Math.sign( _tempNormal[ uvAxis ] ) === 1 ) {
 
 			return arcAngleRatio * arcUvRatio;
 

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 16
examples/js/geometries/TeapotGeometry.js


+ 119 - 124
examples/jsm/cameras/CinematicCamera.js

@@ -10,208 +10,203 @@ import {
 	UniformsUtils,
 	WebGLRenderTarget
 } from '../../../build/three.module.js';
+
 import { BokehShader } from '../shaders/BokehShader2.js';
 import { BokehDepthShader } from '../shaders/BokehShader2.js';
 
-var CinematicCamera = function ( fov, aspect, near, far ) {
-
-	PerspectiveCamera.call( this, fov, aspect, near, far );
+class CinematicCamera extends PerspectiveCamera {
 
-	this.type = 'CinematicCamera';
+	constructor( fov, aspect, near, far ) {
 
-	this.postprocessing = { enabled: true };
-	this.shaderSettings = {
-		rings: 3,
-		samples: 4
-	};
+		super( fov, aspect, near, far );
 
-	var depthShader = BokehDepthShader;
+		this.type = 'CinematicCamera';
 
-	this.materialDepth = new ShaderMaterial( {
-		uniforms: depthShader.uniforms,
-		vertexShader: depthShader.vertexShader,
-		fragmentShader: depthShader.fragmentShader
-	} );
+		this.postprocessing = { enabled: true };
+		this.shaderSettings = {
+			rings: 3,
+			samples: 4
+		};
 
-	this.materialDepth.uniforms[ 'mNear' ].value = near;
-	this.materialDepth.uniforms[ 'mFar' ].value = far;
-
-	// In case of cinematicCamera, having a default lens set is important
-	this.setLens();
+		const depthShader = BokehDepthShader;
 
-	this.initPostProcessing();
+		this.materialDepth = new ShaderMaterial( {
+			uniforms: depthShader.uniforms,
+			vertexShader: depthShader.vertexShader,
+			fragmentShader: depthShader.fragmentShader
+		} );
 
-};
+		this.materialDepth.uniforms[ 'mNear' ].value = near;
+		this.materialDepth.uniforms[ 'mFar' ].value = far;
 
-CinematicCamera.prototype = Object.create( PerspectiveCamera.prototype );
-CinematicCamera.prototype.constructor = CinematicCamera;
+		// In case of cinematicCamera, having a default lens set is important
+		this.setLens();
 
+		this.initPostProcessing();
 
-// providing fnumber and coc(Circle of Confusion) as extra arguments
-CinematicCamera.prototype.setLens = function ( focalLength, filmGauge, fNumber, coc ) {
+	}
 
+	// providing fnumber and coc(Circle of Confusion) as extra arguments
 	// In case of cinematicCamera, having a default lens set is important
-	if ( focalLength === undefined ) focalLength = 35;
-	if ( filmGauge !== undefined ) this.filmGauge = filmGauge;
+	// if fnumber and coc are not provided, cinematicCamera tries to act as a basic PerspectiveCamera
+	setLens( focalLength = 35, filmGauge = 35, fNumber = 8, coc = 0.019 ) {
 
-	this.setFocalLength( focalLength );
+		this.filmGauge = filmGauge;
 
-	// if fnumber and coc are not provided, cinematicCamera tries to act as a basic PerspectiveCamera
-	if ( fNumber === undefined ) fNumber = 8;
-	if ( coc === undefined ) coc = 0.019;
+		this.setFocalLength( focalLength );
 
-	this.fNumber = fNumber;
-	this.coc = coc;
+		this.fNumber = fNumber;
+		this.coc = coc;
 
-	// fNumber is focalLength by aperture
-	this.aperture = focalLength / this.fNumber;
+		// fNumber is focalLength by aperture
+		this.aperture = focalLength / this.fNumber;
 
-	// hyperFocal is required to calculate depthOfField when a lens tries to focus at a distance with given fNumber and focalLength
-	this.hyperFocal = ( focalLength * focalLength ) / ( this.aperture * this.coc );
+		// hyperFocal is required to calculate depthOfField when a lens tries to focus at a distance with given fNumber and focalLength
+		this.hyperFocal = ( focalLength * focalLength ) / ( this.aperture * this.coc );
 
-};
+	}
 
-CinematicCamera.prototype.linearize = function ( depth ) {
+	linearize( depth ) {
 
-	var zfar = this.far;
-	var znear = this.near;
-	return - zfar * znear / ( depth * ( zfar - znear ) - zfar );
+		const zfar = this.far;
+		const znear = this.near;
+		return - zfar * znear / ( depth * ( zfar - znear ) - zfar );
 
-};
+	}
 
-CinematicCamera.prototype.smoothstep = function ( near, far, depth ) {
+	smoothstep( near, far, depth ) {
 
-	var x = this.saturate( ( depth - near ) / ( far - near ) );
-	return x * x * ( 3 - 2 * x );
+		const x = this.saturate( ( depth - near ) / ( far - near ) );
+		return x * x * ( 3 - 2 * x );
 
-};
+	}
 
-CinematicCamera.prototype.saturate = function ( x ) {
+	saturate( x ) {
 
-	return Math.max( 0, Math.min( 1, x ) );
+		return Math.max( 0, Math.min( 1, x ) );
 
-};
+	}
 
-// function for focusing at a distance from the camera
-CinematicCamera.prototype.focusAt = function ( focusDistance ) {
+	// function for focusing at a distance from the camera
+	focusAt( focusDistance = 20 ) {
 
-	if ( focusDistance === undefined ) focusDistance = 20;
+		const focalLength = this.getFocalLength();
 
-	var focalLength = this.getFocalLength();
+		// distance from the camera (normal to frustrum) to focus on
+		this.focus = focusDistance;
 
-	// distance from the camera (normal to frustrum) to focus on
-	this.focus = focusDistance;
+		// the nearest point from the camera which is in focus (unused)
+		this.nearPoint = ( this.hyperFocal * this.focus ) / ( this.hyperFocal + ( this.focus - focalLength ) );
 
-	// the nearest point from the camera which is in focus (unused)
-	this.nearPoint = ( this.hyperFocal * this.focus ) / ( this.hyperFocal + ( this.focus - focalLength ) );
+		// the farthest point from the camera which is in focus (unused)
+		this.farPoint = ( this.hyperFocal * this.focus ) / ( this.hyperFocal - ( this.focus - focalLength ) );
 
-	// the farthest point from the camera which is in focus (unused)
-	this.farPoint = ( this.hyperFocal * this.focus ) / ( this.hyperFocal - ( this.focus - focalLength ) );
+		// the gap or width of the space in which is everything is in focus (unused)
+		this.depthOfField = this.farPoint - this.nearPoint;
 
-	// the gap or width of the space in which is everything is in focus (unused)
-	this.depthOfField = this.farPoint - this.nearPoint;
+		// Considering minimum distance of focus for a standard lens (unused)
+		if ( this.depthOfField < 0 ) this.depthOfField = 0;
 
-	// Considering minimum distance of focus for a standard lens (unused)
-	if ( this.depthOfField < 0 ) this.depthOfField = 0;
+		this.sdistance = this.smoothstep( this.near, this.far, this.focus );
 
-	this.sdistance = this.smoothstep( this.near, this.far, this.focus );
+		this.ldistance = this.linearize( 1 -	this.sdistance );
 
-	this.ldistance = this.linearize( 1 -	this.sdistance );
+		this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = this.ldistance;
 
-	this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = this.ldistance;
+	}
 
-};
+	initPostProcessing() {
 
-CinematicCamera.prototype.initPostProcessing = function () {
+		if ( this.postprocessing.enabled ) {
 
-	if ( this.postprocessing.enabled ) {
+			this.postprocessing.scene = new Scene();
 
-		this.postprocessing.scene = new Scene();
+			this.postprocessing.camera = new OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2,	window.innerHeight / 2, window.innerHeight / - 2, - 10000, 10000 );
 
-		this.postprocessing.camera = new OrthographicCamera( window.innerWidth / - 2, window.innerWidth / 2,	window.innerHeight / 2, window.innerHeight / - 2, - 10000, 10000 );
+			this.postprocessing.scene.add( this.postprocessing.camera );
 
-		this.postprocessing.scene.add( this.postprocessing.camera );
+			const pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBFormat };
+			this.postprocessing.rtTextureDepth = new WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );
+			this.postprocessing.rtTextureColor = new WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );
 
-		var pars = { minFilter: LinearFilter, magFilter: LinearFilter, format: RGBFormat };
-		this.postprocessing.rtTextureDepth = new WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );
-		this.postprocessing.rtTextureColor = new WebGLRenderTarget( window.innerWidth, window.innerHeight, pars );
+			const bokeh_shader = BokehShader;
 
-		var bokeh_shader = BokehShader;
+			this.postprocessing.bokeh_uniforms = UniformsUtils.clone( bokeh_shader.uniforms );
 
-		this.postprocessing.bokeh_uniforms = UniformsUtils.clone( bokeh_shader.uniforms );
+			this.postprocessing.bokeh_uniforms[ 'tColor' ].value = this.postprocessing.rtTextureColor.texture;
+			this.postprocessing.bokeh_uniforms[ 'tDepth' ].value = this.postprocessing.rtTextureDepth.texture;
 
-		this.postprocessing.bokeh_uniforms[ 'tColor' ].value = this.postprocessing.rtTextureColor.texture;
-		this.postprocessing.bokeh_uniforms[ 'tDepth' ].value = this.postprocessing.rtTextureDepth.texture;
+			this.postprocessing.bokeh_uniforms[ 'manualdof' ].value = 0;
+			this.postprocessing.bokeh_uniforms[ 'shaderFocus' ].value = 0;
 
-		this.postprocessing.bokeh_uniforms[ 'manualdof' ].value = 0;
-		this.postprocessing.bokeh_uniforms[ 'shaderFocus' ].value = 0;
+			this.postprocessing.bokeh_uniforms[ 'fstop' ].value = 2.8;
 
-		this.postprocessing.bokeh_uniforms[ 'fstop' ].value = 2.8;
+			this.postprocessing.bokeh_uniforms[ 'showFocus' ].value = 1;
 
-		this.postprocessing.bokeh_uniforms[ 'showFocus' ].value = 1;
+			this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = 0.1;
 
-		this.postprocessing.bokeh_uniforms[ 'focalDepth' ].value = 0.1;
+			//console.log( this.postprocessing.bokeh_uniforms[ "focalDepth" ].value );
 
-		//console.log( this.postprocessing.bokeh_uniforms[ "focalDepth" ].value );
+			this.postprocessing.bokeh_uniforms[ 'znear' ].value = this.near;
+			this.postprocessing.bokeh_uniforms[ 'zfar' ].value = this.near;
 
-		this.postprocessing.bokeh_uniforms[ 'znear' ].value = this.near;
-		this.postprocessing.bokeh_uniforms[ 'zfar' ].value = this.near;
 
+			this.postprocessing.bokeh_uniforms[ 'textureWidth' ].value = window.innerWidth;
 
-		this.postprocessing.bokeh_uniforms[ 'textureWidth' ].value = window.innerWidth;
+			this.postprocessing.bokeh_uniforms[ 'textureHeight' ].value = window.innerHeight;
 
-		this.postprocessing.bokeh_uniforms[ 'textureHeight' ].value = window.innerHeight;
+			this.postprocessing.materialBokeh = new ShaderMaterial( {
+				uniforms: this.postprocessing.bokeh_uniforms,
+				vertexShader: bokeh_shader.vertexShader,
+				fragmentShader: bokeh_shader.fragmentShader,
+				defines: {
+					RINGS: this.shaderSettings.rings,
+					SAMPLES: this.shaderSettings.samples,
+					DEPTH_PACKING: 1
+				}
+			} );
 
-		this.postprocessing.materialBokeh = new ShaderMaterial( {
-			uniforms: this.postprocessing.bokeh_uniforms,
-			vertexShader: bokeh_shader.vertexShader,
-			fragmentShader: bokeh_shader.fragmentShader,
-			defines: {
-				RINGS: this.shaderSettings.rings,
-				SAMPLES: this.shaderSettings.samples,
-				DEPTH_PACKING: 1
-			}
-		} );
+			this.postprocessing.quad = new Mesh( new PlaneGeometry( window.innerWidth, window.innerHeight ), this.postprocessing.materialBokeh );
+			this.postprocessing.quad.position.z = - 500;
+			this.postprocessing.scene.add( this.postprocessing.quad );
 
-		this.postprocessing.quad = new Mesh( new PlaneGeometry( window.innerWidth, window.innerHeight ), this.postprocessing.materialBokeh );
-		this.postprocessing.quad.position.z = - 500;
-		this.postprocessing.scene.add( this.postprocessing.quad );
+		}
 
 	}
 
-};
+	renderCinematic( scene, renderer ) {
 
-CinematicCamera.prototype.renderCinematic = function ( scene, renderer ) {
+		if ( this.postprocessing.enabled ) {
 
-	if ( this.postprocessing.enabled ) {
+			const currentRenderTarget = renderer.getRenderTarget();
 
-		var currentRenderTarget = renderer.getRenderTarget();
+			renderer.clear();
 
-		renderer.clear();
+			// Render scene into texture
 
-		// Render scene into texture
+			scene.overrideMaterial = null;
+			renderer.setRenderTarget( this.postprocessing.rtTextureColor );
+			renderer.clear();
+			renderer.render( scene, this );
 
-		scene.overrideMaterial = null;
-		renderer.setRenderTarget( this.postprocessing.rtTextureColor );
-		renderer.clear();
-		renderer.render( scene, this );
+			// Render depth into texture
 
-		// Render depth into texture
+			scene.overrideMaterial = this.materialDepth;
+			renderer.setRenderTarget( this.postprocessing.rtTextureDepth );
+			renderer.clear();
+			renderer.render( scene, this );
 
-		scene.overrideMaterial = this.materialDepth;
-		renderer.setRenderTarget( this.postprocessing.rtTextureDepth );
-		renderer.clear();
-		renderer.render( scene, this );
+			// Render bokeh composite
 
-		// Render bokeh composite
+			renderer.setRenderTarget( null );
+			renderer.render( this.postprocessing.scene, this.postprocessing.camera );
 
-		renderer.setRenderTarget( null );
-		renderer.render( this.postprocessing.scene, this.postprocessing.camera );
+			renderer.setRenderTarget( currentRenderTarget );
 
-		renderer.setRenderTarget( currentRenderTarget );
+		}
 
 	}
 
-};
+}
 
 export { CinematicCamera };

+ 21 - 13
examples/jsm/environments/DebugEnvironment.js

@@ -1,38 +1,46 @@
-import * as THREE from '../../../build/three.module.js';
-
-class DebugEnvironment extends THREE.Scene {
+import {
+	BackSide,
+	BoxGeometry,
+	Mesh,
+	MeshLambertMaterial,
+	MeshStandardMaterial,
+	PointLight,
+	Scene,
+} from '../../../build/three.module.js';
+
+class DebugEnvironment extends Scene {
 
 	constructor() {
 
 		super();
 
-		const geometry = new THREE.BoxGeometry();
+		const geometry = new BoxGeometry();
 		geometry.deleteAttribute( 'uv' );
-		const roomMaterial = new THREE.MeshStandardMaterial( { metalness: 0, side: THREE.BackSide } );
-		const room = new THREE.Mesh( geometry, roomMaterial );
+		const roomMaterial = new MeshStandardMaterial( { metalness: 0, side: BackSide } );
+		const room = new Mesh( geometry, roomMaterial );
 		room.scale.setScalar( 10 );
 		this.add( room );
 
-		const mainLight = new THREE.PointLight( 0xffffff, 50, 0, 2 );
+		const mainLight = new PointLight( 0xffffff, 50, 0, 2 );
 		this.add( mainLight );
 
-		const material1 = new THREE.MeshLambertMaterial( { color: 0xff0000, emissive: 0xffffff, emissiveIntensity: 10 } );
+		const material1 = new MeshLambertMaterial( { color: 0xff0000, emissive: 0xffffff, emissiveIntensity: 10 } );
 
-		const light1 = new THREE.Mesh( geometry, material1 );
+		const light1 = new Mesh( geometry, material1 );
 		light1.position.set( - 5, 2, 0 );
 		light1.scale.set( 0.1, 1, 1 );
 		this.add( light1 );
 
-		const material2 = new THREE.MeshLambertMaterial( { color: 0x00ff00, emissive: 0xffffff, emissiveIntensity: 10 } );
+		const material2 = new MeshLambertMaterial( { color: 0x00ff00, emissive: 0xffffff, emissiveIntensity: 10 } );
 
-		const light2 = new THREE.Mesh( geometry, material2 );
+		const light2 = new Mesh( geometry, material2 );
 		light2.position.set( 0, 5, 0 );
 		light2.scale.set( 1, 0.1, 1 );
 		this.add( light2 );
 
-		const material3 = new THREE.MeshLambertMaterial( { color: 0x0000ff, emissive: 0xffffff, emissiveIntensity: 10 } );
+		const material3 = new MeshLambertMaterial( { color: 0x0000ff, emissive: 0xffffff, emissiveIntensity: 10 } );
 
-		const light3 = new THREE.Mesh( geometry, material3 );
+		const light3 = new Mesh( geometry, material3 );
 		light3.position.set( 2, 1, 5 );
 		light3.scale.set( 1.5, 2, 0.1 );
 		this.add( light3 );

+ 29 - 21
examples/jsm/environments/RoomEnvironment.js

@@ -2,60 +2,68 @@
  * https://github.com/google/model-viewer/blob/master/packages/model-viewer/src/three-components/EnvironmentScene.ts
  */
 
-import * as THREE from '../../../build/three.module.js';
-
-class RoomEnvironment extends THREE.Scene {
+import {
+ 	BackSide,
+ 	BoxGeometry,
+ 	Mesh,
+	MeshBasicMaterial,
+ 	MeshStandardMaterial,
+ 	PointLight,
+ 	Scene,
+} from '../../../build/three.module.js';
+
+class RoomEnvironment extends Scene {
 
 	constructor() {
 
 		super();
 
-		const geometry = new THREE.BoxGeometry();
+		const geometry = new BoxGeometry();
 		geometry.deleteAttribute( 'uv' );
 
-		const roomMaterial = new THREE.MeshStandardMaterial( { side: THREE.BackSide } );
-		const boxMaterial = new THREE.MeshStandardMaterial();
+		const roomMaterial = new MeshStandardMaterial( { side: BackSide } );
+		const boxMaterial = new MeshStandardMaterial();
 
-		const mainLight = new THREE.PointLight( 0xffffff, 5.0, 28, 2 );
+		const mainLight = new PointLight( 0xffffff, 5.0, 28, 2 );
 		mainLight.position.set( 0.418, 16.199, 0.300 );
 		this.add( mainLight );
 
-		const room = new THREE.Mesh( geometry, roomMaterial );
+		const room = new Mesh( geometry, roomMaterial );
 		room.position.set( - 0.757, 13.219, 0.717 );
 		room.scale.set( 31.713, 28.305, 28.591 );
 		this.add( room );
 
-		const box1 = new THREE.Mesh( geometry, boxMaterial );
+		const box1 = new Mesh( geometry, boxMaterial );
 		box1.position.set( - 10.906, 2.009, 1.846 );
 		box1.rotation.set( 0, - 0.195, 0 );
 		box1.scale.set( 2.328, 7.905, 4.651 );
 		this.add( box1 );
 
-		const box2 = new THREE.Mesh( geometry, boxMaterial );
+		const box2 = new Mesh( geometry, boxMaterial );
 		box2.position.set( - 5.607, - 0.754, - 0.758 );
 		box2.rotation.set( 0, 0.994, 0 );
 		box2.scale.set( 1.970, 1.534, 3.955 );
 		this.add( box2 );
 
-		const box3 = new THREE.Mesh( geometry, boxMaterial );
+		const box3 = new Mesh( geometry, boxMaterial );
 		box3.position.set( 6.167, 0.857, 7.803 );
 		box3.rotation.set( 0, 0.561, 0 );
 		box3.scale.set( 3.927, 6.285, 3.687 );
 		this.add( box3 );
 
-		const box4 = new THREE.Mesh( geometry, boxMaterial );
+		const box4 = new Mesh( geometry, boxMaterial );
 		box4.position.set( - 2.017, 0.018, 6.124 );
 		box4.rotation.set( 0, 0.333, 0 );
 		box4.scale.set( 2.002, 4.566, 2.064 );
 		this.add( box4 );
 
-		const box5 = new THREE.Mesh( geometry, boxMaterial );
+		const box5 = new Mesh( geometry, boxMaterial );
 		box5.position.set( 2.291, - 0.756, - 2.621 );
 		box5.rotation.set( 0, - 0.286, 0 );
 		box5.scale.set( 1.546, 1.552, 1.496 );
 		this.add( box5 );
 
-		const box6 = new THREE.Mesh( geometry, boxMaterial );
+		const box6 = new Mesh( geometry, boxMaterial );
 		box6.position.set( - 2.193, - 0.369, - 5.547 );
 		box6.rotation.set( 0, 0.516, 0 );
 		box6.scale.set( 3.875, 3.487, 2.986 );
@@ -63,37 +71,37 @@ class RoomEnvironment extends THREE.Scene {
 
 
 		// -x right
-		const light1 = new THREE.Mesh( geometry, createAreaLightMaterial( 50 ) );
+		const light1 = new Mesh( geometry, createAreaLightMaterial( 50 ) );
 		light1.position.set( - 16.116, 14.37, 8.208 );
 		light1.scale.set( 0.1, 2.428, 2.739 );
 		this.add( light1 );
 
 		// -x left
-		const light2 = new THREE.Mesh( geometry, createAreaLightMaterial( 50 ) );
+		const light2 = new Mesh( geometry, createAreaLightMaterial( 50 ) );
 		light2.position.set( - 16.109, 18.021, - 8.207 );
 		light2.scale.set( 0.1, 2.425, 2.751 );
 		this.add( light2 );
 
 		// +x
-		const light3 = new THREE.Mesh( geometry, createAreaLightMaterial( 17 ) );
+		const light3 = new Mesh( geometry, createAreaLightMaterial( 17 ) );
 		light3.position.set( 14.904, 12.198, - 1.832 );
 		light3.scale.set( 0.15, 4.265, 6.331 );
 		this.add( light3 );
 
 		// +z
-		const light4 = new THREE.Mesh( geometry, createAreaLightMaterial( 43 ) );
+		const light4 = new Mesh( geometry, createAreaLightMaterial( 43 ) );
 		light4.position.set( - 0.462, 8.89, 14.520 );
 		light4.scale.set( 4.38, 5.441, 0.088 );
 		this.add( light4 );
 
 		// -z
-		const light5 = new THREE.Mesh( geometry, createAreaLightMaterial( 20 ) );
+		const light5 = new Mesh( geometry, createAreaLightMaterial( 20 ) );
 		light5.position.set( 3.235, 11.486, - 12.541 );
 		light5.scale.set( 2.5, 2.0, 0.1 );
 		this.add( light5 );
 
 		// +y
-		const light6 = new THREE.Mesh( geometry, createAreaLightMaterial( 100 ) );
+		const light6 = new Mesh( geometry, createAreaLightMaterial( 100 ) );
 		light6.position.set( 0.0, 20.0, 0.0 );
 		light6.scale.set( 1.0, 0.1, 1.0 );
 		this.add( light6 );
@@ -104,7 +112,7 @@ class RoomEnvironment extends THREE.Scene {
 
 function createAreaLightMaterial( intensity ) {
 
-	const material = new THREE.MeshBasicMaterial();
+	const material = new MeshBasicMaterial();
 	material.color.setScalar( intensity );
 	return material;
 

+ 40 - 41
examples/jsm/geometries/BoxLineGeometry.js

@@ -3,68 +3,67 @@ import {
 	Float32BufferAttribute
 } from '../../../build/three.module.js';
 
-var BoxLineGeometry = function ( width, height, depth, widthSegments, heightSegments, depthSegments ) {
+class BoxLineGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
 
-	width = width || 1;
-	height = height || 1;
-	depth = depth || 1;
+		super();
 
-	widthSegments = Math.floor( widthSegments ) || 1;
-	heightSegments = Math.floor( heightSegments ) || 1;
-	depthSegments = Math.floor( depthSegments ) || 1;
+		widthSegments = Math.floor( widthSegments );
+		heightSegments = Math.floor( heightSegments );
+		depthSegments = Math.floor( depthSegments );
 
-	var widthHalf = width / 2;
-	var heightHalf = height / 2;
-	var depthHalf = depth / 2;
+		const widthHalf = width / 2;
+		const heightHalf = height / 2;
+		const depthHalf = depth / 2;
 
-	var segmentWidth = width / widthSegments;
-	var segmentHeight = height / heightSegments;
-	var segmentDepth = depth / depthSegments;
+		const segmentWidth = width / widthSegments;
+		const segmentHeight = height / heightSegments;
+		const segmentDepth = depth / depthSegments;
 
-	var vertices = [];
+		const vertices = [];
 
-	var x = - widthHalf, y = - heightHalf, z = - depthHalf;
+		let x = - widthHalf;
+		let y = - heightHalf;
+		let z = - depthHalf;
 
-	for ( var i = 0; i <= widthSegments; i ++ ) {
+		for ( let i = 0; i <= widthSegments; i ++ ) {
 
-		vertices.push( x, - heightHalf, - depthHalf, x, heightHalf, - depthHalf );
-		vertices.push( x, heightHalf, - depthHalf, x, heightHalf, depthHalf );
-		vertices.push( x, heightHalf, depthHalf, x, - heightHalf, depthHalf );
-		vertices.push( x, - heightHalf, depthHalf, x, - heightHalf, - depthHalf );
+			vertices.push( x, - heightHalf, - depthHalf, x, heightHalf, - depthHalf );
+			vertices.push( x, heightHalf, - depthHalf, x, heightHalf, depthHalf );
+			vertices.push( x, heightHalf, depthHalf, x, - heightHalf, depthHalf );
+			vertices.push( x, - heightHalf, depthHalf, x, - heightHalf, - depthHalf );
 
-		x += segmentWidth;
+			x += segmentWidth;
 
-	}
+		}
 
-	for ( var i = 0; i <= heightSegments; i ++ ) {
+		for ( let i = 0; i <= heightSegments; i ++ ) {
 
-		vertices.push( - widthHalf, y, - depthHalf, widthHalf, y, - depthHalf );
-		vertices.push( widthHalf, y, - depthHalf, widthHalf, y, depthHalf );
-		vertices.push( widthHalf, y, depthHalf, - widthHalf, y, depthHalf );
-		vertices.push( - widthHalf, y, depthHalf, - widthHalf, y, - depthHalf );
+			vertices.push( - widthHalf, y, - depthHalf, widthHalf, y, - depthHalf );
+			vertices.push( widthHalf, y, - depthHalf, widthHalf, y, depthHalf );
+			vertices.push( widthHalf, y, depthHalf, - widthHalf, y, depthHalf );
+			vertices.push( - widthHalf, y, depthHalf, - widthHalf, y, - depthHalf );
 
-		y += segmentHeight;
+			y += segmentHeight;
 
-	}
+		}
 
-	for ( var i = 0; i <= depthSegments; i ++ ) {
+		for ( let i = 0; i <= depthSegments; i ++ ) {
 
-		vertices.push( - widthHalf, - heightHalf, z, - widthHalf, heightHalf, z );
-		vertices.push( - widthHalf, heightHalf, z, widthHalf, heightHalf, z );
-		vertices.push( widthHalf, heightHalf, z, widthHalf, - heightHalf, z );
-		vertices.push( widthHalf, - heightHalf, z, - widthHalf, - heightHalf, z );
+			vertices.push( - widthHalf, - heightHalf, z, - widthHalf, heightHalf, z );
+			vertices.push( - widthHalf, heightHalf, z, widthHalf, heightHalf, z );
+			vertices.push( widthHalf, heightHalf, z, widthHalf, - heightHalf, z );
+			vertices.push( widthHalf, - heightHalf, z, - widthHalf, - heightHalf, z );
 
-		z += segmentDepth;
+			z += segmentDepth;
 
-	}
+		}
 
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
 
-};
+	}
 
-BoxLineGeometry.prototype = Object.create( BufferGeometry.prototype );
-BoxLineGeometry.prototype.constructor = BoxLineGeometry;
+}
 
 export { BoxLineGeometry };

+ 28 - 29
examples/jsm/geometries/ConvexGeometry.js

@@ -4,57 +4,56 @@ import {
 } from '../../../build/three.module.js';
 import { ConvexHull } from '../math/ConvexHull.js';
 
-// ConvexGeometry
+class ConvexGeometry extends BufferGeometry {
 
-var ConvexGeometry = function ( points ) {
+	constructor( points ) {
 
-	BufferGeometry.call( this );
+		super();
 
-	// buffers
+		// buffers
 
-	var vertices = [];
-	var normals = [];
+		const vertices = [];
+		const normals = [];
 
-	if ( ConvexHull === undefined ) {
+		if ( ConvexHull === undefined ) {
 
-		console.error( 'THREE.ConvexBufferGeometry: ConvexBufferGeometry relies on ConvexHull' );
+			console.error( 'THREE.ConvexBufferGeometry: ConvexBufferGeometry relies on ConvexHull' );
 
-	}
+		}
 
-	var convexHull = new ConvexHull().setFromPoints( points );
+		const convexHull = new ConvexHull().setFromPoints( points );
 
-	// generate vertices and normals
+		// generate vertices and normals
 
-	var faces = convexHull.faces;
+		const faces = convexHull.faces;
 
-	for ( var i = 0; i < faces.length; i ++ ) {
+		for ( let i = 0; i < faces.length; i ++ ) {
 
-		var face = faces[ i ];
-		var edge = face.edge;
+			const face = faces[ i ];
+			let edge = face.edge;
 
-		// we move along a doubly-connected edge list to access all face points (see HalfEdge docs)
+			// we move along a doubly-connected edge list to access all face points (see HalfEdge docs)
 
-		do {
+			do {
 
-			var point = edge.head().point;
+				const point = edge.head().point;
 
-			vertices.push( point.x, point.y, point.z );
-			normals.push( face.normal.x, face.normal.y, face.normal.z );
+				vertices.push( point.x, point.y, point.z );
+				normals.push( face.normal.x, face.normal.y, face.normal.z );
 
-			edge = edge.next;
+				edge = edge.next;
 
-		} while ( edge !== face.edge );
+			} while ( edge !== face.edge );
 
-	}
+		}
 
-	// build geometry
+		// build geometry
 
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
 
-};
+	}
 
-ConvexGeometry.prototype = Object.create( BufferGeometry.prototype );
-ConvexGeometry.prototype.constructor = ConvexGeometry;
+}
 
 export { ConvexGeometry };

+ 209 - 203
examples/jsm/geometries/DecalGeometry.js

@@ -20,338 +20,344 @@ import {
  *
  */
 
-var DecalGeometry = function ( mesh, position, orientation, size ) {
+class DecalGeometry extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( mesh, position, orientation, size ) {
 
-	// buffers
+		super();
 
-	var vertices = [];
-	var normals = [];
-	var uvs = [];
+		// buffers
 
-	// helpers
+		const vertices = [];
+		const normals = [];
+		const uvs = [];
 
-	var plane = new Vector3();
+		// helpers
 
-	// this matrix represents the transformation of the decal projector
+		const plane = new Vector3();
 
-	var projectorMatrix = new Matrix4();
-	projectorMatrix.makeRotationFromEuler( orientation );
-	projectorMatrix.setPosition( position );
+		// this matrix represents the transformation of the decal projector
 
-	var projectorMatrixInverse = new Matrix4();
-	projectorMatrixInverse.copy( projectorMatrix ).invert();
+		const projectorMatrix = new Matrix4();
+		projectorMatrix.makeRotationFromEuler( orientation );
+		projectorMatrix.setPosition( position );
 
-	// generate buffers
+		const projectorMatrixInverse = new Matrix4();
+		projectorMatrixInverse.copy( projectorMatrix ).invert();
 
-	generate();
+		// generate buffers
 
-	// build geometry
+		generate();
 
-	this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
+		// build geometry
 
-	function generate() {
+		this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
 
-		var i;
+		function generate() {
 
-		var decalVertices = [];
+			let decalVertices = [];
 
-		var vertex = new Vector3();
-		var normal = new Vector3();
+			const vertex = new Vector3();
+			const normal = new Vector3();
 
-		// handle different geometry types
+			// handle different geometry types
 
-		if ( mesh.geometry.isGeometry === true ) {
+			if ( mesh.geometry.isGeometry === true ) {
 
-			console.error( 'THREE.DecalGeometry no longer supports THREE.Geometry. Use BufferGeometry instead.' );
-			return;
+				console.error( 'THREE.DecalGeometry no longer supports THREE.Geometry. Use BufferGeometry instead.' );
+				return;
 
-		}
+			}
 
-		var geometry = mesh.geometry;
+			const geometry = mesh.geometry;
 
-		var positionAttribute = geometry.attributes.position;
-		var normalAttribute = geometry.attributes.normal;
+			const positionAttribute = geometry.attributes.position;
+			const normalAttribute = geometry.attributes.normal;
 
-		// first, create an array of 'DecalVertex' objects
-		// three consecutive 'DecalVertex' objects represent a single face
-		//
-		// this data structure will be later used to perform the clipping
+			// first, create an array of 'DecalVertex' objects
+			// three consecutive 'DecalVertex' objects represent a single face
+			//
+			// this data structure will be later used to perform the clipping
 
-		if ( geometry.index !== null ) {
+			if ( geometry.index !== null ) {
 
-			// indexed BufferGeometry
+				// indexed BufferGeometry
 
-			var index = geometry.index;
+				const index = geometry.index;
 
-			for ( i = 0; i < index.count; i ++ ) {
+				for ( let i = 0; i < index.count; i ++ ) {
 
-				vertex.fromBufferAttribute( positionAttribute, index.getX( i ) );
-				normal.fromBufferAttribute( normalAttribute, index.getX( i ) );
+					vertex.fromBufferAttribute( positionAttribute, index.getX( i ) );
+					normal.fromBufferAttribute( normalAttribute, index.getX( i ) );
 
-				pushDecalVertex( decalVertices, vertex, normal );
+					pushDecalVertex( decalVertices, vertex, normal );
 
-			}
+				}
 
-		} else {
+			} else {
 
-			// non-indexed BufferGeometry
+				// non-indexed BufferGeometry
 
-			for ( i = 0; i < positionAttribute.count; i ++ ) {
+				for ( let i = 0; i < positionAttribute.count; i ++ ) {
 
-				vertex.fromBufferAttribute( positionAttribute, i );
-				normal.fromBufferAttribute( normalAttribute, i );
+					vertex.fromBufferAttribute( positionAttribute, i );
+					normal.fromBufferAttribute( normalAttribute, i );
 
-				pushDecalVertex( decalVertices, vertex, normal );
+					pushDecalVertex( decalVertices, vertex, normal );
+
+				}
 
 			}
 
-		}
+			// second, clip the geometry so that it doesn't extend out from the projector
 
-		// second, clip the geometry so that it doesn't extend out from the projector
+			decalVertices = clipGeometry( decalVertices, plane.set( 1, 0, 0 ) );
+			decalVertices = clipGeometry( decalVertices, plane.set( - 1, 0, 0 ) );
+			decalVertices = clipGeometry( decalVertices, plane.set( 0, 1, 0 ) );
+			decalVertices = clipGeometry( decalVertices, plane.set( 0, - 1, 0 ) );
+			decalVertices = clipGeometry( decalVertices, plane.set( 0, 0, 1 ) );
+			decalVertices = clipGeometry( decalVertices, plane.set( 0, 0, - 1 ) );
 
-		decalVertices = clipGeometry( decalVertices, plane.set( 1, 0, 0 ) );
-		decalVertices = clipGeometry( decalVertices, plane.set( - 1, 0, 0 ) );
-		decalVertices = clipGeometry( decalVertices, plane.set( 0, 1, 0 ) );
-		decalVertices = clipGeometry( decalVertices, plane.set( 0, - 1, 0 ) );
-		decalVertices = clipGeometry( decalVertices, plane.set( 0, 0, 1 ) );
-		decalVertices = clipGeometry( decalVertices, plane.set( 0, 0, - 1 ) );
+			// third, generate final vertices, normals and uvs
 
-		// third, generate final vertices, normals and uvs
+			for ( let i = 0; i < decalVertices.length; i ++ ) {
 
-		for ( i = 0; i < decalVertices.length; i ++ ) {
+				const decalVertex = decalVertices[ i ];
 
-			var decalVertex = decalVertices[ i ];
+				// create texture coordinates (we are still in projector space)
 
-			// create texture coordinates (we are still in projector space)
+				uvs.push(
+					0.5 + ( decalVertex.position.x / size.x ),
+					0.5 + ( decalVertex.position.y / size.y )
+				);
 
-			uvs.push(
-				0.5 + ( decalVertex.position.x / size.x ),
-				0.5 + ( decalVertex.position.y / size.y )
-			);
+				// transform the vertex back to world space
 
-			// transform the vertex back to world space
+				decalVertex.position.applyMatrix4( projectorMatrix );
 
-			decalVertex.position.applyMatrix4( projectorMatrix );
+				// now create vertex and normal buffer data
 
-			// now create vertex and normal buffer data
+				vertices.push( decalVertex.position.x, decalVertex.position.y, decalVertex.position.z );
+				normals.push( decalVertex.normal.x, decalVertex.normal.y, decalVertex.normal.z );
 
-			vertices.push( decalVertex.position.x, decalVertex.position.y, decalVertex.position.z );
-			normals.push( decalVertex.normal.x, decalVertex.normal.y, decalVertex.normal.z );
+			}
 
 		}
 
-	}
+		function pushDecalVertex( decalVertices, vertex, normal ) {
 
-	function pushDecalVertex( decalVertices, vertex, normal ) {
+			// transform the vertex to world space, then to projector space
 
-		// transform the vertex to world space, then to projector space
+			vertex.applyMatrix4( mesh.matrixWorld );
+			vertex.applyMatrix4( projectorMatrixInverse );
 
-		vertex.applyMatrix4( mesh.matrixWorld );
-		vertex.applyMatrix4( projectorMatrixInverse );
+			normal.transformDirection( mesh.matrixWorld );
 
-		normal.transformDirection( mesh.matrixWorld );
+			decalVertices.push( new DecalVertex( vertex.clone(), normal.clone() ) );
 
-		decalVertices.push( new DecalVertex( vertex.clone(), normal.clone() ) );
+		}
 
-	}
+		function clipGeometry( inVertices, plane ) {
 
-	function clipGeometry( inVertices, plane ) {
+			const outVertices = [];
 
-		var outVertices = [];
+			const s = 0.5 * Math.abs( size.dot( plane ) );
 
-		var s = 0.5 * Math.abs( size.dot( plane ) );
+			// a single iteration clips one face,
+			// which consists of three consecutive 'DecalVertex' objects
 
-		// a single iteration clips one face,
-		// which consists of three consecutive 'DecalVertex' objects
+			for ( let i = 0; i < inVertices.length; i += 3 ) {
 
-		for ( var i = 0; i < inVertices.length; i += 3 ) {
+				let total = 0;
+				let nV1;
+				let nV2;
+				let nV3;
+				let nV4;
 
-			var v1Out, v2Out, v3Out, total = 0;
-			var nV1, nV2, nV3, nV4;
+				const d1 = inVertices[ i + 0 ].position.dot( plane ) - s;
+				const d2 = inVertices[ i + 1 ].position.dot( plane ) - s;
+				const d3 = inVertices[ i + 2 ].position.dot( plane ) - s;
 
-			var d1 = inVertices[ i + 0 ].position.dot( plane ) - s;
-			var d2 = inVertices[ i + 1 ].position.dot( plane ) - s;
-			var d3 = inVertices[ i + 2 ].position.dot( plane ) - s;
+				const v1Out = d1 > 0;
+				const v2Out = d2 > 0;
+				const v3Out = d3 > 0;
 
-			v1Out = d1 > 0;
-			v2Out = d2 > 0;
-			v3Out = d3 > 0;
+				// calculate, how many vertices of the face lie outside of the clipping plane
 
-			// calculate, how many vertices of the face lie outside of the clipping plane
+				total = ( v1Out ? 1 : 0 ) + ( v2Out ? 1 : 0 ) + ( v3Out ? 1 : 0 );
 
-			total = ( v1Out ? 1 : 0 ) + ( v2Out ? 1 : 0 ) + ( v3Out ? 1 : 0 );
+				switch ( total ) {
 
-			switch ( total ) {
+					case 0: {
 
-				case 0: {
+						// the entire face lies inside of the plane, no clipping needed
 
-					// the entire face lies inside of the plane, no clipping needed
+						outVertices.push( inVertices[ i ] );
+						outVertices.push( inVertices[ i + 1 ] );
+						outVertices.push( inVertices[ i + 2 ] );
+						break;
 
-					outVertices.push( inVertices[ i ] );
-					outVertices.push( inVertices[ i + 1 ] );
-					outVertices.push( inVertices[ i + 2 ] );
-					break;
+					}
 
-				}
+					case 1: {
 
-				case 1: {
+						// one vertex lies outside of the plane, perform clipping
 
-					// one vertex lies outside of the plane, perform clipping
+						if ( v1Out ) {
 
-					if ( v1Out ) {
+							nV1 = inVertices[ i + 1 ];
+							nV2 = inVertices[ i + 2 ];
+							nV3 = clip( inVertices[ i ], nV1, plane, s );
+							nV4 = clip( inVertices[ i ], nV2, plane, s );
 
-						nV1 = inVertices[ i + 1 ];
-						nV2 = inVertices[ i + 2 ];
-						nV3 = clip( inVertices[ i ], nV1, plane, s );
-						nV4 = clip( inVertices[ i ], nV2, plane, s );
+						}
 
-					}
+						if ( v2Out ) {
 
-					if ( v2Out ) {
+							nV1 = inVertices[ i ];
+							nV2 = inVertices[ i + 2 ];
+							nV3 = clip( inVertices[ i + 1 ], nV1, plane, s );
+							nV4 = clip( inVertices[ i + 1 ], nV2, plane, s );
 
-						nV1 = inVertices[ i ];
-						nV2 = inVertices[ i + 2 ];
-						nV3 = clip( inVertices[ i + 1 ], nV1, plane, s );
-						nV4 = clip( inVertices[ i + 1 ], nV2, plane, s );
+							outVertices.push( nV3 );
+							outVertices.push( nV2.clone() );
+							outVertices.push( nV1.clone() );
 
-						outVertices.push( nV3 );
-						outVertices.push( nV2.clone() );
-						outVertices.push( nV1.clone() );
+							outVertices.push( nV2.clone() );
+							outVertices.push( nV3.clone() );
+							outVertices.push( nV4 );
+							break;
 
-						outVertices.push( nV2.clone() );
-						outVertices.push( nV3.clone() );
-						outVertices.push( nV4 );
-						break;
+						}
 
-					}
+						if ( v3Out ) {
 
-					if ( v3Out ) {
+							nV1 = inVertices[ i ];
+							nV2 = inVertices[ i + 1 ];
+							nV3 = clip( inVertices[ i + 2 ], nV1, plane, s );
+							nV4 = clip( inVertices[ i + 2 ], nV2, plane, s );
 
-						nV1 = inVertices[ i ];
-						nV2 = inVertices[ i + 1 ];
-						nV3 = clip( inVertices[ i + 2 ], nV1, plane, s );
-						nV4 = clip( inVertices[ i + 2 ], nV2, plane, s );
+						}
 
-					}
+						outVertices.push( nV1.clone() );
+						outVertices.push( nV2.clone() );
+						outVertices.push( nV3 );
 
-					outVertices.push( nV1.clone() );
-					outVertices.push( nV2.clone() );
-					outVertices.push( nV3 );
+						outVertices.push( nV4 );
+						outVertices.push( nV3.clone() );
+						outVertices.push( nV2.clone() );
 
-					outVertices.push( nV4 );
-					outVertices.push( nV3.clone() );
-					outVertices.push( nV2.clone() );
+						break;
 
-					break;
+					}
 
-				}
+					case 2: {
 
-				case 2: {
+						// two vertices lies outside of the plane, perform clipping
 
-					// two vertices lies outside of the plane, perform clipping
+						if ( ! v1Out ) {
 
-					if ( ! v1Out ) {
+							nV1 = inVertices[ i ].clone();
+							nV2 = clip( nV1, inVertices[ i + 1 ], plane, s );
+							nV3 = clip( nV1, inVertices[ i + 2 ], plane, s );
+							outVertices.push( nV1 );
+							outVertices.push( nV2 );
+							outVertices.push( nV3 );
 
-						nV1 = inVertices[ i ].clone();
-						nV2 = clip( nV1, inVertices[ i + 1 ], plane, s );
-						nV3 = clip( nV1, inVertices[ i + 2 ], plane, s );
-						outVertices.push( nV1 );
-						outVertices.push( nV2 );
-						outVertices.push( nV3 );
+						}
 
-					}
+						if ( ! v2Out ) {
 
-					if ( ! v2Out ) {
+							nV1 = inVertices[ i + 1 ].clone();
+							nV2 = clip( nV1, inVertices[ i + 2 ], plane, s );
+							nV3 = clip( nV1, inVertices[ i ], plane, s );
+							outVertices.push( nV1 );
+							outVertices.push( nV2 );
+							outVertices.push( nV3 );
 
-						nV1 = inVertices[ i + 1 ].clone();
-						nV2 = clip( nV1, inVertices[ i + 2 ], plane, s );
-						nV3 = clip( nV1, inVertices[ i ], plane, s );
-						outVertices.push( nV1 );
-						outVertices.push( nV2 );
-						outVertices.push( nV3 );
+						}
 
-					}
+						if ( ! v3Out ) {
 
-					if ( ! v3Out ) {
+							nV1 = inVertices[ i + 2 ].clone();
+							nV2 = clip( nV1, inVertices[ i ], plane, s );
+							nV3 = clip( nV1, inVertices[ i + 1 ], plane, s );
+							outVertices.push( nV1 );
+							outVertices.push( nV2 );
+							outVertices.push( nV3 );
 
-						nV1 = inVertices[ i + 2 ].clone();
-						nV2 = clip( nV1, inVertices[ i ], plane, s );
-						nV3 = clip( nV1, inVertices[ i + 1 ], plane, s );
-						outVertices.push( nV1 );
-						outVertices.push( nV2 );
-						outVertices.push( nV3 );
+						}
+
+						break;
 
 					}
 
-					break;
+					case 3: {
 
-				}
+						// the entire face lies outside of the plane, so let's discard the corresponding vertices
 
-				case 3: {
-
-					// the entire face lies outside of the plane, so let's discard the corresponding vertices
+						break;
 
-					break;
+					}
 
 				}
 
 			}
 
-		}
+			return outVertices;
 
-		return outVertices;
+		}
 
-	}
+		function clip( v0, v1, p, s ) {
 
-	function clip( v0, v1, p, s ) {
+			const d0 = v0.position.dot( p ) - s;
+			const d1 = v1.position.dot( p ) - s;
 
-		var d0 = v0.position.dot( p ) - s;
-		var d1 = v1.position.dot( p ) - s;
+			const s0 = d0 / ( d0 - d1 );
 
-		var s0 = d0 / ( d0 - d1 );
+			const v = new DecalVertex(
+				new Vector3(
+					v0.position.x + s0 * ( v1.position.x - v0.position.x ),
+					v0.position.y + s0 * ( v1.position.y - v0.position.y ),
+					v0.position.z + s0 * ( v1.position.z - v0.position.z )
+				),
+				new Vector3(
+					v0.normal.x + s0 * ( v1.normal.x - v0.normal.x ),
+					v0.normal.y + s0 * ( v1.normal.y - v0.normal.y ),
+					v0.normal.z + s0 * ( v1.normal.z - v0.normal.z )
+				)
+			);
 
-		var v = new DecalVertex(
-			new Vector3(
-				v0.position.x + s0 * ( v1.position.x - v0.position.x ),
-				v0.position.y + s0 * ( v1.position.y - v0.position.y ),
-				v0.position.z + s0 * ( v1.position.z - v0.position.z )
-			),
-			new Vector3(
-				v0.normal.x + s0 * ( v1.normal.x - v0.normal.x ),
-				v0.normal.y + s0 * ( v1.normal.y - v0.normal.y ),
-				v0.normal.z + s0 * ( v1.normal.z - v0.normal.z )
-			)
-		);
+			// need to clip more values (texture coordinates)? do it this way:
+			// intersectpoint.value = a.value + s * ( b.value - a.value );
 
-		// need to clip more values (texture coordinates)? do it this way:
-		// intersectpoint.value = a.value + s * ( b.value - a.value );
+			return v;
 
-		return v;
+		}
 
 	}
 
-};
-
-DecalGeometry.prototype = Object.create( BufferGeometry.prototype );
-DecalGeometry.prototype.constructor = DecalGeometry;
+}
 
 // helper
 
-var DecalVertex = function ( position, normal ) {
+class DecalVertex {
+
+	constructor( position, normal ) {
 
-	this.position = position;
-	this.normal = normal;
+		this.position = position;
+		this.normal = normal;
 
-};
+	}
+
+	clone() {
 
-DecalVertex.prototype.clone = function () {
+		return new this.constructor( this.position.clone(), this.normal.clone() );
 
-	return new this.constructor( this.position.clone(), this.normal.clone() );
+	}
 
-};
+}
 
 export { DecalGeometry, DecalVertex };

+ 596 - 597
examples/jsm/geometries/LightningStrike.js

@@ -109,910 +109,909 @@ import { SimplexNoise } from '../math/SimplexNoise.js';
  *
 */
 
-var LightningStrike = function ( rayParameters ) {
+class LightningStrike extends BufferGeometry {
 
-	BufferGeometry.call( this );
+	constructor( rayParameters = {} ) {
 
-	this.type = 'LightningStrike';
+		super();
 
-	// Set parameters, and set undefined parameters to default values
-	rayParameters = rayParameters || {};
-	this.init( LightningStrike.copyParameters( rayParameters, rayParameters ) );
+		this.type = 'LightningStrike';
 
-	// Creates and populates the mesh
-	this.createMesh();
+		// Set parameters, and set undefined parameters to default values
+		this.init( LightningStrike.copyParameters( rayParameters, rayParameters ) );
 
-};
+		// Creates and populates the mesh
+		this.createMesh();
 
-LightningStrike.prototype = Object.create( BufferGeometry.prototype );
-
-LightningStrike.prototype.constructor = LightningStrike;
+	}
 
-LightningStrike.prototype.isLightningStrike = true;
+	static createRandomGenerator() {
 
-// Ray states
-LightningStrike.RAY_INITIALIZED = 0;
-LightningStrike.RAY_UNBORN = 1;
-LightningStrike.RAY_PROPAGATING = 2;
-LightningStrike.RAY_STEADY = 3;
-LightningStrike.RAY_VANISHING = 4;
-LightningStrike.RAY_EXTINGUISHED = 5;
+		const numSeeds = 2053;
+		const seeds = [];
 
-LightningStrike.COS30DEG = Math.cos( 30 * Math.PI / 180 );
-LightningStrike.SIN30DEG = Math.sin( 30 * Math.PI / 180 );
+		for ( let i = 0; i < numSeeds; i ++ ) {
 
-LightningStrike.createRandomGenerator = function () {
+			seeds.push( Math.random() );
 
-	var numSeeds = 2053;
-	var seeds = [];
+		}
 
-	for ( var i = 0; i < numSeeds; i ++ ) {
+		const generator = {
 
-		seeds.push( Math.random() );
+			currentSeed: 0,
 
-	}
+			random: function () {
 
-	var generator = {
+				const value = seeds[ generator.currentSeed ];
 
-		currentSeed: 0,
+				generator.currentSeed = ( generator.currentSeed + 1 ) % numSeeds;
 
-		random: function () {
+				return value;
 
-			var value = seeds[ generator.currentSeed ];
+			},
 
-			generator.currentSeed = ( generator.currentSeed + 1 ) % numSeeds;
+			getSeed: function () {
 
-			return value;
+				return generator.currentSeed / numSeeds;
 
-		},
+			},
 
-		getSeed: function () {
+			setSeed: function ( seed ) {
 
-			return generator.currentSeed / numSeeds;
+				generator.currentSeed = Math.floor( seed * numSeeds ) % numSeeds;
 
-		},
+			}
 
-		setSeed: function ( seed ) {
+		};
 
-			generator.currentSeed = Math.floor( seed * numSeeds ) % numSeeds;
+		return generator;
 
-		}
+	}
 
-	};
+	static copyParameters( dest = {}, source = {} ) {
 
-	return generator;
+		const vecCopy = function ( v ) {
 
-};
+			if ( source === dest ) {
 
-LightningStrike.copyParameters = function ( dest, source ) {
+				return v;
 
-	source = source || {};
-	dest = dest || {};
+			} else {
 
-	var vecCopy = function ( v ) {
+				return v.clone();
 
-		if ( source === dest ) {
+			}
 
-			return v;
+		};
 
-		} else {
+		dest.sourceOffset = source.sourceOffset !== undefined ? vecCopy( source.sourceOffset ) : new Vector3( 0, 100, 0 ),
+		dest.destOffset = source.destOffset !== undefined ? vecCopy( source.destOffset ) : new Vector3( 0, 0, 0 ),
 
-			return v.clone();
+		dest.timeScale = source.timeScale !== undefined ? source.timeScale : 1,
+		dest.roughness = source.roughness !== undefined ? source.roughness : 0.9,
+		dest.straightness = source.straightness !== undefined ? source.straightness : 0.7,
 
-		}
+		dest.up0 = source.up0 !== undefined ? vecCopy( source.up0 ) : new Vector3( 0, 0, 1 );
+		dest.up1 = source.up1 !== undefined ? vecCopy( source.up1 ) : new Vector3( 0, 0, 1 ),
+		dest.radius0 = source.radius0 !== undefined ? source.radius0 : 1,
+		dest.radius1 = source.radius1 !== undefined ? source.radius1 : 1,
+		dest.radius0Factor = source.radius0Factor !== undefined ? source.radius0Factor : 0.5,
+		dest.radius1Factor = source.radius1Factor !== undefined ? source.radius1Factor : 0.2,
+		dest.minRadius = source.minRadius !== undefined ? source.minRadius : 0.2,
 
-	};
+		// These parameters should not be changed after lightning creation. They can be changed but the ray will change its form abruptly:
 
-	dest.sourceOffset = source.sourceOffset !== undefined ? vecCopy( source.sourceOffset ) : new Vector3( 0, 100, 0 ),
-	dest.destOffset = source.destOffset !== undefined ? vecCopy( source.destOffset ) : new Vector3( 0, 0, 0 ),
+		dest.isEternal = source.isEternal !== undefined ? source.isEternal : ( source.birthTime === undefined || source.deathTime === undefined ),
+		dest.birthTime = source.birthTime,
+		dest.deathTime = source.deathTime,
+		dest.propagationTimeFactor = source.propagationTimeFactor !== undefined ? source.propagationTimeFactor : 0.1,
+		dest.vanishingTimeFactor = source.vanishingTimeFactor !== undefined ? source.vanishingTimeFactor : 0.9,
+		dest.subrayPeriod = source.subrayPeriod !== undefined ? source.subrayPeriod : 4,
+		dest.subrayDutyCycle = source.subrayDutyCycle !== undefined ? source.subrayDutyCycle : 0.6;
 
-	dest.timeScale = source.timeScale !== undefined ? source.timeScale : 1,
-	dest.roughness = source.roughness !== undefined ? source.roughness : 0.9,
-	dest.straightness = source.straightness !== undefined ? source.straightness : 0.7,
+		// These parameters cannot change after lightning creation:
 
-	dest.up0 = source.up0 !== undefined ? vecCopy( source.up0 ) : new Vector3( 0, 0, 1 );
-	dest.up1 = source.up1 !== undefined ? vecCopy( source.up1 ) : new Vector3( 0, 0, 1 ),
-	dest.radius0 = source.radius0 !== undefined ? source.radius0 : 1,
-	dest.radius1 = source.radius1 !== undefined ? source.radius1 : 1,
-	dest.radius0Factor = source.radius0Factor !== undefined ? source.radius0Factor : 0.5,
-	dest.radius1Factor = source.radius1Factor !== undefined ? source.radius1Factor : 0.2,
-	dest.minRadius = source.minRadius !== undefined ? source.minRadius : 0.2,
+		dest.maxIterations = source.maxIterations !== undefined ? source.maxIterations : 9;
+		dest.isStatic = source.isStatic !== undefined ? source.isStatic : false;
+		dest.ramification = source.ramification !== undefined ? source.ramification : 5;
+		dest.maxSubrayRecursion = source.maxSubrayRecursion !== undefined ? source.maxSubrayRecursion : 3;
+		dest.recursionProbability = source.recursionProbability !== undefined ? source.recursionProbability : 0.6;
+		dest.generateUVs = source.generateUVs !== undefined ? source.generateUVs : false;
+		dest.randomGenerator = source.randomGenerator,
+		dest.noiseSeed = source.noiseSeed,
+		dest.onDecideSubrayCreation = source.onDecideSubrayCreation,
+		dest.onSubrayCreation = source.onSubrayCreation;
 
-	// These parameters should not be changed after lightning creation. They can be changed but the ray will change its form abruptly:
+		return dest;
 
-	dest.isEternal = source.isEternal !== undefined ? source.isEternal : ( source.birthTime === undefined || source.deathTime === undefined ),
-	dest.birthTime = source.birthTime,
-	dest.deathTime = source.deathTime,
-	dest.propagationTimeFactor = source.propagationTimeFactor !== undefined ? source.propagationTimeFactor : 0.1,
-	dest.vanishingTimeFactor = source.vanishingTimeFactor !== undefined ? source.vanishingTimeFactor : 0.9,
-	dest.subrayPeriod = source.subrayPeriod !== undefined ? source.subrayPeriod : 4,
-	dest.subrayDutyCycle = source.subrayDutyCycle !== undefined ? source.subrayDutyCycle : 0.6;
+	}
 
-	// These parameters cannot change after lightning creation:
+	update( time ) {
 
-	dest.maxIterations = source.maxIterations !== undefined ? source.maxIterations : 9;
-	dest.isStatic = source.isStatic !== undefined ? source.isStatic : false;
-	dest.ramification = source.ramification !== undefined ? source.ramification : 5;
-	dest.maxSubrayRecursion = source.maxSubrayRecursion !== undefined ? source.maxSubrayRecursion : 3;
-	dest.recursionProbability = source.recursionProbability !== undefined ? source.recursionProbability : 0.6;
-	dest.generateUVs = source.generateUVs !== undefined ? source.generateUVs : false;
-	dest.randomGenerator = source.randomGenerator,
-	dest.noiseSeed = source.noiseSeed,
-	dest.onDecideSubrayCreation = source.onDecideSubrayCreation,
-	dest.onSubrayCreation = source.onSubrayCreation;
+		if ( this.isStatic ) return;
 
-	return dest;
+		if ( this.rayParameters.isEternal || ( this.rayParameters.birthTime <= time && time <= this.rayParameters.deathTime ) ) {
 
-};
+			this.updateMesh( time );
 
-LightningStrike.prototype.update = function ( time ) {
+			if ( time < this.subrays[ 0 ].endPropagationTime ) {
 
-	if ( this.isStatic ) return;
+				this.state = LightningStrike.RAY_PROPAGATING;
 
-	if ( this.rayParameters.isEternal || ( this.rayParameters.birthTime <= time && time <= this.rayParameters.deathTime ) ) {
+			} else if ( time > this.subrays[ 0 ].beginVanishingTime ) {
 
-		this.updateMesh( time );
+				this.state = LightningStrike.RAY_VANISHING;
 
-		if ( time < this.subrays[ 0 ].endPropagationTime ) {
+			} else {
 
-			this.state = LightningStrike.RAY_PROPAGATING;
+				this.state = LightningStrike.RAY_STEADY;
 
-		} else if ( time > this.subrays[ 0 ].beginVanishingTime ) {
+			}
 
-			this.state = LightningStrike.RAY_VANISHING;
+			this.visible = true;
 
 		} else {
 
-			this.state = LightningStrike.RAY_STEADY;
-
-		}
-
-		this.visible = true;
+			this.visible = false;
 
-	} else {
+			if ( time < this.rayParameters.birthTime ) {
 
-		this.visible = false;
+				this.state = LightningStrike.RAY_UNBORN;
 
-		if ( time < this.rayParameters.birthTime ) {
+			} else {
 
-			this.state = LightningStrike.RAY_UNBORN;
+				this.state = LightningStrike.RAY_EXTINGUISHED;
 
-		} else {
-
-			this.state = LightningStrike.RAY_EXTINGUISHED;
+			}
 
 		}
 
 	}
 
-};
+	init( rayParameters ) {
 
-LightningStrike.prototype.init = function ( rayParameters ) {
+		// Init all the state from the parameters
 
-	// Init all the state from the parameters
+		this.rayParameters = rayParameters;
 
-	this.rayParameters = rayParameters;
+		// These parameters cannot change after lightning creation:
 
-	// These parameters cannot change after lightning creation:
+		this.maxIterations = rayParameters.maxIterations !== undefined ? Math.floor( rayParameters.maxIterations ) : 9;
+		rayParameters.maxIterations = this.maxIterations;
+		this.isStatic = rayParameters.isStatic !== undefined ? rayParameters.isStatic : false;
+		rayParameters.isStatic = this.isStatic;
+		this.ramification = rayParameters.ramification !== undefined ? Math.floor( rayParameters.ramification ) : 5;
+		rayParameters.ramification = this.ramification;
+		this.maxSubrayRecursion = rayParameters.maxSubrayRecursion !== undefined ? Math.floor( rayParameters.maxSubrayRecursion ) : 3;
+		rayParameters.maxSubrayRecursion = this.maxSubrayRecursion;
+		this.recursionProbability = rayParameters.recursionProbability !== undefined ? rayParameters.recursionProbability : 0.6;
+		rayParameters.recursionProbability = this.recursionProbability;
+		this.generateUVs = rayParameters.generateUVs !== undefined ? rayParameters.generateUVs : false;
+		rayParameters.generateUVs = this.generateUVs;
 
-	this.maxIterations = rayParameters.maxIterations !== undefined ? Math.floor( rayParameters.maxIterations ) : 9;
-	rayParameters.maxIterations = this.maxIterations;
-	this.isStatic = rayParameters.isStatic !== undefined ? rayParameters.isStatic : false;
-	rayParameters.isStatic = this.isStatic;
-	this.ramification = rayParameters.ramification !== undefined ? Math.floor( rayParameters.ramification ) : 5;
-	rayParameters.ramification = this.ramification;
-	this.maxSubrayRecursion = rayParameters.maxSubrayRecursion !== undefined ? Math.floor( rayParameters.maxSubrayRecursion ) : 3;
-	rayParameters.maxSubrayRecursion = this.maxSubrayRecursion;
-	this.recursionProbability = rayParameters.recursionProbability !== undefined ? rayParameters.recursionProbability : 0.6;
-	rayParameters.recursionProbability = this.recursionProbability;
-	this.generateUVs = rayParameters.generateUVs !== undefined ? rayParameters.generateUVs : false;
-	rayParameters.generateUVs = this.generateUVs;
+		// Random generator
+		if ( rayParameters.randomGenerator !== undefined ) {
 
-	// Random generator
-	if ( rayParameters.randomGenerator !== undefined ) {
+			this.randomGenerator = rayParameters.randomGenerator;
+			this.seedGenerator = rayParameters.randomGenerator;
 
-		this.randomGenerator = rayParameters.randomGenerator;
-		this.seedGenerator = rayParameters.randomGenerator;
+			if ( rayParameters.noiseSeed !== undefined ) {
 
-		if ( rayParameters.noiseSeed !== undefined ) {
+				this.seedGenerator.setSeed( rayParameters.noiseSeed );
 
-			this.seedGenerator.setSeed( rayParameters.noiseSeed );
+			}
 
-		}
+		} else {
 
-	} else {
+			this.randomGenerator = LightningStrike.createRandomGenerator();
+			this.seedGenerator = Math;
 
-		this.randomGenerator = LightningStrike.createRandomGenerator();
-		this.seedGenerator = Math;
+		}
 
-	}
+		// Ray creation callbacks
+		if ( rayParameters.onDecideSubrayCreation !== undefined ) {
 
-	// Ray creation callbacks
-	if ( rayParameters.onDecideSubrayCreation !== undefined ) {
+			this.onDecideSubrayCreation = rayParameters.onDecideSubrayCreation;
 
-		this.onDecideSubrayCreation = rayParameters.onDecideSubrayCreation;
+		} else {
 
-	} else {
+			this.createDefaultSubrayCreationCallbacks();
 
-		this.createDefaultSubrayCreationCallbacks();
+			if ( rayParameters.onSubrayCreation !== undefined ) {
 
-		if ( rayParameters.onSubrayCreation !== undefined ) {
+				this.onSubrayCreation = rayParameters.onSubrayCreation;
 
-			this.onSubrayCreation = rayParameters.onSubrayCreation;
+			}
 
 		}
 
-	}
+		// Internal state
 
-	// Internal state
+		this.state = LightningStrike.RAY_INITIALIZED;
 
-	this.state = LightningStrike.RAY_INITIALIZED;
+		this.maxSubrays = Math.ceil( 1 + Math.pow( this.ramification, Math.max( 0, this.maxSubrayRecursion - 1 ) ) );
+		rayParameters.maxSubrays = this.maxSubrays;
 
-	this.maxSubrays = Math.ceil( 1 + Math.pow( this.ramification, Math.max( 0, this.maxSubrayRecursion - 1 ) ) );
-	rayParameters.maxSubrays = this.maxSubrays;
+		this.maxRaySegments = 2 * ( 1 << this.maxIterations );
 
-	this.maxRaySegments = 2 * ( 1 << this.maxIterations );
+		this.subrays = [];
 
-	this.subrays = [];
+		for ( let i = 0; i < this.maxSubrays; i ++ ) {
 
-	for ( var i = 0; i < this.maxSubrays; i ++ ) {
+			this.subrays.push( this.createSubray() );
 
-		this.subrays.push( this.createSubray() );
+		}
 
-	}
+		this.raySegments = [];
 
-	this.raySegments = [];
+		for ( let i = 0; i < this.maxRaySegments; i ++ ) {
 
-	for ( var i = 0; i < this.maxRaySegments; i ++ ) {
+			this.raySegments.push( this.createSegment() );
 
-		this.raySegments.push( this.createSegment() );
+		}
+
+		this.time = 0;
+		this.timeFraction = 0;
+		this.currentSegmentCallback = null;
+		this.currentCreateTriangleVertices = this.generateUVs ? this.createTriangleVerticesWithUVs : this.createTriangleVerticesWithoutUVs;
+		this.numSubrays = 0;
+		this.currentSubray = null;
+		this.currentSegmentIndex = 0;
+		this.isInitialSegment = false;
+		this.subrayProbability = 0;
+
+		this.currentVertex = 0;
+		this.currentIndex = 0;
+		this.currentCoordinate = 0;
+		this.currentUVCoordinate = 0;
+		this.vertices = null;
+		this.uvs = null;
+		this.indices = null;
+		this.positionAttribute = null;
+		this.uvsAttribute = null;
+
+		this.simplexX = new SimplexNoise( this.seedGenerator );
+		this.simplexY = new SimplexNoise( this.seedGenerator );
+		this.simplexZ = new SimplexNoise( this.seedGenerator );
+
+		// Temp vectors
+		this.forwards = new Vector3();
+		this.forwardsFill = new Vector3();
+		this.side = new Vector3();
+		this.down = new Vector3();
+		this.middlePos = new Vector3();
+		this.middleLinPos = new Vector3();
+		this.newPos = new Vector3();
+		this.vPos = new Vector3();
+		this.cross1 = new Vector3();
 
 	}
 
-	this.time = 0;
-	this.timeFraction = 0;
-	this.currentSegmentCallback = null;
-	this.currentCreateTriangleVertices = this.generateUVs ? this.createTriangleVerticesWithUVs : this.createTriangleVerticesWithoutUVs;
-	this.numSubrays = 0;
-	this.currentSubray = null;
-	this.currentSegmentIndex = 0;
-	this.isInitialSegment = false;
-	this.subrayProbability = 0;
-
-	this.currentVertex = 0;
-	this.currentIndex = 0;
-	this.currentCoordinate = 0;
-	this.currentUVCoordinate = 0;
-	this.vertices = null;
-	this.uvs = null;
-	this.indices = null;
-	this.positionAttribute = null;
-	this.uvsAttribute = null;
-
-	this.simplexX = new SimplexNoise( this.seedGenerator );
-	this.simplexY = new SimplexNoise( this.seedGenerator );
-	this.simplexZ = new SimplexNoise( this.seedGenerator );
-
-	// Temp vectors
-	this.forwards = new Vector3();
-	this.forwardsFill = new Vector3();
-	this.side = new Vector3();
-	this.down = new Vector3();
-	this.middlePos = new Vector3();
-	this.middleLinPos = new Vector3();
-	this.newPos = new Vector3();
-	this.vPos = new Vector3();
-	this.cross1 = new Vector3();
-
-};
-
-LightningStrike.prototype.createMesh = function () {
-
-	var maxDrawableSegmentsPerSubRay = 1 << this.maxIterations;
-
-	var maxVerts = 3 * ( maxDrawableSegmentsPerSubRay + 1 ) * this.maxSubrays;
-	var maxIndices = 18 * maxDrawableSegmentsPerSubRay * this.maxSubrays;
-
-	this.vertices = new Float32Array( maxVerts * 3 );
-	this.indices = new Uint32Array( maxIndices );
-	if ( this.generateUVs ) {
-
-		this.uvs = new Float32Array( maxVerts * 2 );
+	createMesh() {
 
-	}
+		const maxDrawableSegmentsPerSubRay = 1 << this.maxIterations;
 
-	// Populate the mesh
-	this.fillMesh( 0 );
+		const maxVerts = 3 * ( maxDrawableSegmentsPerSubRay + 1 ) * this.maxSubrays;
+		const maxIndices = 18 * maxDrawableSegmentsPerSubRay * this.maxSubrays;
 
-	this.setIndex( new Uint32BufferAttribute( this.indices, 1 ) );
+		this.vertices = new Float32Array( maxVerts * 3 );
+		this.indices = new Uint32Array( maxIndices );
 
-	this.positionAttribute = new Float32BufferAttribute( this.vertices, 3 );
-	this.setAttribute( 'position', this.positionAttribute );
+		if ( this.generateUVs ) {
 
-	if ( this.generateUVs ) {
+			this.uvs = new Float32Array( maxVerts * 2 );
 
-		this.uvsAttribute = new Float32BufferAttribute( new Float32Array( this.uvs ), 2 );
-		this.setAttribute( 'uv', this.uvsAttribute );
+		}
 
-	}
+		// Populate the mesh
+		this.fillMesh( 0 );
 
-	if ( ! this.isStatic ) {
+		this.setIndex( new Uint32BufferAttribute( this.indices, 1 ) );
+
+		this.positionAttribute = new Float32BufferAttribute( this.vertices, 3 );
+		this.setAttribute( 'position', this.positionAttribute );
 
-		this.index.usage = DynamicDrawUsage;
-		this.positionAttribute.usage = DynamicDrawUsage;
 		if ( this.generateUVs ) {
 
-			this.uvsAttribute.usage = DynamicDrawUsage;
+			this.uvsAttribute = new Float32BufferAttribute( new Float32Array( this.uvs ), 2 );
+			this.setAttribute( 'uv', this.uvsAttribute );
 
 		}
 
-	}
+		if ( ! this.isStatic ) {
 
-	// Store buffers for later modification
-	this.vertices = this.positionAttribute.array;
-	this.indices = this.index.array;
-	if ( this.generateUVs ) {
+			this.index.usage = DynamicDrawUsage;
+			this.positionAttribute.usage = DynamicDrawUsage;
 
-		this.uvs = this.uvsAttribute.array;
+			if ( this.generateUVs ) {
 
-	}
+				this.uvsAttribute.usage = DynamicDrawUsage;
 
-};
+			}
 
-LightningStrike.prototype.updateMesh = function ( time ) {
+		}
 
-	this.fillMesh( time );
+		// Store buffers for later modification
+		this.vertices = this.positionAttribute.array;
+		this.indices = this.index.array;
 
-	this.drawRange.count = this.currentIndex;
+		if ( this.generateUVs ) {
 
-	this.index.needsUpdate = true;
+			this.uvs = this.uvsAttribute.array;
 
-	this.positionAttribute.needsUpdate = true;
+		}
 
-	if ( this.generateUVs ) {
+	}
 
-		this.uvsAttribute.needsUpdate = true;
+	updateMesh( time ) {
 
-	}
+		this.fillMesh( time );
 
-};
+		this.drawRange.count = this.currentIndex;
 
-LightningStrike.prototype.fillMesh = function ( time ) {
+		this.index.needsUpdate = true;
 
-	var scope = this;
+		this.positionAttribute.needsUpdate = true;
 
-	this.currentVertex = 0;
-	this.currentIndex = 0;
-	this.currentCoordinate = 0;
-	this.currentUVCoordinate = 0;
+		if ( this.generateUVs ) {
 
-	this.fractalRay( time, function fillVertices( segment ) {
+			this.uvsAttribute.needsUpdate = true;
 
-		var subray = scope.currentSubray;
+		}
 
-		if ( time < subray.birthTime ) { //&& ( ! this.rayParameters.isEternal || scope.currentSubray.recursion > 0 ) ) {
+	}
 
-			return;
+	fillMesh( time ) {
 
-		} else if ( this.rayParameters.isEternal && scope.currentSubray.recursion == 0 ) {
+		const scope = this;
 
-			// Eternal rays don't propagate nor vanish, but its subrays do
+		this.currentVertex = 0;
+		this.currentIndex = 0;
+		this.currentCoordinate = 0;
+		this.currentUVCoordinate = 0;
 
-			scope.createPrism( segment );
+		this.fractalRay( time, function fillVertices( segment ) {
 
-			scope.onDecideSubrayCreation( segment, scope );
+			const subray = scope.currentSubray;
 
-		} else if ( time < subray.endPropagationTime ) {
+			if ( time < subray.birthTime ) { //&& ( ! this.rayParameters.isEternal || scope.currentSubray.recursion > 0 ) ) {
 
-			if ( scope.timeFraction >= segment.fraction0 * subray.propagationTimeFactor ) {
+				return;
 
-				// Ray propagation has arrived to this segment
+			} else if ( this.rayParameters.isEternal && scope.currentSubray.recursion == 0 ) {
+
+				// Eternal rays don't propagate nor vanish, but its subrays do
 
 				scope.createPrism( segment );
 
 				scope.onDecideSubrayCreation( segment, scope );
 
-			}
+			} else if ( time < subray.endPropagationTime ) {
 
-		} else if ( time < subray.beginVanishingTime ) {
+				if ( scope.timeFraction >= segment.fraction0 * subray.propagationTimeFactor ) {
 
-			// Ray is steady (nor propagating nor vanishing)
+					// Ray propagation has arrived to this segment
 
-			scope.createPrism( segment );
+					scope.createPrism( segment );
 
-			scope.onDecideSubrayCreation( segment, scope );
+					scope.onDecideSubrayCreation( segment, scope );
 
-		} else {
+				}
 
-			if ( scope.timeFraction <= subray.vanishingTimeFactor + segment.fraction1 * ( 1 - subray.vanishingTimeFactor ) ) {
+			} else if ( time < subray.beginVanishingTime ) {
 
-				// Segment has not yet vanished
+				// Ray is steady (nor propagating nor vanishing)
 
 				scope.createPrism( segment );
 
-			}
+				scope.onDecideSubrayCreation( segment, scope );
 
-			scope.onDecideSubrayCreation( segment, scope );
+			} else {
 
-		}
+				if ( scope.timeFraction <= subray.vanishingTimeFactor + segment.fraction1 * ( 1 - subray.vanishingTimeFactor ) ) {
 
-	} );
+					// Segment has not yet vanished
 
-};
+					scope.createPrism( segment );
 
-LightningStrike.prototype.addNewSubray = function ( /*rayParameters*/ ) {
+				}
 
-	return this.subrays[ this.numSubrays ++ ];
+				scope.onDecideSubrayCreation( segment, scope );
 
-};
+			}
 
-LightningStrike.prototype.initSubray = function ( subray, rayParameters ) {
+		} );
 
-	subray.pos0.copy( rayParameters.sourceOffset );
-	subray.pos1.copy( rayParameters.destOffset );
-	subray.up0.copy( rayParameters.up0 );
-	subray.up1.copy( rayParameters.up1 );
-	subray.radius0 = rayParameters.radius0;
-	subray.radius1 = rayParameters.radius1;
-	subray.birthTime = rayParameters.birthTime;
-	subray.deathTime = rayParameters.deathTime;
-	subray.timeScale = rayParameters.timeScale;
-	subray.roughness = rayParameters.roughness;
-	subray.straightness = rayParameters.straightness;
-	subray.propagationTimeFactor = rayParameters.propagationTimeFactor;
-	subray.vanishingTimeFactor = rayParameters.vanishingTimeFactor;
+	}
 
-	subray.maxIterations = this.maxIterations;
-	subray.seed = rayParameters.noiseSeed !== undefined ? rayParameters.noiseSeed : 0;
-	subray.recursion = 0;
+	addNewSubray( /*rayParameters*/ ) {
 
-};
+		return this.subrays[ this.numSubrays ++ ];
 
-LightningStrike.prototype.fractalRay = function ( time, segmentCallback ) {
+	}
 
-	this.time = time;
-	this.currentSegmentCallback = segmentCallback;
-	this.numSubrays = 0;
+	initSubray( subray, rayParameters ) {
+
+		subray.pos0.copy( rayParameters.sourceOffset );
+		subray.pos1.copy( rayParameters.destOffset );
+		subray.up0.copy( rayParameters.up0 );
+		subray.up1.copy( rayParameters.up1 );
+		subray.radius0 = rayParameters.radius0;
+		subray.radius1 = rayParameters.radius1;
+		subray.birthTime = rayParameters.birthTime;
+		subray.deathTime = rayParameters.deathTime;
+		subray.timeScale = rayParameters.timeScale;
+		subray.roughness = rayParameters.roughness;
+		subray.straightness = rayParameters.straightness;
+		subray.propagationTimeFactor = rayParameters.propagationTimeFactor;
+		subray.vanishingTimeFactor = rayParameters.vanishingTimeFactor;
+
+		subray.maxIterations = this.maxIterations;
+		subray.seed = rayParameters.noiseSeed !== undefined ? rayParameters.noiseSeed : 0;
+		subray.recursion = 0;
 
-	// Add the top level subray
-	this.initSubray( this.addNewSubray(), this.rayParameters );
+	}
 
-	// Process all subrays that are being generated until consuming all of them
-	for ( var subrayIndex = 0; subrayIndex < this.numSubrays; subrayIndex ++ ) {
+	fractalRay( time, segmentCallback ) {
 
-		var subray = this.subrays[ subrayIndex ];
-		this.currentSubray = subray;
+		this.time = time;
+		this.currentSegmentCallback = segmentCallback;
+		this.numSubrays = 0;
 
-		this.randomGenerator.setSeed( subray.seed );
+		// Add the top level subray
+		this.initSubray( this.addNewSubray(), this.rayParameters );
 
-		subray.endPropagationTime = MathUtils.lerp( subray.birthTime, subray.deathTime, subray.propagationTimeFactor );
-		subray.beginVanishingTime = MathUtils.lerp( subray.deathTime, subray.birthTime, 1 - subray.vanishingTimeFactor );
+		// Process all subrays that are being generated until consuming all of them
+		for ( let subrayIndex = 0; subrayIndex < this.numSubrays; subrayIndex ++ ) {
 
-		var random1 = this.randomGenerator.random;
-		subray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
-		subray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+			const subray = this.subrays[ subrayIndex ];
+			this.currentSubray = subray;
 
-		this.timeFraction = ( time - subray.birthTime ) / ( subray.deathTime - subray.birthTime );
+			this.randomGenerator.setSeed( subray.seed );
 
-		this.currentSegmentIndex = 0;
-		this.isInitialSegment = true;
-
-		var segment = this.getNewSegment();
-		segment.iteration = 0;
-		segment.pos0.copy( subray.pos0 );
-		segment.pos1.copy( subray.pos1 );
-		segment.linPos0.copy( subray.linPos0 );
-		segment.linPos1.copy( subray.linPos1 );
-		segment.up0.copy( subray.up0 );
-		segment.up1.copy( subray.up1 );
-		segment.radius0 = subray.radius0;
-		segment.radius1 = subray.radius1;
-		segment.fraction0 = 0;
-		segment.fraction1 = 1;
-		segment.positionVariationFactor = 1 - subray.straightness;
-
-		this.subrayProbability = this.ramification * Math.pow( this.recursionProbability, subray.recursion ) / ( 1 << subray.maxIterations );
-
-		this.fractalRayRecursive( segment );
+			subray.endPropagationTime = MathUtils.lerp( subray.birthTime, subray.deathTime, subray.propagationTimeFactor );
+			subray.beginVanishingTime = MathUtils.lerp( subray.deathTime, subray.birthTime, 1 - subray.vanishingTimeFactor );
 
-	}
+			const random1 = this.randomGenerator.random;
+			subray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+			subray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
 
-	this.currentSegmentCallback = null;
-	this.currentSubray = null;
+			this.timeFraction = ( time - subray.birthTime ) / ( subray.deathTime - subray.birthTime );
 
-};
+			this.currentSegmentIndex = 0;
+			this.isInitialSegment = true;
 
-LightningStrike.prototype.fractalRayRecursive = function ( segment ) {
+			const segment = this.getNewSegment();
+			segment.iteration = 0;
+			segment.pos0.copy( subray.pos0 );
+			segment.pos1.copy( subray.pos1 );
+			segment.linPos0.copy( subray.linPos0 );
+			segment.linPos1.copy( subray.linPos1 );
+			segment.up0.copy( subray.up0 );
+			segment.up1.copy( subray.up1 );
+			segment.radius0 = subray.radius0;
+			segment.radius1 = subray.radius1;
+			segment.fraction0 = 0;
+			segment.fraction1 = 1;
+			segment.positionVariationFactor = 1 - subray.straightness;
 
-	// Leave recursion condition
-	if ( segment.iteration >= this.currentSubray.maxIterations ) {
+			this.subrayProbability = this.ramification * Math.pow( this.recursionProbability, subray.recursion ) / ( 1 << subray.maxIterations );
 
-		this.currentSegmentCallback( segment );
+			this.fractalRayRecursive( segment );
 
-		return;
+		}
 
-	}
+		this.currentSegmentCallback = null;
+		this.currentSubray = null;
 
-	// Interpolation
-	this.forwards.subVectors( segment.pos1, segment.pos0 );
-	var lForwards = this.forwards.length();
+	}
 
-	if ( lForwards < 0.000001 ) {
+	fractalRayRecursive( segment ) {
 
-		this.forwards.set( 0, 0, 0.01 );
-		lForwards = this.forwards.length();
+		// Leave recursion condition
+		if ( segment.iteration >= this.currentSubray.maxIterations ) {
 
-	}
+			this.currentSegmentCallback( segment );
 
-	var middleRadius = ( segment.radius0 + segment.radius1 ) * 0.5;
-	var middleFraction = ( segment.fraction0 + segment.fraction1 ) * 0.5;
+			return;
 
-	var timeDimension = this.time * this.currentSubray.timeScale * Math.pow( 2, segment.iteration );
+		}
 
-	this.middlePos.lerpVectors( segment.pos0, segment.pos1, 0.5 );
-	this.middleLinPos.lerpVectors( segment.linPos0, segment.linPos1, 0.5 );
-	var p = this.middleLinPos;
+		// Interpolation
+		this.forwards.subVectors( segment.pos1, segment.pos0 );
+		let lForwards = this.forwards.length();
 
-	// Noise
-	this.newPos.set( this.simplexX.noise4d( p.x, p.y, p.z, timeDimension ),
-		this.simplexY.noise4d( p.x, p.y, p.z, timeDimension ),
-		this.simplexZ.noise4d( p.x, p.y, p.z, timeDimension ) );
+		if ( lForwards < 0.000001 ) {
 
-	this.newPos.multiplyScalar( segment.positionVariationFactor * lForwards );
-	this.newPos.add( this.middlePos );
+			this.forwards.set( 0, 0, 0.01 );
+			lForwards = this.forwards.length();
 
-	// Recursion
+		}
 
-	var newSegment1 = this.getNewSegment();
-	newSegment1.pos0.copy( segment.pos0 );
-	newSegment1.pos1.copy( this.newPos );
-	newSegment1.linPos0.copy( segment.linPos0 );
-	newSegment1.linPos1.copy( this.middleLinPos );
-	newSegment1.up0.copy( segment.up0 );
-	newSegment1.up1.copy( segment.up1 );
-	newSegment1.radius0 = segment.radius0;
-	newSegment1.radius1 = middleRadius;
-	newSegment1.fraction0 = segment.fraction0;
-	newSegment1.fraction1 = middleFraction;
-	newSegment1.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
-	newSegment1.iteration = segment.iteration + 1;
+		const middleRadius = ( segment.radius0 + segment.radius1 ) * 0.5;
+		const middleFraction = ( segment.fraction0 + segment.fraction1 ) * 0.5;
+
+		const timeDimension = this.time * this.currentSubray.timeScale * Math.pow( 2, segment.iteration );
+
+		this.middlePos.lerpVectors( segment.pos0, segment.pos1, 0.5 );
+		this.middleLinPos.lerpVectors( segment.linPos0, segment.linPos1, 0.5 );
+		const p = this.middleLinPos;
+
+		// Noise
+		this.newPos.set( this.simplexX.noise4d( p.x, p.y, p.z, timeDimension ),
+			this.simplexY.noise4d( p.x, p.y, p.z, timeDimension ),
+			this.simplexZ.noise4d( p.x, p.y, p.z, timeDimension ) );
+
+		this.newPos.multiplyScalar( segment.positionVariationFactor * lForwards );
+		this.newPos.add( this.middlePos );
+
+		// Recursion
+
+		const newSegment1 = this.getNewSegment();
+		newSegment1.pos0.copy( segment.pos0 );
+		newSegment1.pos1.copy( this.newPos );
+		newSegment1.linPos0.copy( segment.linPos0 );
+		newSegment1.linPos1.copy( this.middleLinPos );
+		newSegment1.up0.copy( segment.up0 );
+		newSegment1.up1.copy( segment.up1 );
+		newSegment1.radius0 = segment.radius0;
+		newSegment1.radius1 = middleRadius;
+		newSegment1.fraction0 = segment.fraction0;
+		newSegment1.fraction1 = middleFraction;
+		newSegment1.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
+		newSegment1.iteration = segment.iteration + 1;
+
+		const newSegment2 = this.getNewSegment();
+		newSegment2.pos0.copy( this.newPos );
+		newSegment2.pos1.copy( segment.pos1 );
+		newSegment2.linPos0.copy( this.middleLinPos );
+		newSegment2.linPos1.copy( segment.linPos1 );
+		this.cross1.crossVectors( segment.up0, this.forwards.normalize() );
+		newSegment2.up0.crossVectors( this.forwards, this.cross1 ).normalize();
+		newSegment2.up1.copy( segment.up1 );
+		newSegment2.radius0 = middleRadius;
+		newSegment2.radius1 = segment.radius1;
+		newSegment2.fraction0 = middleFraction;
+		newSegment2.fraction1 = segment.fraction1;
+		newSegment2.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
+		newSegment2.iteration = segment.iteration + 1;
+
+		this.fractalRayRecursive( newSegment1 );
+
+		this.fractalRayRecursive( newSegment2 );
 
-	var newSegment2 = this.getNewSegment();
-	newSegment2.pos0.copy( this.newPos );
-	newSegment2.pos1.copy( segment.pos1 );
-	newSegment2.linPos0.copy( this.middleLinPos );
-	newSegment2.linPos1.copy( segment.linPos1 );
-	this.cross1.crossVectors( segment.up0, this.forwards.normalize() );
-	newSegment2.up0.crossVectors( this.forwards, this.cross1 ).normalize();
-	newSegment2.up1.copy( segment.up1 );
-	newSegment2.radius0 = middleRadius;
-	newSegment2.radius1 = segment.radius1;
-	newSegment2.fraction0 = middleFraction;
-	newSegment2.fraction1 = segment.fraction1;
-	newSegment2.positionVariationFactor = segment.positionVariationFactor * this.currentSubray.roughness;
-	newSegment2.iteration = segment.iteration + 1;
+	}
 
-	this.fractalRayRecursive( newSegment1 );
+	createPrism( segment ) {
 
-	this.fractalRayRecursive( newSegment2 );
+		// Creates one triangular prism and its vertices at the segment
 
-};
+		this.forwardsFill.subVectors( segment.pos1, segment.pos0 ).normalize();
 
-LightningStrike.prototype.createPrism = function ( segment ) {
+		if ( this.isInitialSegment ) {
 
-	// Creates one triangular prism and its vertices at the segment
+			this.currentCreateTriangleVertices( segment.pos0, segment.up0, this.forwardsFill, segment.radius0, 0 );
 
-	this.forwardsFill.subVectors( segment.pos1, segment.pos0 ).normalize();
+			this.isInitialSegment = false;
 
-	if ( this.isInitialSegment ) {
+		}
 
-		this.currentCreateTriangleVertices( segment.pos0, segment.up0, this.forwardsFill, segment.radius0, 0 );
+		this.currentCreateTriangleVertices( segment.pos1, segment.up0, this.forwardsFill, segment.radius1, segment.fraction1 );
 
-		this.isInitialSegment = false;
+		this.createPrismFaces();
 
 	}
 
-	this.currentCreateTriangleVertices( segment.pos1, segment.up0, this.forwardsFill, segment.radius1, segment.fraction1 );
+	createTriangleVerticesWithoutUVs( pos, up, forwards, radius ) {
 
-	this.createPrismFaces();
+		// Create an equilateral triangle (only vertices)
 
-};
+		this.side.crossVectors( up, forwards ).multiplyScalar( radius * LightningStrike.COS30DEG );
+		this.down.copy( up ).multiplyScalar( - radius * LightningStrike.SIN30DEG );
 
-LightningStrike.prototype.createTriangleVerticesWithoutUVs = function ( pos, up, forwards, radius ) {
+		const p = this.vPos;
+		const v = this.vertices;
 
-	// Create an equilateral triangle (only vertices)
+		p.copy( pos ).sub( this.side ).add( this.down );
 
-	this.side.crossVectors( up, forwards ).multiplyScalar( radius * LightningStrike.COS30DEG );
-	this.down.copy( up ).multiplyScalar( - radius * LightningStrike.SIN30DEG );
+		v[ this.currentCoordinate ++ ] = p.x;
+		v[ this.currentCoordinate ++ ] = p.y;
+		v[ this.currentCoordinate ++ ] = p.z;
 
-	var p = this.vPos;
-	var v = this.vertices;
+		p.copy( pos ).add( this.side ).add( this.down );
 
-	p.copy( pos ).sub( this.side ).add( this.down );
+		v[ this.currentCoordinate ++ ] = p.x;
+		v[ this.currentCoordinate ++ ] = p.y;
+		v[ this.currentCoordinate ++ ] = p.z;
 
-	v[ this.currentCoordinate ++ ] = p.x;
-	v[ this.currentCoordinate ++ ] = p.y;
-	v[ this.currentCoordinate ++ ] = p.z;
+		p.copy( up ).multiplyScalar( radius ).add( pos );
 
-	p.copy( pos ).add( this.side ).add( this.down );
+		v[ this.currentCoordinate ++ ] = p.x;
+		v[ this.currentCoordinate ++ ] = p.y;
+		v[ this.currentCoordinate ++ ] = p.z;
 
-	v[ this.currentCoordinate ++ ] = p.x;
-	v[ this.currentCoordinate ++ ] = p.y;
-	v[ this.currentCoordinate ++ ] = p.z;
+		this.currentVertex += 3;
 
-	p.copy( up ).multiplyScalar( radius ).add( pos );
-
-	v[ this.currentCoordinate ++ ] = p.x;
-	v[ this.currentCoordinate ++ ] = p.y;
-	v[ this.currentCoordinate ++ ] = p.z;
+	}
 
-	this.currentVertex += 3;
+	createTriangleVerticesWithUVs( pos, up, forwards, radius, u ) {
 
-};
+		// Create an equilateral triangle (only vertices)
 
-LightningStrike.prototype.createTriangleVerticesWithUVs = function ( pos, up, forwards, radius, u ) {
+		this.side.crossVectors( up, forwards ).multiplyScalar( radius * LightningStrike.COS30DEG );
+		this.down.copy( up ).multiplyScalar( - radius * LightningStrike.SIN30DEG );
 
-	// Create an equilateral triangle (only vertices)
+		const p = this.vPos;
+		const v = this.vertices;
+		const uv = this.uvs;
 
-	this.side.crossVectors( up, forwards ).multiplyScalar( radius * LightningStrike.COS30DEG );
-	this.down.copy( up ).multiplyScalar( - radius * LightningStrike.SIN30DEG );
+		p.copy( pos ).sub( this.side ).add( this.down );
 
-	var p = this.vPos;
-	var v = this.vertices;
-	var uv = this.uvs;
+		v[ this.currentCoordinate ++ ] = p.x;
+		v[ this.currentCoordinate ++ ] = p.y;
+		v[ this.currentCoordinate ++ ] = p.z;
 
-	p.copy( pos ).sub( this.side ).add( this.down );
+		uv[ this.currentUVCoordinate ++ ] = u;
+		uv[ this.currentUVCoordinate ++ ] = 0;
 
-	v[ this.currentCoordinate ++ ] = p.x;
-	v[ this.currentCoordinate ++ ] = p.y;
-	v[ this.currentCoordinate ++ ] = p.z;
+		p.copy( pos ).add( this.side ).add( this.down );
 
-	uv[ this.currentUVCoordinate ++ ] = u;
-	uv[ this.currentUVCoordinate ++ ] = 0;
+		v[ this.currentCoordinate ++ ] = p.x;
+		v[ this.currentCoordinate ++ ] = p.y;
+		v[ this.currentCoordinate ++ ] = p.z;
 
-	p.copy( pos ).add( this.side ).add( this.down );
+		uv[ this.currentUVCoordinate ++ ] = u;
+		uv[ this.currentUVCoordinate ++ ] = 0.5;
 
-	v[ this.currentCoordinate ++ ] = p.x;
-	v[ this.currentCoordinate ++ ] = p.y;
-	v[ this.currentCoordinate ++ ] = p.z;
+		p.copy( up ).multiplyScalar( radius ).add( pos );
 
-	uv[ this.currentUVCoordinate ++ ] = u;
-	uv[ this.currentUVCoordinate ++ ] = 0.5;
+		v[ this.currentCoordinate ++ ] = p.x;
+		v[ this.currentCoordinate ++ ] = p.y;
+		v[ this.currentCoordinate ++ ] = p.z;
 
-	p.copy( up ).multiplyScalar( radius ).add( pos );
+		uv[ this.currentUVCoordinate ++ ] = u;
+		uv[ this.currentUVCoordinate ++ ] = 1;
 
-	v[ this.currentCoordinate ++ ] = p.x;
-	v[ this.currentCoordinate ++ ] = p.y;
-	v[ this.currentCoordinate ++ ] = p.z;
+		this.currentVertex += 3;
 
-	uv[ this.currentUVCoordinate ++ ] = u;
-	uv[ this.currentUVCoordinate ++ ] = 1;
+	}
 
-	this.currentVertex += 3;
+	createPrismFaces( vertex/*, index*/ ) {
+
+		const indices = this.indices;
+		vertex = this.currentVertex - 6;
+
+		indices[ this.currentIndex ++ ] = vertex + 1;
+		indices[ this.currentIndex ++ ] = vertex + 2;
+		indices[ this.currentIndex ++ ] = vertex + 5;
+		indices[ this.currentIndex ++ ] = vertex + 1;
+		indices[ this.currentIndex ++ ] = vertex + 5;
+		indices[ this.currentIndex ++ ] = vertex + 4;
+		indices[ this.currentIndex ++ ] = vertex + 0;
+		indices[ this.currentIndex ++ ] = vertex + 1;
+		indices[ this.currentIndex ++ ] = vertex + 4;
+		indices[ this.currentIndex ++ ] = vertex + 0;
+		indices[ this.currentIndex ++ ] = vertex + 4;
+		indices[ this.currentIndex ++ ] = vertex + 3;
+		indices[ this.currentIndex ++ ] = vertex + 2;
+		indices[ this.currentIndex ++ ] = vertex + 0;
+		indices[ this.currentIndex ++ ] = vertex + 3;
+		indices[ this.currentIndex ++ ] = vertex + 2;
+		indices[ this.currentIndex ++ ] = vertex + 3;
+		indices[ this.currentIndex ++ ] = vertex + 5;
 
-};
+	}
 
-LightningStrike.prototype.createPrismFaces = function ( vertex/*, index*/ ) {
+	createDefaultSubrayCreationCallbacks() {
 
-	var indices = this.indices;
-	var vertex = this.currentVertex - 6;
+		const random1 = this.randomGenerator.random;
 
-	indices[ this.currentIndex ++ ] = vertex + 1;
-	indices[ this.currentIndex ++ ] = vertex + 2;
-	indices[ this.currentIndex ++ ] = vertex + 5;
-	indices[ this.currentIndex ++ ] = vertex + 1;
-	indices[ this.currentIndex ++ ] = vertex + 5;
-	indices[ this.currentIndex ++ ] = vertex + 4;
-	indices[ this.currentIndex ++ ] = vertex + 0;
-	indices[ this.currentIndex ++ ] = vertex + 1;
-	indices[ this.currentIndex ++ ] = vertex + 4;
-	indices[ this.currentIndex ++ ] = vertex + 0;
-	indices[ this.currentIndex ++ ] = vertex + 4;
-	indices[ this.currentIndex ++ ] = vertex + 3;
-	indices[ this.currentIndex ++ ] = vertex + 2;
-	indices[ this.currentIndex ++ ] = vertex + 0;
-	indices[ this.currentIndex ++ ] = vertex + 3;
-	indices[ this.currentIndex ++ ] = vertex + 2;
-	indices[ this.currentIndex ++ ] = vertex + 3;
-	indices[ this.currentIndex ++ ] = vertex + 5;
+		this.onDecideSubrayCreation = function ( segment, lightningStrike ) {
 
-};
+			// Decide subrays creation at parent (sub)ray segment
 
-LightningStrike.prototype.createDefaultSubrayCreationCallbacks = function () {
+			const subray = lightningStrike.currentSubray;
 
-	var random1 = this.randomGenerator.random;
+			const period = lightningStrike.rayParameters.subrayPeriod;
+			const dutyCycle = lightningStrike.rayParameters.subrayDutyCycle;
 
-	this.onDecideSubrayCreation = function ( segment, lightningStrike ) {
+			const phase0 = ( lightningStrike.rayParameters.isEternal && subray.recursion == 0 ) ? - random1() * period : MathUtils.lerp( subray.birthTime, subray.endPropagationTime, segment.fraction0 ) - random1() * period;
 
-		// Decide subrays creation at parent (sub)ray segment
+			const phase = lightningStrike.time - phase0;
+			const currentCycle = Math.floor( phase / period );
 
-		var subray = lightningStrike.currentSubray;
+			const childSubraySeed = random1() * ( currentCycle + 1 );
 
-		var period = lightningStrike.rayParameters.subrayPeriod;
-		var dutyCycle = lightningStrike.rayParameters.subrayDutyCycle;
+			const isActive = phase % period <= dutyCycle * period;
 
-		var phase0 = ( lightningStrike.rayParameters.isEternal && subray.recursion == 0 ) ? - random1() * period : MathUtils.lerp( subray.birthTime, subray.endPropagationTime, segment.fraction0 ) - random1() * period;
+			let probability = 0;
 
-		var phase = lightningStrike.time - phase0;
-		var currentCycle = Math.floor( phase / period );
+			if ( isActive ) {
 
-		var childSubraySeed = random1() * ( currentCycle + 1 );
+				probability = lightningStrike.subrayProbability;
+				// Distribution test: probability *= segment.fraction0 > 0.5 && segment.fraction0 < 0.9 ? 1 / 0.4 : 0;
 
-		var isActive = phase % period <= dutyCycle * period;
+			}
 
-		var probability = 0;
+			if ( subray.recursion < lightningStrike.maxSubrayRecursion && lightningStrike.numSubrays < lightningStrike.maxSubrays && random1() < probability ) {
 
-		if ( isActive ) {
+				const childSubray = lightningStrike.addNewSubray();
 
-			probability = lightningStrike.subrayProbability;
-			// Distribution test: probability *= segment.fraction0 > 0.5 && segment.fraction0 < 0.9 ? 1 / 0.4 : 0;
+				const parentSeed = lightningStrike.randomGenerator.getSeed();
+				childSubray.seed = childSubraySeed;
+				lightningStrike.randomGenerator.setSeed( childSubraySeed );
 
-		}
+				childSubray.recursion = subray.recursion + 1;
+				childSubray.maxIterations = Math.max( 1, subray.maxIterations - 1 );
 
-		if ( subray.recursion < lightningStrike.maxSubrayRecursion && lightningStrike.numSubrays < lightningStrike.maxSubrays && random1() < probability ) {
+				childSubray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+				childSubray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
+				childSubray.up0.copy( subray.up0 );
+				childSubray.up1.copy( subray.up1 );
+				childSubray.radius0 = segment.radius0 * lightningStrike.rayParameters.radius0Factor;
+				childSubray.radius1 = Math.min( lightningStrike.rayParameters.minRadius, segment.radius1 * lightningStrike.rayParameters.radius1Factor );
 
-			var childSubray = lightningStrike.addNewSubray();
+				childSubray.birthTime = phase0 + ( currentCycle ) * period;
+				childSubray.deathTime = childSubray.birthTime + period * dutyCycle;
 
-			var parentSeed = lightningStrike.randomGenerator.getSeed();
-			childSubray.seed = childSubraySeed;
-			lightningStrike.randomGenerator.setSeed( childSubraySeed );
+				if ( ! lightningStrike.rayParameters.isEternal && subray.recursion == 0 ) {
 
-			childSubray.recursion = subray.recursion + 1;
-			childSubray.maxIterations = Math.max( 1, subray.maxIterations - 1 );
+					childSubray.birthTime = Math.max( childSubray.birthTime, subray.birthTime );
+					childSubray.deathTime = Math.min( childSubray.deathTime, subray.deathTime );
 
-			childSubray.linPos0.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
-			childSubray.linPos1.set( random1(), random1(), random1() ).multiplyScalar( 1000 );
-			childSubray.up0.copy( subray.up0 );
-			childSubray.up1.copy( subray.up1 );
-			childSubray.radius0 = segment.radius0 * lightningStrike.rayParameters.radius0Factor;
-			childSubray.radius1 = Math.min( lightningStrike.rayParameters.minRadius, segment.radius1 * lightningStrike.rayParameters.radius1Factor );
+				}
 
-			childSubray.birthTime = phase0 + ( currentCycle ) * period;
-			childSubray.deathTime = childSubray.birthTime + period * dutyCycle;
+				childSubray.timeScale = subray.timeScale * 2;
+				childSubray.roughness = subray.roughness;
+				childSubray.straightness = subray.straightness;
+				childSubray.propagationTimeFactor = subray.propagationTimeFactor;
+				childSubray.vanishingTimeFactor = subray.vanishingTimeFactor;
 
-			if ( ! lightningStrike.rayParameters.isEternal && subray.recursion == 0 ) {
+				lightningStrike.onSubrayCreation( segment, subray, childSubray, lightningStrike );
 
-				childSubray.birthTime = Math.max( childSubray.birthTime, subray.birthTime );
-				childSubray.deathTime = Math.min( childSubray.deathTime, subray.deathTime );
+				lightningStrike.randomGenerator.setSeed( parentSeed );
 
 			}
 
-			childSubray.timeScale = subray.timeScale * 2;
-			childSubray.roughness = subray.roughness;
-			childSubray.straightness = subray.straightness;
-			childSubray.propagationTimeFactor = subray.propagationTimeFactor;
-			childSubray.vanishingTimeFactor = subray.vanishingTimeFactor;
-
-			lightningStrike.onSubrayCreation( segment, subray, childSubray, lightningStrike );
+		};
 
-			lightningStrike.randomGenerator.setSeed( parentSeed );
+		const vec1Pos = new Vector3();
+		const vec2Forward = new Vector3();
+		const vec3Side = new Vector3();
+		const vec4Up = new Vector3();
 
-		}
-
-	};
-
-	var vec1Pos = new Vector3();
-	var vec2Forward = new Vector3();
-	var vec3Side = new Vector3();
-	var vec4Up = new Vector3();
-
-	this.onSubrayCreation = function ( segment, parentSubray, childSubray, lightningStrike ) {
+		this.onSubrayCreation = function ( segment, parentSubray, childSubray, lightningStrike ) {
 
-		// Decide childSubray origin and destination positions (pos0 and pos1) and possibly other properties of childSubray
+			// Decide childSubray origin and destination positions (pos0 and pos1) and possibly other properties of childSubray
 
-		// Just use the default cone position generator
-		lightningStrike.subrayCylinderPosition( segment, parentSubray, childSubray, 0.5, 0.6, 0.2 );
+			// Just use the default cone position generator
+			lightningStrike.subrayCylinderPosition( segment, parentSubray, childSubray, 0.5, 0.6, 0.2 );
 
-	};
+		};
 
-	this.subrayConePosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
+		this.subrayConePosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
 
-		// Sets childSubray pos0 and pos1 in a cone
+			// Sets childSubray pos0 and pos1 in a cone
 
-		childSubray.pos0.copy( segment.pos0 );
+			childSubray.pos0.copy( segment.pos0 );
 
-		vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
-		vec2Forward.copy( vec1Pos ).normalize();
-		vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( random1() * heightFactor ) );
-		var length = vec1Pos.length();
-		vec3Side.crossVectors( parentSubray.up0, vec2Forward );
-		var angle = 2 * Math.PI * random1();
-		vec3Side.multiplyScalar( Math.cos( angle ) );
-		vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin( angle ) );
+			vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
+			vec2Forward.copy( vec1Pos ).normalize();
+			vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( random1() * heightFactor ) );
+			const length = vec1Pos.length();
+			vec3Side.crossVectors( parentSubray.up0, vec2Forward );
+			const angle = 2 * Math.PI * random1();
+			vec3Side.multiplyScalar( Math.cos( angle ) );
+			vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin( angle ) );
 
-		childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
+			childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
 
-	};
+		};
 
-	this.subrayCylinderPosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
+		this.subrayCylinderPosition = function ( segment, parentSubray, childSubray, heightFactor, sideWidthFactor, minSideWidthFactor ) {
 
-		// Sets childSubray pos0 and pos1 in a cylinder
+			// Sets childSubray pos0 and pos1 in a cylinder
 
-		childSubray.pos0.copy( segment.pos0 );
+			childSubray.pos0.copy( segment.pos0 );
 
-		vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
-		vec2Forward.copy( vec1Pos ).normalize();
-		vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( ( 2 * random1() - 1 ) * heightFactor ) );
-		var length = vec1Pos.length();
-		vec3Side.crossVectors( parentSubray.up0, vec2Forward );
-		var angle = 2 * Math.PI * random1();
-		vec3Side.multiplyScalar( Math.cos( angle ) );
-		vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin( angle ) );
+			vec1Pos.subVectors( parentSubray.pos1, parentSubray.pos0 );
+			vec2Forward.copy( vec1Pos ).normalize();
+			vec1Pos.multiplyScalar( segment.fraction0 + ( 1 - segment.fraction0 ) * ( ( 2 * random1() - 1 ) * heightFactor ) );
+			const length = vec1Pos.length();
+			vec3Side.crossVectors( parentSubray.up0, vec2Forward );
+			const angle = 2 * Math.PI * random1();
+			vec3Side.multiplyScalar( Math.cos( angle ) );
+			vec4Up.copy( parentSubray.up0 ).multiplyScalar( Math.sin( angle ) );
 
-		childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
+			childSubray.pos1.copy( vec3Side ).add( vec4Up ).multiplyScalar( length * sideWidthFactor * ( minSideWidthFactor + random1() * ( 1 - minSideWidthFactor ) ) ).add( vec1Pos ).add( parentSubray.pos0 );
 
-	};
+		};
 
-};
+	}
 
-LightningStrike.prototype.createSubray = function () {
+	createSubray() {
+
+		return {
+
+			seed: 0,
+			maxIterations: 0,
+			recursion: 0,
+			pos0: new Vector3(),
+			pos1: new Vector3(),
+			linPos0: new Vector3(),
+			linPos1: new Vector3(),
+			up0: new Vector3(),
+			up1: new Vector3(),
+			radius0: 0,
+			radius1: 0,
+			birthTime: 0,
+			deathTime: 0,
+			timeScale: 0,
+			roughness: 0,
+			straightness: 0,
+			propagationTimeFactor: 0,
+			vanishingTimeFactor: 0,
+			endPropagationTime: 0,
+			beginVanishingTime: 0
+
+		};
 
-	return {
+	}
 
-		seed: 0,
-		maxIterations: 0,
-		recursion: 0,
-		pos0: new Vector3(),
-		pos1: new Vector3(),
-		linPos0: new Vector3(),
-		linPos1: new Vector3(),
-		up0: new Vector3(),
-		up1: new Vector3(),
-		radius0: 0,
-		radius1: 0,
-		birthTime: 0,
-		deathTime: 0,
-		timeScale: 0,
-		roughness: 0,
-		straightness: 0,
-		propagationTimeFactor: 0,
-		vanishingTimeFactor: 0,
-		endPropagationTime: 0,
-		beginVanishingTime: 0
+	createSegment() {
+
+		return {
+			iteration: 0,
+			pos0: new Vector3(),
+			pos1: new Vector3(),
+			linPos0: new Vector3(),
+			linPos1: new Vector3(),
+			up0: new Vector3(),
+			up1: new Vector3(),
+			radius0: 0,
+			radius1: 0,
+			fraction0: 0,
+			fraction1: 0,
+			positionVariationFactor: 0
+		};
 
-	};
+	}
 
-};
+	getNewSegment() {
 
-LightningStrike.prototype.createSegment = function () {
+		return this.raySegments[ this.currentSegmentIndex ++ ];
 
-	return {
-		iteration: 0,
-		pos0: new Vector3(),
-		pos1: new Vector3(),
-		linPos0: new Vector3(),
-		linPos1: new Vector3(),
-		up0: new Vector3(),
-		up1: new Vector3(),
-		radius0: 0,
-		radius1: 0,
-		fraction0: 0,
-		fraction1: 0,
-		positionVariationFactor: 0
-	};
+	}
 
-};
+	copy( source ) {
 
-LightningStrike.prototype.getNewSegment = function () {
+		super.copy( source );
 
-	return this.raySegments[ this.currentSegmentIndex ++ ];
+		this.init( LightningStrike.copyParameters( {}, source.rayParameters ) );
 
-};
+		return this;
 
-LightningStrike.prototype.copy = function ( source ) {
+	}
 
-	BufferGeometry.prototype.copy.call( this, source );
+	clone() {
 
-	this.init( LightningStrike.copyParameters( {}, source.rayParameters ) );
+		return new this.constructor( LightningStrike.copyParameters( {}, this.rayParameters ) );
 
-	return this;
+	}
 
-};
+}
 
-LightningStrike.prototype.clone = function () {
+LightningStrike.prototype.isLightningStrike = true;
 
-	return new this.constructor( LightningStrike.copyParameters( {}, this.rayParameters ) );
+// Ray states
+LightningStrike.RAY_INITIALIZED = 0;
+LightningStrike.RAY_UNBORN = 1;
+LightningStrike.RAY_PROPAGATING = 2;
+LightningStrike.RAY_STEADY = 3;
+LightningStrike.RAY_VANISHING = 4;
+LightningStrike.RAY_EXTINGUISHED = 5;
 
-};
+LightningStrike.COS30DEG = Math.cos( 30 * Math.PI / 180 );
+LightningStrike.SIN30DEG = Math.sin( 30 * Math.PI / 180 );
 
 export { LightningStrike };

+ 100 - 108
examples/jsm/geometries/ParametricGeometries.js

@@ -1,5 +1,4 @@
 import {
-	BufferGeometry,
 	Curve,
 	ParametricGeometry,
 	Vector3
@@ -9,7 +8,7 @@ import {
  * Experimenting of primitive geometry creation using Surface Parametric equations
  */
 
-var ParametricGeometries = {
+const ParametricGeometries = {
 
 	klein: function ( v, u, target ) {
 
@@ -17,7 +16,7 @@ var ParametricGeometries = {
 		v *= 2 * Math.PI;
 
 		u = u * 2;
-		var x, y, z;
+		let x, z;
 		if ( u < Math.PI ) {
 
 			x = 3 * Math.cos( u ) * ( 1 + Math.sin( u ) ) + ( 2 * ( 1 - Math.cos( u ) / 2 ) ) * Math.cos( u ) * Math.cos( v );
@@ -30,7 +29,7 @@ var ParametricGeometries = {
 
 		}
 
-		y = - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( v );
+		const y = - 2 * ( 1 - Math.cos( u ) / 2 ) * Math.sin( v );
 
 		target.set( x, y, z );
 
@@ -40,9 +39,9 @@ var ParametricGeometries = {
 
 		return function ( u, v, target ) {
 
-			var x = u * width;
-			var y = 0;
-			var z = v * height;
+			const x = u * width;
+			const y = 0;
+			const z = v * height;
 
 			target.set( x, y, z );
 
@@ -55,15 +54,13 @@ var ParametricGeometries = {
 		// flat mobius strip
 		// http://www.wolframalpha.com/input/?i=M%C3%B6bius+strip+parametric+equations&lk=1&a=ClashPrefs_*Surface.MoebiusStrip.SurfaceProperty.ParametricEquations-
 		u = u - 0.5;
-		var v = 2 * Math.PI * t;
+		const v = 2 * Math.PI * t;
 
-		var x, y, z;
+		const a = 2;
 
-		var a = 2;
-
-		x = Math.cos( v ) * ( a + u * Math.cos( v / 2 ) );
-		y = Math.sin( v ) * ( a + u * Math.cos( v / 2 ) );
-		z = u * Math.sin( v / 2 );
+		const x = Math.cos( v ) * ( a + u * Math.cos( v / 2 ) );
+		const y = Math.sin( v ) * ( a + u * Math.cos( v / 2 ) );
+		const z = u * Math.sin( v / 2 );
 
 		target.set( x, y, z );
 
@@ -77,14 +74,12 @@ var ParametricGeometries = {
 		t *= 2 * Math.PI;
 
 		u = u * 2;
-		var phi = u / 2;
-		var major = 2.25, a = 0.125, b = 0.65;
-
-		var x, y, z;
+		const phi = u / 2;
+		const major = 2.25, a = 0.125, b = 0.65;
 
-		x = a * Math.cos( t ) * Math.cos( phi ) - b * Math.sin( t ) * Math.sin( phi );
-		z = a * Math.cos( t ) * Math.sin( phi ) + b * Math.sin( t ) * Math.cos( phi );
-		y = ( major + x ) * Math.sin( u );
+		let x = a * Math.cos( t ) * Math.cos( phi ) - b * Math.sin( t ) * Math.sin( phi );
+		const z = a * Math.cos( t ) * Math.sin( phi ) + b * Math.sin( t ) * Math.cos( phi );
+		const y = ( major + x ) * Math.sin( u );
 		x = ( major + x ) * Math.cos( u );
 
 		target.set( x, y, z );
@@ -100,58 +95,58 @@ var ParametricGeometries = {
  *
  *********************************************/
 
-ParametricGeometries.TubeGeometry = function ( path, segments, radius, segmentsRadius, closed ) {
+ParametricGeometries.TubeGeometry = class TubeGeometry extends ParametricGeometry {
 
-	this.path = path;
-	this.segments = segments || 64;
-	this.radius = radius || 1;
-	this.segmentsRadius = segmentsRadius || 8;
-	this.closed = closed || false;
+	constructor( path, segments = 64, radius = 1, segmentsRadius = 8, closed = false ) {
 
-	var scope = this, numpoints = this.segments + 1;
+		const numpoints = segments + 1;
 
-	var frames = path.computeFrenetFrames( segments, closed ),
-		tangents = frames.tangents,
-		normals = frames.normals,
-		binormals = frames.binormals;
+		const frames = path.computeFrenetFrames( segments, closed ),
+			tangents = frames.tangents,
+			normals = frames.normals,
+			binormals = frames.binormals;
 
-	// proxy internals
+		const position = new Vector3();
 
-	this.tangents = tangents;
-	this.normals = normals;
-	this.binormals = binormals;
+		function ParametricTube( u, v, target ) {
 
-	var position = new Vector3();
+			v *= 2 * Math.PI;
 
-	var ParametricTube = function ( u, v, target ) {
+			const i = Math.floor( u * ( numpoints - 1 ) );
 
-		v *= 2 * Math.PI;
+			path.getPointAt( u, position );
+
+			const normal = normals[ i ];
+			const binormal = binormals[ i ];
 
-		var i = u * ( numpoints - 1 );
-		i = Math.floor( i );
+			const cx = - radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
+			const cy = radius * Math.sin( v );
 
-		path.getPointAt( u, position );
+			position.x += cx * normal.x + cy * binormal.x;
+			position.y += cx * normal.y + cy * binormal.y;
+			position.z += cx * normal.z + cy * binormal.z;
 
-		var normal = normals[ i ];
-		var binormal = binormals[ i ];
+			target.copy( position );
 
-		var cx = - scope.radius * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
-		var cy = scope.radius * Math.sin( v );
+		}
 
-		position.x += cx * normal.x + cy * binormal.x;
-		position.y += cx * normal.y + cy * binormal.y;
-		position.z += cx * normal.z + cy * binormal.z;
+		super( ParametricTube, segments, segmentsRadius );
 
-		target.copy( position );
+		// proxy internals
 
-	};
+		this.tangents = tangents;
+		this.normals = normals;
+		this.binormals = binormals;
 
-	ParametricGeometry.call( this, ParametricTube, segments, segmentsRadius );
+		this.path = path;
+		this.segments = segments;
+		this.radius = radius;
+		this.segmentsRadius = segmentsRadius;
+		this.closed = closed;
 
-};
+	}
 
-ParametricGeometries.TubeGeometry.prototype = Object.create( BufferGeometry.prototype );
-ParametricGeometries.TubeGeometry.prototype.constructor = ParametricGeometries.TubeGeometry;
+};
 
 
 /*********************************************
@@ -159,78 +154,74 @@ ParametricGeometries.TubeGeometry.prototype.constructor = ParametricGeometries.T
   * Parametric Replacement for TorusKnotGeometry
   *
   *********************************************/
-ParametricGeometries.TorusKnotGeometry = function ( radius, tube, segmentsT, segmentsR, p, q ) {
+ParametricGeometries.TorusKnotGeometry = class TorusKnotGeometry extends ParametricGeometries.TubeGeometry {
 
-	this.radius = radius || 200;
-	this.tube = tube || 40;
-	this.segmentsT = segmentsT || 64;
-	this.segmentsR = segmentsR || 8;
-	this.p = p || 2;
-	this.q = q || 3;
+	constructor( radius = 200, tube = 40, segmentsT = 64, segmentsR = 8, p = 2, q = 3 ) {
 
-	function TorusKnotCurve() {
+		class TorusKnotCurve extends Curve {
 
-		Curve.call( this );
+			getPoint( t, optionalTarget = new Vector3() ) {
 
-	}
+				const point = optionalTarget;
 
-	TorusKnotCurve.prototype = Object.create( Curve.prototype );
-	TorusKnotCurve.prototype.constructor = TorusKnotCurve;
+				t *= Math.PI * 2;
 
-	TorusKnotCurve.prototype.getPoint = function ( t, optionalTarget ) {
+				const r = 0.5;
 
-		var point = optionalTarget || new Vector3();
+				const x = ( 1 + r * Math.cos( q * t ) ) * Math.cos( p * t );
+				const y = ( 1 + r * Math.cos( q * t ) ) * Math.sin( p * t );
+				const z = r * Math.sin( q * t );
 
-		t *= Math.PI * 2;
+				return point.set( x, y, z ).multiplyScalar( radius );
 
-		var r = 0.5;
+			}
 
-		var x = ( 1 + r * Math.cos( q * t ) ) * Math.cos( p * t );
-		var y = ( 1 + r * Math.cos( q * t ) ) * Math.sin( p * t );
-		var z = r * Math.sin( q * t );
+		}
 
-		return point.set( x, y, z ).multiplyScalar( radius );
+		const segments = segmentsT;
+		const radiusSegments = segmentsR;
+		const extrudePath = new TorusKnotCurve();
 
-	};
+		super( extrudePath, segments, tube, radiusSegments, true, false );
 
-	var segments = segmentsT;
-	var radiusSegments = segmentsR;
-	var extrudePath = new TorusKnotCurve();
+		this.radius = radius;
+		this.tube = tube;
+		this.segmentsT = segmentsT;
+		this.segmentsR = segmentsR;
+		this.p = p;
+		this.q = q;
 
-	ParametricGeometries.TubeGeometry.call( this, extrudePath, segments, tube, radiusSegments, true, false );
+	}
 
 };
 
-ParametricGeometries.TorusKnotGeometry.prototype = Object.create( BufferGeometry.prototype );
-ParametricGeometries.TorusKnotGeometry.prototype.constructor = ParametricGeometries.TorusKnotGeometry;
-
-
 /*********************************************
   *
   * Parametric Replacement for SphereGeometry
   *
   *********************************************/
-ParametricGeometries.SphereGeometry = function ( size, u, v ) {
+ParametricGeometries.SphereGeometry = class SphereGeometry extends ParametricGeometry {
 
-	function sphere( u, v, target ) {
+	constructor( size, u, v ) {
 
-		u *= Math.PI;
-		v *= 2 * Math.PI;
+		function sphere( u, v, target ) {
 
-		var x = size * Math.sin( u ) * Math.cos( v );
-		var y = size * Math.sin( u ) * Math.sin( v );
-		var z = size * Math.cos( u );
+			u *= Math.PI;
+			v *= 2 * Math.PI;
 
-		target.set( x, y, z );
+			var x = size * Math.sin( u ) * Math.cos( v );
+			var y = size * Math.sin( u ) * Math.sin( v );
+			var z = size * Math.cos( u );
 
-	}
+			target.set( x, y, z );
 
-	ParametricGeometry.call( this, sphere, u, v );
+		}
 
-};
+		super( sphere, u, v );
 
-ParametricGeometries.SphereGeometry.prototype = Object.create( BufferGeometry.prototype );
-ParametricGeometries.SphereGeometry.prototype.constructor = ParametricGeometries.SphereGeometry;
+	}
+
+};
 
 
 /*********************************************
@@ -239,23 +230,24 @@ ParametricGeometries.SphereGeometry.prototype.constructor = ParametricGeometries
   *
   *********************************************/
 
-ParametricGeometries.PlaneGeometry = function ( width, depth, segmentsWidth, segmentsDepth ) {
+ParametricGeometries.PlaneGeometry = class PlaneGeometry extends ParametricGeometry {
 
-	function plane( u, v, target ) {
+	constructor( width, depth, segmentsWidth, segmentsDepth ) {
 
-		var x = u * width;
-		var y = 0;
-		var z = v * depth;
+		function plane( u, v, target ) {
 
-		target.set( x, y, z );
+			const x = u * width;
+			const y = 0;
+			const z = v * depth;
 
-	}
+			target.set( x, y, z );
 
-	ParametricGeometry.call( this, plane, segmentsWidth, segmentsDepth );
+		}
 
-};
+		super( plane, segmentsWidth, segmentsDepth );
 
-ParametricGeometries.PlaneGeometry.prototype = Object.create( BufferGeometry.prototype );
-ParametricGeometries.PlaneGeometry.prototype.constructor = ParametricGeometries.PlaneGeometry;
+	}
+
+};
 
 export { ParametricGeometries };

+ 7 - 6
examples/jsm/geometries/RoundedBoxGeometry.js

@@ -3,7 +3,8 @@ import {
 	Vector3
 } from '../../../build/three.module.js';
 
-const tempNormal = new Vector3();
+const _tempNormal = new Vector3();
+
 function getUv( faceDirVector, normal, uvAxis, projectionAxis, radius, sideLength ) {
 
 	const totArcLength = 2 * Math.PI * radius / 4;
@@ -13,17 +14,17 @@ function getUv( faceDirVector, normal, uvAxis, projectionAxis, radius, sideLengt
 	const halfArc = Math.PI / 4;
 
 	// Get the vector projected onto the Y plane
-	tempNormal.copy( normal );
-	tempNormal[ projectionAxis ] = 0;
-	tempNormal.normalize();
+	_tempNormal.copy( normal );
+	_tempNormal[ projectionAxis ] = 0;
+	_tempNormal.normalize();
 
 	// total amount of UV space alloted to a single arc
 	const arcUvRatio = 0.5 * totArcLength / ( totArcLength + centerLength );
 
 	// the distance along one arc the point is at
-	const arcAngleRatio = 1.0 - ( tempNormal.angleTo( faceDirVector ) / halfArc );
+	const arcAngleRatio = 1.0 - ( _tempNormal.angleTo( faceDirVector ) / halfArc );
 
-	if ( Math.sign( tempNormal[ uvAxis ] ) === 1 ) {
+	if ( Math.sign( _tempNormal[ uvAxis ] ) === 1 ) {
 
 		return arcAngleRatio * arcUvRatio;
 

+ 566 - 585
examples/jsm/geometries/TeapotGeometry.js

@@ -55,670 +55,651 @@ import {
  *
  */
 
-var TeapotGeometry = function ( size, segments, bottom, lid, body, fitLid, blinn ) {
-
-	// 32 * 4 * 4 Bezier spline patches
-	var teapotPatches = [
-		/*rim*/
-		0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
-		3, 16, 17, 18, 7, 19, 20, 21, 11, 22, 23, 24, 15, 25, 26, 27,
-		18, 28, 29, 30, 21, 31, 32, 33, 24, 34, 35, 36, 27, 37, 38, 39,
-		30, 40, 41, 0, 33, 42, 43, 4, 36, 44, 45, 8, 39, 46, 47, 12,
-		/*body*/
-		12, 13, 14, 15, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
-		15, 25, 26, 27, 51, 60, 61, 62, 55, 63, 64, 65, 59, 66, 67, 68,
-		27, 37, 38, 39, 62, 69, 70, 71, 65, 72, 73, 74, 68, 75, 76, 77,
-		39, 46, 47, 12, 71, 78, 79, 48, 74, 80, 81, 52, 77, 82, 83, 56,
-		56, 57, 58, 59, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
-		59, 66, 67, 68, 87, 96, 97, 98, 91, 99, 100, 101, 95, 102, 103, 104,
-		68, 75, 76, 77, 98, 105, 106, 107, 101, 108, 109, 110, 104, 111, 112, 113,
-		77, 82, 83, 56, 107, 114, 115, 84, 110, 116, 117, 88, 113, 118, 119, 92,
-		/*handle*/
-		120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
-		123, 136, 137, 120, 127, 138, 139, 124, 131, 140, 141, 128, 135, 142, 143, 132,
-		132, 133, 134, 135, 144, 145, 146, 147, 148, 149, 150, 151, 68, 152, 153, 154,
-		135, 142, 143, 132, 147, 155, 156, 144, 151, 157, 158, 148, 154, 159, 160, 68,
-		/*spout*/
-		161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
-		164, 177, 178, 161, 168, 179, 180, 165, 172, 181, 182, 169, 176, 183, 184, 173,
-		173, 174, 175, 176, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
-		176, 183, 184, 173, 188, 197, 198, 185, 192, 199, 200, 189, 196, 201, 202, 193,
-		/*lid*/
-		203, 203, 203, 203, 204, 205, 206, 207, 208, 208, 208, 208, 209, 210, 211, 212,
-		203, 203, 203, 203, 207, 213, 214, 215, 208, 208, 208, 208, 212, 216, 217, 218,
-		203, 203, 203, 203, 215, 219, 220, 221, 208, 208, 208, 208, 218, 222, 223, 224,
-		203, 203, 203, 203, 221, 225, 226, 204, 208, 208, 208, 208, 224, 227, 228, 209,
-		209, 210, 211, 212, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
-		212, 216, 217, 218, 232, 241, 242, 243, 236, 244, 245, 246, 240, 247, 248, 249,
-		218, 222, 223, 224, 243, 250, 251, 252, 246, 253, 254, 255, 249, 256, 257, 258,
-		224, 227, 228, 209, 252, 259, 260, 229, 255, 261, 262, 233, 258, 263, 264, 237,
-		/*bottom*/
-		265, 265, 265, 265, 266, 267, 268, 269, 270, 271, 272, 273, 92, 119, 118, 113,
-		265, 265, 265, 265, 269, 274, 275, 276, 273, 277, 278, 279, 113, 112, 111, 104,
-		265, 265, 265, 265, 276, 280, 281, 282, 279, 283, 284, 285, 104, 103, 102, 95,
-		265, 265, 265, 265, 282, 286, 287, 266, 285, 288, 289, 270, 95, 94, 93, 92
-	];
-
-	var teapotVertices = [
-		1.4, 0, 2.4,
-		1.4, - 0.784, 2.4,
-		0.784, - 1.4, 2.4,
-		0, - 1.4, 2.4,
-		1.3375, 0, 2.53125,
-		1.3375, - 0.749, 2.53125,
-		0.749, - 1.3375, 2.53125,
-		0, - 1.3375, 2.53125,
-		1.4375, 0, 2.53125,
-		1.4375, - 0.805, 2.53125,
-		0.805, - 1.4375, 2.53125,
-		0, - 1.4375, 2.53125,
-		1.5, 0, 2.4,
-		1.5, - 0.84, 2.4,
-		0.84, - 1.5, 2.4,
-		0, - 1.5, 2.4,
-		- 0.784, - 1.4, 2.4,
-		- 1.4, - 0.784, 2.4,
-		- 1.4, 0, 2.4,
-		- 0.749, - 1.3375, 2.53125,
-		- 1.3375, - 0.749, 2.53125,
-		- 1.3375, 0, 2.53125,
-		- 0.805, - 1.4375, 2.53125,
-		- 1.4375, - 0.805, 2.53125,
-		- 1.4375, 0, 2.53125,
-		- 0.84, - 1.5, 2.4,
-		- 1.5, - 0.84, 2.4,
-		- 1.5, 0, 2.4,
-		- 1.4, 0.784, 2.4,
-		- 0.784, 1.4, 2.4,
-		0, 1.4, 2.4,
-		- 1.3375, 0.749, 2.53125,
-		- 0.749, 1.3375, 2.53125,
-		0, 1.3375, 2.53125,
-		- 1.4375, 0.805, 2.53125,
-		- 0.805, 1.4375, 2.53125,
-		0, 1.4375, 2.53125,
-		- 1.5, 0.84, 2.4,
-		- 0.84, 1.5, 2.4,
-		0, 1.5, 2.4,
-		0.784, 1.4, 2.4,
-		1.4, 0.784, 2.4,
-		0.749, 1.3375, 2.53125,
-		1.3375, 0.749, 2.53125,
-		0.805, 1.4375, 2.53125,
-		1.4375, 0.805, 2.53125,
-		0.84, 1.5, 2.4,
-		1.5, 0.84, 2.4,
-		1.75, 0, 1.875,
-		1.75, - 0.98, 1.875,
-		0.98, - 1.75, 1.875,
-		0, - 1.75, 1.875,
-		2, 0, 1.35,
-		2, - 1.12, 1.35,
-		1.12, - 2, 1.35,
-		0, - 2, 1.35,
-		2, 0, 0.9,
-		2, - 1.12, 0.9,
-		1.12, - 2, 0.9,
-		0, - 2, 0.9,
-		- 0.98, - 1.75, 1.875,
-		- 1.75, - 0.98, 1.875,
-		- 1.75, 0, 1.875,
-		- 1.12, - 2, 1.35,
-		- 2, - 1.12, 1.35,
-		- 2, 0, 1.35,
-		- 1.12, - 2, 0.9,
-		- 2, - 1.12, 0.9,
-		- 2, 0, 0.9,
-		- 1.75, 0.98, 1.875,
-		- 0.98, 1.75, 1.875,
-		0, 1.75, 1.875,
-		- 2, 1.12, 1.35,
-		- 1.12, 2, 1.35,
-		0, 2, 1.35,
-		- 2, 1.12, 0.9,
-		- 1.12, 2, 0.9,
-		0, 2, 0.9,
-		0.98, 1.75, 1.875,
-		1.75, 0.98, 1.875,
-		1.12, 2, 1.35,
-		2, 1.12, 1.35,
-		1.12, 2, 0.9,
-		2, 1.12, 0.9,
-		2, 0, 0.45,
-		2, - 1.12, 0.45,
-		1.12, - 2, 0.45,
-		0, - 2, 0.45,
-		1.5, 0, 0.225,
-		1.5, - 0.84, 0.225,
-		0.84, - 1.5, 0.225,
-		0, - 1.5, 0.225,
-		1.5, 0, 0.15,
-		1.5, - 0.84, 0.15,
-		0.84, - 1.5, 0.15,
-		0, - 1.5, 0.15,
-		- 1.12, - 2, 0.45,
-		- 2, - 1.12, 0.45,
-		- 2, 0, 0.45,
-		- 0.84, - 1.5, 0.225,
-		- 1.5, - 0.84, 0.225,
-		- 1.5, 0, 0.225,
-		- 0.84, - 1.5, 0.15,
-		- 1.5, - 0.84, 0.15,
-		- 1.5, 0, 0.15,
-		- 2, 1.12, 0.45,
-		- 1.12, 2, 0.45,
-		0, 2, 0.45,
-		- 1.5, 0.84, 0.225,
-		- 0.84, 1.5, 0.225,
-		0, 1.5, 0.225,
-		- 1.5, 0.84, 0.15,
-		- 0.84, 1.5, 0.15,
-		0, 1.5, 0.15,
-		1.12, 2, 0.45,
-		2, 1.12, 0.45,
-		0.84, 1.5, 0.225,
-		1.5, 0.84, 0.225,
-		0.84, 1.5, 0.15,
-		1.5, 0.84, 0.15,
-		- 1.6, 0, 2.025,
-		- 1.6, - 0.3, 2.025,
-		- 1.5, - 0.3, 2.25,
-		- 1.5, 0, 2.25,
-		- 2.3, 0, 2.025,
-		- 2.3, - 0.3, 2.025,
-		- 2.5, - 0.3, 2.25,
-		- 2.5, 0, 2.25,
-		- 2.7, 0, 2.025,
-		- 2.7, - 0.3, 2.025,
-		- 3, - 0.3, 2.25,
-		- 3, 0, 2.25,
-		- 2.7, 0, 1.8,
-		- 2.7, - 0.3, 1.8,
-		- 3, - 0.3, 1.8,
-		- 3, 0, 1.8,
-		- 1.5, 0.3, 2.25,
-		- 1.6, 0.3, 2.025,
-		- 2.5, 0.3, 2.25,
-		- 2.3, 0.3, 2.025,
-		- 3, 0.3, 2.25,
-		- 2.7, 0.3, 2.025,
-		- 3, 0.3, 1.8,
-		- 2.7, 0.3, 1.8,
-		- 2.7, 0, 1.575,
-		- 2.7, - 0.3, 1.575,
-		- 3, - 0.3, 1.35,
-		- 3, 0, 1.35,
-		- 2.5, 0, 1.125,
-		- 2.5, - 0.3, 1.125,
-		- 2.65, - 0.3, 0.9375,
-		- 2.65, 0, 0.9375,
-		- 2, - 0.3, 0.9,
-		- 1.9, - 0.3, 0.6,
-		- 1.9, 0, 0.6,
-		- 3, 0.3, 1.35,
-		- 2.7, 0.3, 1.575,
-		- 2.65, 0.3, 0.9375,
-		- 2.5, 0.3, 1.125,
-		- 1.9, 0.3, 0.6,
-		- 2, 0.3, 0.9,
-		1.7, 0, 1.425,
-		1.7, - 0.66, 1.425,
-		1.7, - 0.66, 0.6,
-		1.7, 0, 0.6,
-		2.6, 0, 1.425,
-		2.6, - 0.66, 1.425,
-		3.1, - 0.66, 0.825,
-		3.1, 0, 0.825,
-		2.3, 0, 2.1,
-		2.3, - 0.25, 2.1,
-		2.4, - 0.25, 2.025,
-		2.4, 0, 2.025,
-		2.7, 0, 2.4,
-		2.7, - 0.25, 2.4,
-		3.3, - 0.25, 2.4,
-		3.3, 0, 2.4,
-		1.7, 0.66, 0.6,
-		1.7, 0.66, 1.425,
-		3.1, 0.66, 0.825,
-		2.6, 0.66, 1.425,
-		2.4, 0.25, 2.025,
-		2.3, 0.25, 2.1,
-		3.3, 0.25, 2.4,
-		2.7, 0.25, 2.4,
-		2.8, 0, 2.475,
-		2.8, - 0.25, 2.475,
-		3.525, - 0.25, 2.49375,
-		3.525, 0, 2.49375,
-		2.9, 0, 2.475,
-		2.9, - 0.15, 2.475,
-		3.45, - 0.15, 2.5125,
-		3.45, 0, 2.5125,
-		2.8, 0, 2.4,
-		2.8, - 0.15, 2.4,
-		3.2, - 0.15, 2.4,
-		3.2, 0, 2.4,
-		3.525, 0.25, 2.49375,
-		2.8, 0.25, 2.475,
-		3.45, 0.15, 2.5125,
-		2.9, 0.15, 2.475,
-		3.2, 0.15, 2.4,
-		2.8, 0.15, 2.4,
-		0, 0, 3.15,
-		0.8, 0, 3.15,
-		0.8, - 0.45, 3.15,
-		0.45, - 0.8, 3.15,
-		0, - 0.8, 3.15,
-		0, 0, 2.85,
-		0.2, 0, 2.7,
-		0.2, - 0.112, 2.7,
-		0.112, - 0.2, 2.7,
-		0, - 0.2, 2.7,
-		- 0.45, - 0.8, 3.15,
-		- 0.8, - 0.45, 3.15,
-		- 0.8, 0, 3.15,
-		- 0.112, - 0.2, 2.7,
-		- 0.2, - 0.112, 2.7,
-		- 0.2, 0, 2.7,
-		- 0.8, 0.45, 3.15,
-		- 0.45, 0.8, 3.15,
-		0, 0.8, 3.15,
-		- 0.2, 0.112, 2.7,
-		- 0.112, 0.2, 2.7,
-		0, 0.2, 2.7,
-		0.45, 0.8, 3.15,
-		0.8, 0.45, 3.15,
-		0.112, 0.2, 2.7,
-		0.2, 0.112, 2.7,
-		0.4, 0, 2.55,
-		0.4, - 0.224, 2.55,
-		0.224, - 0.4, 2.55,
-		0, - 0.4, 2.55,
-		1.3, 0, 2.55,
-		1.3, - 0.728, 2.55,
-		0.728, - 1.3, 2.55,
-		0, - 1.3, 2.55,
-		1.3, 0, 2.4,
-		1.3, - 0.728, 2.4,
-		0.728, - 1.3, 2.4,
-		0, - 1.3, 2.4,
-		- 0.224, - 0.4, 2.55,
-		- 0.4, - 0.224, 2.55,
-		- 0.4, 0, 2.55,
-		- 0.728, - 1.3, 2.55,
-		- 1.3, - 0.728, 2.55,
-		- 1.3, 0, 2.55,
-		- 0.728, - 1.3, 2.4,
-		- 1.3, - 0.728, 2.4,
-		- 1.3, 0, 2.4,
-		- 0.4, 0.224, 2.55,
-		- 0.224, 0.4, 2.55,
-		0, 0.4, 2.55,
-		- 1.3, 0.728, 2.55,
-		- 0.728, 1.3, 2.55,
-		0, 1.3, 2.55,
-		- 1.3, 0.728, 2.4,
-		- 0.728, 1.3, 2.4,
-		0, 1.3, 2.4,
-		0.224, 0.4, 2.55,
-		0.4, 0.224, 2.55,
-		0.728, 1.3, 2.55,
-		1.3, 0.728, 2.55,
-		0.728, 1.3, 2.4,
-		1.3, 0.728, 2.4,
-		0, 0, 0,
-		1.425, 0, 0,
-		1.425, 0.798, 0,
-		0.798, 1.425, 0,
-		0, 1.425, 0,
-		1.5, 0, 0.075,
-		1.5, 0.84, 0.075,
-		0.84, 1.5, 0.075,
-		0, 1.5, 0.075,
-		- 0.798, 1.425, 0,
-		- 1.425, 0.798, 0,
-		- 1.425, 0, 0,
-		- 0.84, 1.5, 0.075,
-		- 1.5, 0.84, 0.075,
-		- 1.5, 0, 0.075,
-		- 1.425, - 0.798, 0,
-		- 0.798, - 1.425, 0,
-		0, - 1.425, 0,
-		- 1.5, - 0.84, 0.075,
-		- 0.84, - 1.5, 0.075,
-		0, - 1.5, 0.075,
-		0.798, - 1.425, 0,
-		1.425, - 0.798, 0,
-		0.84, - 1.5, 0.075,
-		1.5, - 0.84, 0.075
-	];
-
-	BufferGeometry.call( this );
-
-	size = size || 50;
-
-	// number of segments per patch
-	segments = segments !== undefined ? Math.max( 2, Math.floor( segments ) || 10 ) : 10;
-
-	// which parts should be visible
-	bottom = bottom === undefined ? true : bottom;
-	lid = lid === undefined ? true : lid;
-	body = body === undefined ? true : body;
-
-	// Should the lid be snug? It's not traditional, but we make it snug by default
-	fitLid = fitLid === undefined ? true : fitLid;
-
-	// Jim Blinn scaled the teapot down in size by about 1.3 for
-	// some rendering tests. He liked the new proportions that he kept
-	// the data in this form. The model was distributed with these new
-	// proportions and became the norm. Trivia: comparing images of the
-	// real teapot and the computer model, the ratio for the bowl of the
-	// real teapot is more like 1.25, but since 1.3 is the traditional
-	// value given, we use it here.
-	var blinnScale = 1.3;
-	blinn = blinn === undefined ? true : blinn;
-
-	// scale the size to be the real scaling factor
-	var maxHeight = 3.15 * ( blinn ? 1 : blinnScale );
-
-	var maxHeight2 = maxHeight / 2;
-	var trueSize = size / maxHeight2;
-
-	// Number of elements depends on what is needed. Subtract degenerate
-	// triangles at tip of bottom and lid out in advance.
-	var numTriangles = bottom ? ( 8 * segments - 4 ) * segments : 0;
-	numTriangles += lid ? ( 16 * segments - 4 ) * segments : 0;
-	numTriangles += body ? 40 * segments * segments : 0;
-
-	var indices = new Uint32Array( numTriangles * 3 );
-
-	var numVertices = bottom ? 4 : 0;
-	numVertices += lid ? 8 : 0;
-	numVertices += body ? 20 : 0;
-	numVertices *= ( segments + 1 ) * ( segments + 1 );
-
-	var vertices = new Float32Array( numVertices * 3 );
-	var normals = new Float32Array( numVertices * 3 );
-	var uvs = new Float32Array( numVertices * 2 );
-
-	// Bezier form
-	var ms = new Matrix4();
-	ms.set(
-		- 1.0, 3.0, - 3.0, 1.0,
-		3.0, - 6.0, 3.0, 0.0,
-		- 3.0, 3.0, 0.0, 0.0,
-		1.0, 0.0, 0.0, 0.0 );
-
-	var g = [];
-	var i, r, c;
-
-	var sp = [];
-	var tp = [];
-	var dsp = [];
-	var dtp = [];
-
-	// M * G * M matrix, sort of see
-	// http://www.cs.helsinki.fi/group/goa/mallinnus/curves/surfaces.html
-	var mgm = [];
-
-	var vert = [];
-	var sdir = [];
-	var tdir = [];
-
-	var norm = new Vector3();
-
-	var tcoord;
-
-	var sstep, tstep;
-	var vertPerRow;
-
-	var s, t, sval, tval, p;
-	var dsval = 0;
-	var dtval = 0;
-
-	var normOut = new Vector3();
-	var v1, v2, v3, v4;
-
-	var gmx = new Matrix4();
-	var tmtx = new Matrix4();
+class TeapotGeometry extends BufferGeometry {
+
+	constructor( size = 50, segments = 10, bottom = true, lid = true, body = true, fitLid = true, blinn = true ) {
+
+		// 32 * 4 * 4 Bezier spline patches
+		const teapotPatches = [
+			/*rim*/
+			0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+			3, 16, 17, 18, 7, 19, 20, 21, 11, 22, 23, 24, 15, 25, 26, 27,
+			18, 28, 29, 30, 21, 31, 32, 33, 24, 34, 35, 36, 27, 37, 38, 39,
+			30, 40, 41, 0, 33, 42, 43, 4, 36, 44, 45, 8, 39, 46, 47, 12,
+			/*body*/
+			12, 13, 14, 15, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,
+			15, 25, 26, 27, 51, 60, 61, 62, 55, 63, 64, 65, 59, 66, 67, 68,
+			27, 37, 38, 39, 62, 69, 70, 71, 65, 72, 73, 74, 68, 75, 76, 77,
+			39, 46, 47, 12, 71, 78, 79, 48, 74, 80, 81, 52, 77, 82, 83, 56,
+			56, 57, 58, 59, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+			59, 66, 67, 68, 87, 96, 97, 98, 91, 99, 100, 101, 95, 102, 103, 104,
+			68, 75, 76, 77, 98, 105, 106, 107, 101, 108, 109, 110, 104, 111, 112, 113,
+			77, 82, 83, 56, 107, 114, 115, 84, 110, 116, 117, 88, 113, 118, 119, 92,
+			/*handle*/
+			120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135,
+			123, 136, 137, 120, 127, 138, 139, 124, 131, 140, 141, 128, 135, 142, 143, 132,
+			132, 133, 134, 135, 144, 145, 146, 147, 148, 149, 150, 151, 68, 152, 153, 154,
+			135, 142, 143, 132, 147, 155, 156, 144, 151, 157, 158, 148, 154, 159, 160, 68,
+			/*spout*/
+			161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176,
+			164, 177, 178, 161, 168, 179, 180, 165, 172, 181, 182, 169, 176, 183, 184, 173,
+			173, 174, 175, 176, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196,
+			176, 183, 184, 173, 188, 197, 198, 185, 192, 199, 200, 189, 196, 201, 202, 193,
+			/*lid*/
+			203, 203, 203, 203, 204, 205, 206, 207, 208, 208, 208, 208, 209, 210, 211, 212,
+			203, 203, 203, 203, 207, 213, 214, 215, 208, 208, 208, 208, 212, 216, 217, 218,
+			203, 203, 203, 203, 215, 219, 220, 221, 208, 208, 208, 208, 218, 222, 223, 224,
+			203, 203, 203, 203, 221, 225, 226, 204, 208, 208, 208, 208, 224, 227, 228, 209,
+			209, 210, 211, 212, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239, 240,
+			212, 216, 217, 218, 232, 241, 242, 243, 236, 244, 245, 246, 240, 247, 248, 249,
+			218, 222, 223, 224, 243, 250, 251, 252, 246, 253, 254, 255, 249, 256, 257, 258,
+			224, 227, 228, 209, 252, 259, 260, 229, 255, 261, 262, 233, 258, 263, 264, 237,
+			/*bottom*/
+			265, 265, 265, 265, 266, 267, 268, 269, 270, 271, 272, 273, 92, 119, 118, 113,
+			265, 265, 265, 265, 269, 274, 275, 276, 273, 277, 278, 279, 113, 112, 111, 104,
+			265, 265, 265, 265, 276, 280, 281, 282, 279, 283, 284, 285, 104, 103, 102, 95,
+			265, 265, 265, 265, 282, 286, 287, 266, 285, 288, 289, 270, 95, 94, 93, 92
+		];
+
+		const teapotVertices = [
+			1.4, 0, 2.4,
+			1.4, - 0.784, 2.4,
+			0.784, - 1.4, 2.4,
+			0, - 1.4, 2.4,
+			1.3375, 0, 2.53125,
+			1.3375, - 0.749, 2.53125,
+			0.749, - 1.3375, 2.53125,
+			0, - 1.3375, 2.53125,
+			1.4375, 0, 2.53125,
+			1.4375, - 0.805, 2.53125,
+			0.805, - 1.4375, 2.53125,
+			0, - 1.4375, 2.53125,
+			1.5, 0, 2.4,
+			1.5, - 0.84, 2.4,
+			0.84, - 1.5, 2.4,
+			0, - 1.5, 2.4,
+			- 0.784, - 1.4, 2.4,
+			- 1.4, - 0.784, 2.4,
+			- 1.4, 0, 2.4,
+			- 0.749, - 1.3375, 2.53125,
+			- 1.3375, - 0.749, 2.53125,
+			- 1.3375, 0, 2.53125,
+			- 0.805, - 1.4375, 2.53125,
+			- 1.4375, - 0.805, 2.53125,
+			- 1.4375, 0, 2.53125,
+			- 0.84, - 1.5, 2.4,
+			- 1.5, - 0.84, 2.4,
+			- 1.5, 0, 2.4,
+			- 1.4, 0.784, 2.4,
+			- 0.784, 1.4, 2.4,
+			0, 1.4, 2.4,
+			- 1.3375, 0.749, 2.53125,
+			- 0.749, 1.3375, 2.53125,
+			0, 1.3375, 2.53125,
+			- 1.4375, 0.805, 2.53125,
+			- 0.805, 1.4375, 2.53125,
+			0, 1.4375, 2.53125,
+			- 1.5, 0.84, 2.4,
+			- 0.84, 1.5, 2.4,
+			0, 1.5, 2.4,
+			0.784, 1.4, 2.4,
+			1.4, 0.784, 2.4,
+			0.749, 1.3375, 2.53125,
+			1.3375, 0.749, 2.53125,
+			0.805, 1.4375, 2.53125,
+			1.4375, 0.805, 2.53125,
+			0.84, 1.5, 2.4,
+			1.5, 0.84, 2.4,
+			1.75, 0, 1.875,
+			1.75, - 0.98, 1.875,
+			0.98, - 1.75, 1.875,
+			0, - 1.75, 1.875,
+			2, 0, 1.35,
+			2, - 1.12, 1.35,
+			1.12, - 2, 1.35,
+			0, - 2, 1.35,
+			2, 0, 0.9,
+			2, - 1.12, 0.9,
+			1.12, - 2, 0.9,
+			0, - 2, 0.9,
+			- 0.98, - 1.75, 1.875,
+			- 1.75, - 0.98, 1.875,
+			- 1.75, 0, 1.875,
+			- 1.12, - 2, 1.35,
+			- 2, - 1.12, 1.35,
+			- 2, 0, 1.35,
+			- 1.12, - 2, 0.9,
+			- 2, - 1.12, 0.9,
+			- 2, 0, 0.9,
+			- 1.75, 0.98, 1.875,
+			- 0.98, 1.75, 1.875,
+			0, 1.75, 1.875,
+			- 2, 1.12, 1.35,
+			- 1.12, 2, 1.35,
+			0, 2, 1.35,
+			- 2, 1.12, 0.9,
+			- 1.12, 2, 0.9,
+			0, 2, 0.9,
+			0.98, 1.75, 1.875,
+			1.75, 0.98, 1.875,
+			1.12, 2, 1.35,
+			2, 1.12, 1.35,
+			1.12, 2, 0.9,
+			2, 1.12, 0.9,
+			2, 0, 0.45,
+			2, - 1.12, 0.45,
+			1.12, - 2, 0.45,
+			0, - 2, 0.45,
+			1.5, 0, 0.225,
+			1.5, - 0.84, 0.225,
+			0.84, - 1.5, 0.225,
+			0, - 1.5, 0.225,
+			1.5, 0, 0.15,
+			1.5, - 0.84, 0.15,
+			0.84, - 1.5, 0.15,
+			0, - 1.5, 0.15,
+			- 1.12, - 2, 0.45,
+			- 2, - 1.12, 0.45,
+			- 2, 0, 0.45,
+			- 0.84, - 1.5, 0.225,
+			- 1.5, - 0.84, 0.225,
+			- 1.5, 0, 0.225,
+			- 0.84, - 1.5, 0.15,
+			- 1.5, - 0.84, 0.15,
+			- 1.5, 0, 0.15,
+			- 2, 1.12, 0.45,
+			- 1.12, 2, 0.45,
+			0, 2, 0.45,
+			- 1.5, 0.84, 0.225,
+			- 0.84, 1.5, 0.225,
+			0, 1.5, 0.225,
+			- 1.5, 0.84, 0.15,
+			- 0.84, 1.5, 0.15,
+			0, 1.5, 0.15,
+			1.12, 2, 0.45,
+			2, 1.12, 0.45,
+			0.84, 1.5, 0.225,
+			1.5, 0.84, 0.225,
+			0.84, 1.5, 0.15,
+			1.5, 0.84, 0.15,
+			- 1.6, 0, 2.025,
+			- 1.6, - 0.3, 2.025,
+			- 1.5, - 0.3, 2.25,
+			- 1.5, 0, 2.25,
+			- 2.3, 0, 2.025,
+			- 2.3, - 0.3, 2.025,
+			- 2.5, - 0.3, 2.25,
+			- 2.5, 0, 2.25,
+			- 2.7, 0, 2.025,
+			- 2.7, - 0.3, 2.025,
+			- 3, - 0.3, 2.25,
+			- 3, 0, 2.25,
+			- 2.7, 0, 1.8,
+			- 2.7, - 0.3, 1.8,
+			- 3, - 0.3, 1.8,
+			- 3, 0, 1.8,
+			- 1.5, 0.3, 2.25,
+			- 1.6, 0.3, 2.025,
+			- 2.5, 0.3, 2.25,
+			- 2.3, 0.3, 2.025,
+			- 3, 0.3, 2.25,
+			- 2.7, 0.3, 2.025,
+			- 3, 0.3, 1.8,
+			- 2.7, 0.3, 1.8,
+			- 2.7, 0, 1.575,
+			- 2.7, - 0.3, 1.575,
+			- 3, - 0.3, 1.35,
+			- 3, 0, 1.35,
+			- 2.5, 0, 1.125,
+			- 2.5, - 0.3, 1.125,
+			- 2.65, - 0.3, 0.9375,
+			- 2.65, 0, 0.9375,
+			- 2, - 0.3, 0.9,
+			- 1.9, - 0.3, 0.6,
+			- 1.9, 0, 0.6,
+			- 3, 0.3, 1.35,
+			- 2.7, 0.3, 1.575,
+			- 2.65, 0.3, 0.9375,
+			- 2.5, 0.3, 1.125,
+			- 1.9, 0.3, 0.6,
+			- 2, 0.3, 0.9,
+			1.7, 0, 1.425,
+			1.7, - 0.66, 1.425,
+			1.7, - 0.66, 0.6,
+			1.7, 0, 0.6,
+			2.6, 0, 1.425,
+			2.6, - 0.66, 1.425,
+			3.1, - 0.66, 0.825,
+			3.1, 0, 0.825,
+			2.3, 0, 2.1,
+			2.3, - 0.25, 2.1,
+			2.4, - 0.25, 2.025,
+			2.4, 0, 2.025,
+			2.7, 0, 2.4,
+			2.7, - 0.25, 2.4,
+			3.3, - 0.25, 2.4,
+			3.3, 0, 2.4,
+			1.7, 0.66, 0.6,
+			1.7, 0.66, 1.425,
+			3.1, 0.66, 0.825,
+			2.6, 0.66, 1.425,
+			2.4, 0.25, 2.025,
+			2.3, 0.25, 2.1,
+			3.3, 0.25, 2.4,
+			2.7, 0.25, 2.4,
+			2.8, 0, 2.475,
+			2.8, - 0.25, 2.475,
+			3.525, - 0.25, 2.49375,
+			3.525, 0, 2.49375,
+			2.9, 0, 2.475,
+			2.9, - 0.15, 2.475,
+			3.45, - 0.15, 2.5125,
+			3.45, 0, 2.5125,
+			2.8, 0, 2.4,
+			2.8, - 0.15, 2.4,
+			3.2, - 0.15, 2.4,
+			3.2, 0, 2.4,
+			3.525, 0.25, 2.49375,
+			2.8, 0.25, 2.475,
+			3.45, 0.15, 2.5125,
+			2.9, 0.15, 2.475,
+			3.2, 0.15, 2.4,
+			2.8, 0.15, 2.4,
+			0, 0, 3.15,
+			0.8, 0, 3.15,
+			0.8, - 0.45, 3.15,
+			0.45, - 0.8, 3.15,
+			0, - 0.8, 3.15,
+			0, 0, 2.85,
+			0.2, 0, 2.7,
+			0.2, - 0.112, 2.7,
+			0.112, - 0.2, 2.7,
+			0, - 0.2, 2.7,
+			- 0.45, - 0.8, 3.15,
+			- 0.8, - 0.45, 3.15,
+			- 0.8, 0, 3.15,
+			- 0.112, - 0.2, 2.7,
+			- 0.2, - 0.112, 2.7,
+			- 0.2, 0, 2.7,
+			- 0.8, 0.45, 3.15,
+			- 0.45, 0.8, 3.15,
+			0, 0.8, 3.15,
+			- 0.2, 0.112, 2.7,
+			- 0.112, 0.2, 2.7,
+			0, 0.2, 2.7,
+			0.45, 0.8, 3.15,
+			0.8, 0.45, 3.15,
+			0.112, 0.2, 2.7,
+			0.2, 0.112, 2.7,
+			0.4, 0, 2.55,
+			0.4, - 0.224, 2.55,
+			0.224, - 0.4, 2.55,
+			0, - 0.4, 2.55,
+			1.3, 0, 2.55,
+			1.3, - 0.728, 2.55,
+			0.728, - 1.3, 2.55,
+			0, - 1.3, 2.55,
+			1.3, 0, 2.4,
+			1.3, - 0.728, 2.4,
+			0.728, - 1.3, 2.4,
+			0, - 1.3, 2.4,
+			- 0.224, - 0.4, 2.55,
+			- 0.4, - 0.224, 2.55,
+			- 0.4, 0, 2.55,
+			- 0.728, - 1.3, 2.55,
+			- 1.3, - 0.728, 2.55,
+			- 1.3, 0, 2.55,
+			- 0.728, - 1.3, 2.4,
+			- 1.3, - 0.728, 2.4,
+			- 1.3, 0, 2.4,
+			- 0.4, 0.224, 2.55,
+			- 0.224, 0.4, 2.55,
+			0, 0.4, 2.55,
+			- 1.3, 0.728, 2.55,
+			- 0.728, 1.3, 2.55,
+			0, 1.3, 2.55,
+			- 1.3, 0.728, 2.4,
+			- 0.728, 1.3, 2.4,
+			0, 1.3, 2.4,
+			0.224, 0.4, 2.55,
+			0.4, 0.224, 2.55,
+			0.728, 1.3, 2.55,
+			1.3, 0.728, 2.55,
+			0.728, 1.3, 2.4,
+			1.3, 0.728, 2.4,
+			0, 0, 0,
+			1.425, 0, 0,
+			1.425, 0.798, 0,
+			0.798, 1.425, 0,
+			0, 1.425, 0,
+			1.5, 0, 0.075,
+			1.5, 0.84, 0.075,
+			0.84, 1.5, 0.075,
+			0, 1.5, 0.075,
+			- 0.798, 1.425, 0,
+			- 1.425, 0.798, 0,
+			- 1.425, 0, 0,
+			- 0.84, 1.5, 0.075,
+			- 1.5, 0.84, 0.075,
+			- 1.5, 0, 0.075,
+			- 1.425, - 0.798, 0,
+			- 0.798, - 1.425, 0,
+			0, - 1.425, 0,
+			- 1.5, - 0.84, 0.075,
+			- 0.84, - 1.5, 0.075,
+			0, - 1.5, 0.075,
+			0.798, - 1.425, 0,
+			1.425, - 0.798, 0,
+			0.84, - 1.5, 0.075,
+			1.5, - 0.84, 0.075
+		];
+
+		super();
+
+		// number of segments per patch
+		segments = Math.max( 2, Math.floor( segments ) );
+
+		// Jim Blinn scaled the teapot down in size by about 1.3 for
+		// some rendering tests. He liked the new proportions that he kept
+		// the data in this form. The model was distributed with these new
+		// proportions and became the norm. Trivia: comparing images of the
+		// real teapot and the computer model, the ratio for the bowl of the
+		// real teapot is more like 1.25, but since 1.3 is the traditional
+		// value given, we use it here.
+		const blinnScale = 1.3;
+
+		// scale the size to be the real scaling factor
+		const maxHeight = 3.15 * ( blinn ? 1 : blinnScale );
+
+		const maxHeight2 = maxHeight / 2;
+		const trueSize = size / maxHeight2;
+
+		// Number of elements depends on what is needed. Subtract degenerate
+		// triangles at tip of bottom and lid out in advance.
+		let numTriangles = bottom ? ( 8 * segments - 4 ) * segments : 0;
+		numTriangles += lid ? ( 16 * segments - 4 ) * segments : 0;
+		numTriangles += body ? 40 * segments * segments : 0;
+
+		const indices = new Uint32Array( numTriangles * 3 );
+
+		let numVertices = bottom ? 4 : 0;
+		numVertices += lid ? 8 : 0;
+		numVertices += body ? 20 : 0;
+		numVertices *= ( segments + 1 ) * ( segments + 1 );
+
+		const vertices = new Float32Array( numVertices * 3 );
+		const normals = new Float32Array( numVertices * 3 );
+		const uvs = new Float32Array( numVertices * 2 );
+
+		// Bezier form
+		const ms = new Matrix4();
+		ms.set(
+			- 1.0, 3.0, - 3.0, 1.0,
+			3.0, - 6.0, 3.0, 0.0,
+			- 3.0, 3.0, 0.0, 0.0,
+			1.0, 0.0, 0.0, 0.0 );
+
+		const g = [];
+
+		const sp = [];
+		const tp = [];
+		const dsp = [];
+		const dtp = [];
+
+		// M * G * M matrix, sort of see
+		// http://www.cs.helsinki.fi/group/goa/mallinnus/curves/surfaces.html
+		const mgm = [];
+
+		const vert = [];
+		const sdir = [];
+		const tdir = [];
+
+		const norm = new Vector3();
+
+		let tcoord;
+
+		let sval;
+		let tval;
+		let p;
+		let dsval = 0;
+		let dtval = 0;
+
+		const normOut = new Vector3();
+
+		const gmx = new Matrix4();
+		const tmtx = new Matrix4();
+
+		const vsp = new Vector4();
+		const vtp = new Vector4();
+		const vdsp = new Vector4();
+		const vdtp = new Vector4();
+
+		const vsdir = new Vector3();
+		const vtdir = new Vector3();
+
+		const mst = ms.clone();
+		mst.transpose();
+
+		// internal function: test if triangle has any matching vertices;
+		// if so, don't save triangle, since it won't display anything.
+		const notDegenerate = ( vtx1, vtx2, vtx3 ) => // if any vertex matches, return false
+			! ( ( ( vertices[ vtx1 * 3 ] === vertices[ vtx2 * 3 ] ) &&
+					( vertices[ vtx1 * 3 + 1 ] === vertices[ vtx2 * 3 + 1 ] ) &&
+					( vertices[ vtx1 * 3 + 2 ] === vertices[ vtx2 * 3 + 2 ] ) ) ||
+					( ( vertices[ vtx1 * 3 ] === vertices[ vtx3 * 3 ] ) &&
+					( vertices[ vtx1 * 3 + 1 ] === vertices[ vtx3 * 3 + 1 ] ) &&
+					( vertices[ vtx1 * 3 + 2 ] === vertices[ vtx3 * 3 + 2 ] ) ) || ( vertices[ vtx2 * 3 ] === vertices[ vtx3 * 3 ] ) &&
+					( vertices[ vtx2 * 3 + 1 ] === vertices[ vtx3 * 3 + 1 ] ) &&
+					( vertices[ vtx2 * 3 + 2 ] === vertices[ vtx3 * 3 + 2 ] ) );
 
-	var vsp = new Vector4();
-	var vtp = new Vector4();
-	var vdsp = new Vector4();
-	var vdtp = new Vector4();
 
-	var vsdir = new Vector3();
-	var vtdir = new Vector3();
+		for ( let i = 0; i < 3; i ++ ) {
 
-	var mst = ms.clone();
-	mst.transpose();
+			mgm[ i ] = new Matrix4();
 
-	// internal function: test if triangle has any matching vertices;
-	// if so, don't save triangle, since it won't display anything.
-	var notDegenerate = function ( vtx1, vtx2, vtx3 ) {
-
-		// if any vertex matches, return false
-		return ! ( ( ( vertices[ vtx1 * 3 ] === vertices[ vtx2 * 3 ] ) &&
-					 ( vertices[ vtx1 * 3 + 1 ] === vertices[ vtx2 * 3 + 1 ] ) &&
-					 ( vertices[ vtx1 * 3 + 2 ] === vertices[ vtx2 * 3 + 2 ] ) ) ||
-				   ( ( vertices[ vtx1 * 3 ] === vertices[ vtx3 * 3 ] ) &&
-					 ( vertices[ vtx1 * 3 + 1 ] === vertices[ vtx3 * 3 + 1 ] ) &&
-					 ( vertices[ vtx1 * 3 + 2 ] === vertices[ vtx3 * 3 + 2 ] ) ) ||
-				   ( ( vertices[ vtx2 * 3 ] === vertices[ vtx3 * 3 ] ) &&
-					 ( vertices[ vtx2 * 3 + 1 ] === vertices[ vtx3 * 3 + 1 ] ) &&
-					 ( vertices[ vtx2 * 3 + 2 ] === vertices[ vtx3 * 3 + 2 ] ) ) );
-
-	};
-
-
-	for ( i = 0; i < 3; i ++ ) {
-
-		mgm[ i ] = new Matrix4();
+		}
 
-	}
+		const minPatches = body ? 0 : 20;
+		const maxPatches = bottom ? 32 : 28;
 
-	var minPatches = body ? 0 : 20;
-	var maxPatches = bottom ? 32 : 28;
+		const vertPerRow = segments + 1;
 
-	vertPerRow = segments + 1;
+		let surfCount = 0;
 
-	var surfCount = 0;
+		let vertCount = 0;
+		let normCount = 0;
+		let uvCount = 0;
 
-	var vertCount = 0;
-	var normCount = 0;
-	var uvCount = 0;
+		let indexCount = 0;
 
-	var indexCount = 0;
+		for ( let surf = minPatches; surf < maxPatches; surf ++ ) {
 
-	for ( var surf = minPatches; surf < maxPatches; surf ++ ) {
+			// lid is in the middle of the data, patches 20-27,
+			// so ignore it for this part of the loop if the lid is not desired
+			if ( lid || ( surf < 20 || surf >= 28 ) ) {
 
-		// lid is in the middle of the data, patches 20-27,
-		// so ignore it for this part of the loop if the lid is not desired
-		if ( lid || ( surf < 20 || surf >= 28 ) ) {
+				// get M * G * M matrix for x,y,z
+				for ( let i = 0; i < 3; i ++ ) {
 
-			// get M * G * M matrix for x,y,z
-			for ( i = 0; i < 3; i ++ ) {
+					// get control patches
+					for ( let r = 0; r < 4; r ++ ) {
 
-				// get control patches
-				for ( r = 0; r < 4; r ++ ) {
+						for ( let c = 0; c < 4; c ++ ) {
 
-					for ( c = 0; c < 4; c ++ ) {
+							// transposed
+							g[ c * 4 + r ] = teapotVertices[ teapotPatches[ surf * 16 + r * 4 + c ] * 3 + i ];
 
-						// transposed
-						g[ c * 4 + r ] = teapotVertices[ teapotPatches[ surf * 16 + r * 4 + c ] * 3 + i ];
+							// is the lid to be made larger, and is this a point on the lid
+							// that is X or Y?
+							if ( fitLid && ( surf >= 20 && surf < 28 ) && ( i !== 2 ) ) {
 
-						// is the lid to be made larger, and is this a point on the lid
-						// that is X or Y?
-						if ( fitLid && ( surf >= 20 && surf < 28 ) && ( i !== 2 ) ) {
+								// increase XY size by 7.7%, found empirically. I don't
+								// increase Z so that the teapot will continue to fit in the
+								// space -1 to 1 for Y (Y is up for the final model).
+								g[ c * 4 + r ] *= 1.077;
 
-							// increase XY size by 7.7%, found empirically. I don't
-							// increase Z so that the teapot will continue to fit in the
-							// space -1 to 1 for Y (Y is up for the final model).
-							g[ c * 4 + r ] *= 1.077;
+							}
 
-						}
+							// Blinn "fixed" the teapot by dividing Z by blinnScale, and that's the
+							// data we now use. The original teapot is taller. Fix it:
+							if ( ! blinn && ( i === 2 ) ) {
 
-						// Blinn "fixed" the teapot by dividing Z by blinnScale, and that's the
-						// data we now use. The original teapot is taller. Fix it:
-						if ( ! blinn && ( i === 2 ) ) {
+								g[ c * 4 + r ] *= blinnScale;
 
-							g[ c * 4 + r ] *= blinnScale;
+							}
 
 						}
 
 					}
 
-				}
+					gmx.set( g[ 0 ], g[ 1 ], g[ 2 ], g[ 3 ], g[ 4 ], g[ 5 ], g[ 6 ], g[ 7 ], g[ 8 ], g[ 9 ], g[ 10 ], g[ 11 ], g[ 12 ], g[ 13 ], g[ 14 ], g[ 15 ] );
 
-				gmx.set( g[ 0 ], g[ 1 ], g[ 2 ], g[ 3 ], g[ 4 ], g[ 5 ], g[ 6 ], g[ 7 ], g[ 8 ], g[ 9 ], g[ 10 ], g[ 11 ], g[ 12 ], g[ 13 ], g[ 14 ], g[ 15 ] );
+					tmtx.multiplyMatrices( gmx, ms );
+					mgm[ i ].multiplyMatrices( mst, tmtx );
 
-				tmtx.multiplyMatrices( gmx, ms );
-				mgm[ i ].multiplyMatrices( mst, tmtx );
+				}
 
-			}
+				// step along, get points, and output
+				for ( let sstep = 0; sstep <= segments; sstep ++ ) {
 
-			// step along, get points, and output
-			for ( sstep = 0; sstep <= segments; sstep ++ ) {
+					const s = sstep / segments;
 
-				s = sstep / segments;
+					for ( let tstep = 0; tstep <= segments; tstep ++ ) {
 
-				for ( tstep = 0; tstep <= segments; tstep ++ ) {
+						const t = tstep / segments;
 
-					t = tstep / segments;
+						// point from basis
+						// get power vectors and their derivatives
+						for ( p = 4, sval = tval = 1.0; p --; ) {
 
-					// point from basis
-					// get power vectors and their derivatives
-					for ( p = 4, sval = tval = 1.0; p --; ) {
+							sp[ p ] = sval;
+							tp[ p ] = tval;
+							sval *= s;
+							tval *= t;
 
-						sp[ p ] = sval;
-						tp[ p ] = tval;
-						sval *= s;
-						tval *= t;
+							if ( p === 3 ) {
 
-						if ( p === 3 ) {
+								dsp[ p ] = dtp[ p ] = 0.0;
+								dsval = dtval = 1.0;
 
-							dsp[ p ] = dtp[ p ] = 0.0;
-							dsval = dtval = 1.0;
+							} else {
 
-						} else {
+								dsp[ p ] = dsval * ( 3 - p );
+								dtp[ p ] = dtval * ( 3 - p );
+								dsval *= s;
+								dtval *= t;
 
-							dsp[ p ] = dsval * ( 3 - p );
-							dtp[ p ] = dtval * ( 3 - p );
-							dsval *= s;
-							dtval *= t;
+							}
 
 						}
 
-					}
+						vsp.fromArray( sp );
+						vtp.fromArray( tp );
+						vdsp.fromArray( dsp );
+						vdtp.fromArray( dtp );
 
-					vsp.fromArray( sp );
-					vtp.fromArray( tp );
-					vdsp.fromArray( dsp );
-					vdtp.fromArray( dtp );
+						// do for x,y,z
+						for ( let i = 0; i < 3; i ++ ) {
 
-					// do for x,y,z
-					for ( i = 0; i < 3; i ++ ) {
+							// multiply power vectors times matrix to get value
+							tcoord = vsp.clone();
+							tcoord.applyMatrix4( mgm[ i ] );
+							vert[ i ] = tcoord.dot( vtp );
 
-						// multiply power vectors times matrix to get value
-						tcoord = vsp.clone();
-						tcoord.applyMatrix4( mgm[ i ] );
-						vert[ i ] = tcoord.dot( vtp );
+							// get s and t tangent vectors
+							tcoord = vdsp.clone();
+							tcoord.applyMatrix4( mgm[ i ] );
+							sdir[ i ] = tcoord.dot( vtp );
 
-						// get s and t tangent vectors
-						tcoord = vdsp.clone();
-						tcoord.applyMatrix4( mgm[ i ] );
-						sdir[ i ] = tcoord.dot( vtp );
+							tcoord = vsp.clone();
+							tcoord.applyMatrix4( mgm[ i ] );
+							tdir[ i ] = tcoord.dot( vdtp );
 
-						tcoord = vsp.clone();
-						tcoord.applyMatrix4( mgm[ i ] );
-						tdir[ i ] = tcoord.dot( vdtp );
+						}
 
-					}
+						// find normal
+						vsdir.fromArray( sdir );
+						vtdir.fromArray( tdir );
+						norm.crossVectors( vtdir, vsdir );
+						norm.normalize();
 
-					// find normal
-					vsdir.fromArray( sdir );
-					vtdir.fromArray( tdir );
-					norm.crossVectors( vtdir, vsdir );
-					norm.normalize();
+						// if X and Z length is 0, at the cusp, so point the normal up or down, depending on patch number
+						if ( vert[ 0 ] === 0 && vert[ 1 ] === 0 ) {
 
-					// if X and Z length is 0, at the cusp, so point the normal up or down, depending on patch number
-					if ( vert[ 0 ] === 0 && vert[ 1 ] === 0 ) {
+							// if above the middle of the teapot, normal points up, else down
+							normOut.set( 0, vert[ 2 ] > maxHeight2 ? 1 : - 1, 0 );
 
-						// if above the middle of the teapot, normal points up, else down
-						normOut.set( 0, vert[ 2 ] > maxHeight2 ? 1 : - 1, 0 );
+						} else {
 
-					} else {
+							// standard output: rotate on X axis
+							normOut.set( norm.x, norm.z, - norm.y );
 
-						// standard output: rotate on X axis
-						normOut.set( norm.x, norm.z, - norm.y );
+						}
 
-					}
+						// store it all
+						vertices[ vertCount ++ ] = trueSize * vert[ 0 ];
+						vertices[ vertCount ++ ] = trueSize * ( vert[ 2 ] - maxHeight2 );
+						vertices[ vertCount ++ ] = - trueSize * vert[ 1 ];
 
-					// store it all
-					vertices[ vertCount ++ ] = trueSize * vert[ 0 ];
-					vertices[ vertCount ++ ] = trueSize * ( vert[ 2 ] - maxHeight2 );
-					vertices[ vertCount ++ ] = - trueSize * vert[ 1 ];
+						normals[ normCount ++ ] = normOut.x;
+						normals[ normCount ++ ] = normOut.y;
+						normals[ normCount ++ ] = normOut.z;
 
-					normals[ normCount ++ ] = normOut.x;
-					normals[ normCount ++ ] = normOut.y;
-					normals[ normCount ++ ] = normOut.z;
+						uvs[ uvCount ++ ] = 1 - t;
+						uvs[ uvCount ++ ] = 1 - s;
 
-					uvs[ uvCount ++ ] = 1 - t;
-					uvs[ uvCount ++ ] = 1 - s;
+					}
 
 				}
 
-			}
+				// save the faces
+				for ( let sstep = 0; sstep < segments; sstep ++ ) {
 
-			// save the faces
-			for ( sstep = 0; sstep < segments; sstep ++ ) {
+					for ( let tstep = 0; tstep < segments; tstep ++ ) {
 
-				for ( tstep = 0; tstep < segments; tstep ++ ) {
+						const v1 = surfCount * vertPerRow * vertPerRow + sstep * vertPerRow + tstep;
+						const v2 = v1 + 1;
+						const v3 = v2 + vertPerRow;
+						const v4 = v1 + vertPerRow;
 
-					v1 = surfCount * vertPerRow * vertPerRow + sstep * vertPerRow + tstep;
-					v2 = v1 + 1;
-					v3 = v2 + vertPerRow;
-					v4 = v1 + vertPerRow;
+						// Normals and UVs cannot be shared. Without clone(), you can see the consequences
+						// of sharing if you call geometry.applyMatrix4( matrix ).
+						if ( notDegenerate( v1, v2, v3 ) ) {
 
-					// Normals and UVs cannot be shared. Without clone(), you can see the consequences
-					// of sharing if you call geometry.applyMatrix4( matrix ).
-					if ( notDegenerate( v1, v2, v3 ) ) {
+							indices[ indexCount ++ ] = v1;
+							indices[ indexCount ++ ] = v2;
+							indices[ indexCount ++ ] = v3;
 
-						indices[ indexCount ++ ] = v1;
-						indices[ indexCount ++ ] = v2;
-						indices[ indexCount ++ ] = v3;
+						}
 
-					}
+						if ( notDegenerate( v1, v3, v4 ) ) {
 
-					if ( notDegenerate( v1, v3, v4 ) ) {
+							indices[ indexCount ++ ] = v1;
+							indices[ indexCount ++ ] = v3;
+							indices[ indexCount ++ ] = v4;
 
-						indices[ indexCount ++ ] = v1;
-						indices[ indexCount ++ ] = v3;
-						indices[ indexCount ++ ] = v4;
+						}
 
 					}
 
 				}
 
-			}
+				// increment only if a surface was used
+				surfCount ++;
 
-			// increment only if a surface was used
-			surfCount ++;
+			}
 
 		}
 
-	}
+		this.setIndex( new BufferAttribute( indices, 1 ) );
+		this.setAttribute( 'position', new BufferAttribute( vertices, 3 ) );
+		this.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );
+		this.setAttribute( 'uv', new BufferAttribute( uvs, 2 ) );
 
-	this.setIndex( new BufferAttribute( indices, 1 ) );
-	this.setAttribute( 'position', new BufferAttribute( vertices, 3 ) );
-	this.setAttribute( 'normal', new BufferAttribute( normals, 3 ) );
-	this.setAttribute( 'uv', new BufferAttribute( uvs, 2 ) );
-
-	this.computeBoundingSphere();
-
-};
+		this.computeBoundingSphere();
 
+	}
 
-TeapotGeometry.prototype = Object.create( BufferGeometry.prototype );
-TeapotGeometry.prototype.constructor = TeapotGeometry;
+}
 
 export { TeapotGeometry };

Vissa filer visades inte eftersom för många filer har ändrats