Browse Source

New TubeBufferGeometry (#9841)

* TubeBufferGeometry: Initial Commit

* TubeBufferGeometry: Cleanup

* webgl_geometry_extrude_splines: cleanup

* TubeBufferGeometry: Changed FrenetFrames to private function

* TubeBufferGeometry: Changed FrenetFrames function call
Michael Herzog 8 years ago
parent
commit
4b0b278f11

+ 119 - 0
docs/api/geometries/TubeBufferGeometry.html

@@ -0,0 +1,119 @@
+<!DOCTYPE html>
+<html lang="en">
+	<head>
+		<meta charset="utf-8" />
+		<base href="../../" />
+		<script src="list.js"></script>
+		<script src="page.js"></script>
+		<link type="text/css" rel="stylesheet" href="page.css" />
+	</head>
+	<body>
+		[page:BufferGeometry] &rarr;
+
+		<h1>[name]</h1>
+
+		<div class="desc">Creates a tube that extrudes along a 3d curve.</div>
+
+		<iframe id="scene" src="scenes/geometry-browser.html#TubeBufferGeometry"></iframe>
+
+		<script>
+
+		// iOS iframe auto-resize workaround
+
+		if ( /(iPad|iPhone|iPod)/g.test( navigator.userAgent ) ) {
+
+			var scene = document.getElementById( 'scene' );
+
+			scene.style.width = getComputedStyle( scene ).width;
+			scene.style.height = getComputedStyle( scene ).height;
+			scene.setAttribute( 'scrolling', 'no' );
+
+		}
+
+		</script>
+
+		<h2>Example</h2>
+
+		<code>
+		var CustomSinCurve = THREE.Curve.create(
+
+			function ( scale ) { //custom curve constructor
+
+				this.scale = ( scale === undefined ) ? 1 : scale;
+
+			},
+
+			function ( t ) { //getPoint: t is between 0-1
+
+				var tx = t * 3 - 1.5;
+				var ty = Math.sin( 2 * Math.PI * t );
+				var tz = 0;
+
+				return new THREE.Vector3( tx, ty, tz ).multiplyScalar( this.scale );
+
+			}
+
+		);
+
+		var path = new CustomSinCurve( 10 );
+		var geometry = new THREE.TubeBufferGeometry( path, 20, 2, 8, false );
+		var material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
+		var mesh = new THREE.Mesh( geometry, material );
+		scene.add( mesh );
+		</code>
+
+		<h2>Constructor</h2>
+
+
+		<h3>[name]([page:Curve path], [page:Integer tubularSegments], [page:Float radius], [page:Integer radiusSegments], [page:Boolean closed])</h3>
+		<div>
+		path — [page:Curve] - A path that inherits from the [page:Curve] base class<br />
+		tubularSegments — [page:Integer] - The number of segments that make up the tube, default is 64<br />
+		radius — [page:Float] - The radius of the tube, default is 1<br />
+		radiusSegments — [page:Integer] - The number of segments that make up the cross-section, default is 8 <br />
+		closed — [page:Boolean] Is the tube open or closed, default is false <br />
+		</div>
+
+
+		<h2>Properties</h2>
+
+		<h3>[property:Object parameters]</h3>
+		<div>
+		An object with all of the parameters that were used to generate the geometry.
+		</div>
+
+		<h3>[property:Array tangents]</h3>
+		<div>
+		An array of [page:Vector3] tangents
+		</div>
+
+		<h3>[property:Array normals]</h3>
+		<div>
+		An array of [page:Vector3] normals
+		</div>
+
+		<h3>[property:Array binormals]</h3>
+		<div>
+		An array of [page:Vector3] binormals
+		</div>
+
+
+		<h2>Methods</h2>
+
+
+		<h3>THREE.TubeBufferGeometry.FrenetFrames([page:Curve path], [page:Integer segments], [page:Boolean closed])</h3>
+		<div>
+		path — A path that inherits from the [page:Curve] base class <br />
+		segments — The number of segments that make up the tube <br />
+		closed — Is the tube open or closed
+		</div>
+		<div>
+		A static method that generates the Frenet Frames. This is internally run on any new TubeBufferGeometry and then the
+		generated tangents, normals, and binormals are exposed as properties on the TubeBufferGeometry object.
+		</div>
+
+		<h2>Source</h2>
+
+		[link:https://github.com/mrdoob/three.js/blob/master/src/[path].js src/[path].js]
+	</body>
+</html>

+ 5 - 5
docs/api/geometries/TubeGeometry.html

@@ -45,9 +45,9 @@
 
 
 			function ( t ) { //getPoint: t is between 0-1
 			function ( t ) { //getPoint: t is between 0-1
 
 
-				var tx = t * 3 - 1.5,
-				ty = Math.sin( 2 * Math.PI * t ),
-				tz = 0;
+				var tx = t * 3 - 1.5;
+				var ty = Math.sin( 2 * Math.PI * t );
+				var tz = 0;
 
 
 				return new THREE.Vector3( tx, ty, tz ).multiplyScalar( this.scale );
 				return new THREE.Vector3( tx, ty, tz ).multiplyScalar( this.scale );
 
 
@@ -65,10 +65,10 @@
 		<h2>Constructor</h2>
 		<h2>Constructor</h2>
 
 
 
 
-		<h3>[name]([page:Curve path], [page:Integer segments], [page:Float radius], [page:Integer radiusSegments], [page:Boolean closed])</h3>
+		<h3>[name]([page:Curve path], [page:Integer tubularSegments], [page:Float radius], [page:Integer radiusSegments], [page:Boolean closed])</h3>
 		<div>
 		<div>
 		path — [page:Curve] - A path that inherits from the [page:Curve] base class<br />
 		path — [page:Curve] - A path that inherits from the [page:Curve] base class<br />
-		segments — [page:Integer] - The number of segments that make up the tube, default is 64<br />
+		tubularSegments — [page:Integer] - The number of segments that make up the tube, default is 64<br />
 		radius — [page:Float] - The radius of the tube, default is 1<br />
 		radius — [page:Float] - The radius of the tube, default is 1<br />
 		radiusSegments — [page:Integer] - The number of segments that make up the cross-section, default is 8 <br />
 		radiusSegments — [page:Integer] - The number of segments that make up the cross-section, default is 8 <br />
 		closed — [page:Boolean] Is the tube open or closed, default is false <br />
 		closed — [page:Boolean] Is the tube open or closed, default is false <br />

+ 2 - 1
docs/list.js

@@ -71,7 +71,8 @@ var list = {
 			[ "TorusGeometry", "api/geometries/TorusGeometry" ],
 			[ "TorusGeometry", "api/geometries/TorusGeometry" ],
 			[ "TorusKnotBufferGeometry", "api/geometries/TorusKnotBufferGeometry" ],
 			[ "TorusKnotBufferGeometry", "api/geometries/TorusKnotBufferGeometry" ],
 			[ "TorusKnotGeometry", "api/geometries/TorusKnotGeometry" ],
 			[ "TorusKnotGeometry", "api/geometries/TorusKnotGeometry" ],
-			[ "TubeGeometry", "api/geometries/TubeGeometry" ]
+			[ "TubeGeometry", "api/geometries/TubeGeometry" ],
+			[ "TubeBufferGeometry", "api/geometries/TubeBufferGeometry" ]
 		],
 		],
 
 
 		"Lights": [
 		"Lights": [

+ 41 - 13
docs/scenes/js/geometry.js

@@ -91,6 +91,26 @@ function updateGroupGeometry( mesh, geometry ) {
 
 
 }
 }
 
 
+var CustomSinCurve = THREE.Curve.create(
+
+	function ( scale ) {
+
+		this.scale = ( scale === undefined ) ? 1 : scale;
+
+	},
+
+	function ( t ) {
+
+		var tx = t * 3 - 1.5;
+		var ty = Math.sin( 2 * Math.PI * t );
+		var tz = 0;
+
+		return new THREE.Vector3( tx, ty, tz ).multiplyScalar( this.scale );
+
+	}
+
+);
+
 var guis = {
 var guis = {
 
 
 	BoxBufferGeometry : function( mesh ) {
 	BoxBufferGeometry : function( mesh ) {
@@ -1136,37 +1156,45 @@ var guis = {
 			radiusSegments: 8
 			radiusSegments: 8
 		};
 		};
 
 
-		var CustomSinCurve = THREE.Curve.create(
+		var path = new CustomSinCurve( 10 );
 
 
-			function ( scale ) {
+		function generateGeometry() {
 
 
-				this.scale = ( scale === undefined ) ? 1 : scale;
+			updateGroupGeometry( mesh,
+				new THREE.TubeGeometry( path, data.segments, data.radius, data.radiusSegments, false )
+			);
 
 
-			},
+		}
 
 
-			function ( t ) {
+		var folder = gui.addFolder( 'THREE.TubeGeometry' );
 
 
-				var tx = t * 3 - 1.5;
-				var ty = Math.sin( 2 * Math.PI * t );
-				var tz = 0;
+		folder.add( data, 'segments', 1, 100 ).step( 1 ).onChange( generateGeometry );
+		folder.add( data, 'radius', 1, 10 ).onChange( generateGeometry );
+		folder.add( data, 'radiusSegments', 1, 20 ).step( 1 ).onChange( generateGeometry );
 
 
-				return new THREE.Vector3( tx, ty, tz ).multiplyScalar( this.scale );
+		generateGeometry();
 
 
-			}
+	},
 
 
-		);
+	TubeBufferGeometry : function( mesh ) {
+
+		var data = {
+			segments : 20,
+			radius : 2,
+			radiusSegments: 8
+		};
 
 
 		var path = new CustomSinCurve( 10 );
 		var path = new CustomSinCurve( 10 );
 
 
 		function generateGeometry() {
 		function generateGeometry() {
 
 
 			updateGroupGeometry( mesh,
 			updateGroupGeometry( mesh,
-				new THREE.TubeGeometry( path, data.segments, data.radius, data.radiusSegments, false )
+				new THREE.TubeBufferGeometry( path, data.segments, data.radius, data.radiusSegments, false )
 			);
 			);
 
 
 		}
 		}
 
 
-		var folder = gui.addFolder( 'THREE.TubeGeometry' );
+		var folder = gui.addFolder( 'THREE.TubeBufferGeometry' );
 
 
 		folder.add( data, 'segments', 1, 100 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'segments', 1, 100 ).step( 1 ).onChange( generateGeometry );
 		folder.add( data, 'radius', 1, 10 ).onChange( generateGeometry );
 		folder.add( data, 'radius', 1, 10 ).onChange( generateGeometry );

+ 62 - 121
examples/webgl_geometry_extrude_splines.html

@@ -1,7 +1,7 @@
 <!DOCTYPE html>
 <!DOCTYPE html>
 <html lang="en">
 <html lang="en">
 	<head>
 	<head>
-		<title>three.js webgl - geometry - shapes</title>
+		<title>three.js webgl - geometry - spline extrusion</title>
 		<meta charset="utf-8">
 		<meta charset="utf-8">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
 		<style>
 		<style>
@@ -16,6 +16,7 @@
 	<body>
 	<body>
 
 
 		<script src="../build/three.js"></script>
 		<script src="../build/three.js"></script>
+		<script src="js/controls/OrbitControls.js"></script>
 
 
 		<!-- where curves formulas are defined -->
 		<!-- where curves formulas are defined -->
 		<script src="js/CurveExtras.js"></script>
 		<script src="js/CurveExtras.js"></script>
@@ -43,16 +44,30 @@
 		var normal = new THREE.Vector3();
 		var normal = new THREE.Vector3();
 
 
 
 
-		var pipeSpline = new THREE.CatmullRomCurve3([
-				new THREE.Vector3(0, 10, -10), new THREE.Vector3(10, 0, -10), new THREE.Vector3(20, 0, 0), new THREE.Vector3(30, 0, 10), new THREE.Vector3(30, 0, 20), new THREE.Vector3(20, 0, 30), new THREE.Vector3(10, 0, 30), new THREE.Vector3(0, 0, 30), new THREE.Vector3(-10, 10, 30), new THREE.Vector3(-10, 20, 30), new THREE.Vector3(0, 30, 30), new THREE.Vector3(10, 30, 30), new THREE.Vector3(20, 30, 15), new THREE.Vector3(10, 30, 10), new THREE.Vector3(0, 30, 10), new THREE.Vector3(-10, 20, 10), new THREE.Vector3(-10, 10, 10), new THREE.Vector3(0, 0, 10), new THREE.Vector3(10, -10, 10), new THREE.Vector3(20, -15, 10), new THREE.Vector3(30, -15, 10), new THREE.Vector3(40, -15, 10), new THREE.Vector3(50, -15, 10), new THREE.Vector3(60, 0, 10), new THREE.Vector3(70, 0, 0), new THREE.Vector3(80, 0, 0), new THREE.Vector3(90, 0, 0), new THREE.Vector3(100, 0, 0)]);
-
-		var sampleClosedSpline = new THREE.CatmullRomCurve3([
-			new THREE.Vector3(0, -40, -40),
-			new THREE.Vector3(0, 40, -40),
-			new THREE.Vector3(0, 140, -40),
-			new THREE.Vector3(0, 40, 40),
-			new THREE.Vector3(0, -40, 40),
-		]);
+		var pipeSpline = new THREE.CatmullRomCurve3( [
+				new THREE.Vector3( 0, 10, -10 ), new THREE.Vector3( 10, 0, -10 ),
+				new THREE.Vector3( 20, 0, 0 ), new THREE.Vector3( 30, 0, 10 ),
+				new THREE.Vector3( 30, 0, 20 ), new THREE.Vector3( 20, 0, 30 ),
+				new THREE.Vector3( 10, 0, 30 ), new THREE.Vector3( 0, 0, 30 ),
+				new THREE.Vector3( -10, 10, 30 ), new THREE.Vector3( -10, 20, 30 ),
+				new THREE.Vector3( 0, 30, 30 ), new THREE.Vector3( 10, 30, 30 ),
+				new THREE.Vector3( 20, 30, 15 ), new THREE.Vector3( 10, 30, 10 ),
+				new THREE.Vector3( 0, 30, 10 ), new THREE.Vector3( -10, 20, 10 ),
+				new THREE.Vector3( -10, 10, 10 ), new THREE.Vector3( 0, 0, 10 ),
+				new THREE.Vector3( 10, -10, 10 ), new THREE.Vector3( 20, -15, 10 ),
+				new THREE.Vector3( 30, -15, 10 ), new THREE.Vector3( 40, -15, 10 ),
+				new THREE.Vector3( 50, -15, 10 ), new THREE.Vector3( 60, 0, 10 ),
+				new THREE.Vector3( 70, 0, 0 ), new THREE.Vector3( 80, 0, 0 ),
+				new THREE.Vector3( 90, 0, 0 ), new THREE.Vector3( 100, 0, 0 )
+		] );
+
+		var sampleClosedSpline = new THREE.CatmullRomCurve3( [
+			new THREE.Vector3( 0, -40, -40 ),
+			new THREE.Vector3( 0, 40, -40 ),
+			new THREE.Vector3( 0, 140, -40 ),
+			new THREE.Vector3( 0, 40, 40 ),
+			new THREE.Vector3( 0, -40, 40 ),
+		] );
 
 
 		sampleClosedSpline.type = 'catmullrom';
 		sampleClosedSpline.type = 'catmullrom';
 		sampleClosedSpline.closed = true;
 		sampleClosedSpline.closed = true;
@@ -60,14 +75,14 @@
 		// Keep a dictionary of Curve instances
 		// Keep a dictionary of Curve instances
 		var splines = {
 		var splines = {
 			GrannyKnot: new THREE.Curves.GrannyKnot(),
 			GrannyKnot: new THREE.Curves.GrannyKnot(),
-			HeartCurve: new THREE.Curves.HeartCurve(3.5),
-			VivianiCurve: new THREE.Curves.VivianiCurve(70),
+			HeartCurve: new THREE.Curves.HeartCurve( 3.5 ),
+			VivianiCurve: new THREE.Curves.VivianiCurve( 70 ),
 			KnotCurve: new THREE.Curves.KnotCurve(),
 			KnotCurve: new THREE.Curves.KnotCurve(),
 			HelixCurve: new THREE.Curves.HelixCurve(),
 			HelixCurve: new THREE.Curves.HelixCurve(),
 			TrefoilKnot: new THREE.Curves.TrefoilKnot(),
 			TrefoilKnot: new THREE.Curves.TrefoilKnot(),
-			TorusKnot: new THREE.Curves.TorusKnot(20),
-			CinquefoilKnot: new THREE.Curves.CinquefoilKnot(20),
-			TrefoilPolynomialKnot: new THREE.Curves.TrefoilPolynomialKnot(14),
+			TorusKnot: new THREE.Curves.TorusKnot( 20 ),
+			CinquefoilKnot: new THREE.Curves.CinquefoilKnot( 20 ),
+			TrefoilPolynomialKnot: new THREE.Curves.TrefoilPolynomialKnot( 14 ),
 			FigureEightPolynomialKnot: new THREE.Curves.FigureEightPolynomialKnot(),
 			FigureEightPolynomialKnot: new THREE.Curves.FigureEightPolynomialKnot(),
 			DecoratedTorusKnot4a: new THREE.Curves.DecoratedTorusKnot4a(),
 			DecoratedTorusKnot4a: new THREE.Curves.DecoratedTorusKnot4a(),
 			DecoratedTorusKnot4b: new THREE.Curves.DecoratedTorusKnot4b(),
 			DecoratedTorusKnot4b: new THREE.Curves.DecoratedTorusKnot4b(),
@@ -77,17 +92,16 @@
 			SampleClosedSpline: sampleClosedSpline
 			SampleClosedSpline: sampleClosedSpline
 		};
 		};
 
 
-
-
-
 		extrudePath = new THREE.Curves.TrefoilKnot();
 		extrudePath = new THREE.Curves.TrefoilKnot();
 
 
 		var dropdown = '<select id="dropdown" onchange="addTube(this.value)">';
 		var dropdown = '<select id="dropdown" onchange="addTube(this.value)">';
 
 
 		var s;
 		var s;
 		for ( s in splines ) {
 		for ( s in splines ) {
+
 			dropdown += '<option value="' + s + '"';
 			dropdown += '<option value="' + s + '"';
 			dropdown += '>' + s + '</option>';
 			dropdown += '>' + s + '</option>';
+
 		}
 		}
 
 
 		dropdown += '</select>';
 		dropdown += '</select>';
@@ -101,27 +115,27 @@
 
 
 		function addTube() {
 		function addTube() {
 
 
-			var value = document.getElementById('dropdown').value;
+			var value = document.getElementById( 'dropdown' ).value;
 
 
-			var segments = parseInt(document.getElementById('segments').value);
-			closed2 = document.getElementById('closed').checked;
+			var segments = parseInt( document.getElementById( 'segments' ).value );
+			closed2 = document.getElementById( 'closed' ).checked;
 
 
-			var radiusSegments = parseInt(document.getElementById('radiusSegments').value);
+			var radiusSegments = parseInt( document.getElementById( 'radiusSegments' ).value );
 
 
-			if (tubeMesh) parent.remove(tubeMesh);
+			if ( tubeMesh !== undefined ) parent.remove( tubeMesh );
 
 
-			extrudePath = splines[value];
+			extrudePath = splines[ value ];
 
 
-			tube = new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed2);
+			tube = new THREE.TubeBufferGeometry( extrudePath, segments, 2, radiusSegments, closed2 );
 
 
-			addGeometry(tube, 0xff00ff);
+			addGeometry( tube, 0xff00ff );
 			setScale();
 			setScale();
 
 
 		}
 		}
 
 
 		function setScale() {
 		function setScale() {
 
 
-			scale = parseInt( document.getElementById('scale').value );
+			scale = parseInt( document.getElementById( 'scale' ).value );
 			tubeMesh.scale.set( scale, scale, scale );
 			tubeMesh.scale.set( scale, scale, scale );
 
 
 		}
 		}
@@ -132,15 +146,15 @@
 			// 3d shape
 			// 3d shape
 
 
 			tubeMesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [
 			tubeMesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [
-				new THREE.MeshLambertMaterial({
+				new THREE.MeshLambertMaterial( {
 					color: color
 					color: color
-				}),
-				new THREE.MeshBasicMaterial({
+				} ),
+				new THREE.MeshBasicMaterial( {
 					color: 0x000000,
 					color: 0x000000,
 					opacity: 0.3,
 					opacity: 0.3,
 					wireframe: true,
 					wireframe: true,
 					transparent: true
 					transparent: true
-			})]);
+			} ) ] );
 
 
 			parent.add( tubeMesh );
 			parent.add( tubeMesh );
 
 
@@ -148,31 +162,31 @@
 
 
 		function animateCamera( toggle ) {
 		function animateCamera( toggle ) {
 
 
-			if ( toggle ) {
+			if ( toggle === true ) {
 
 
 				animation = animation === false;
 				animation = animation === false;
-				document.getElementById('animation').value = 'Camera Spline Animation View: ' + (animation? 'ON': 'OFF');
+				document.getElementById( 'animation' ).value = 'Camera Spline Animation View: ' + ( animation ? 'ON' : 'OFF' );
 
 
 			}
 			}
 
 
-			lookAhead = document.getElementById('lookAhead').checked;
+			lookAhead = document.getElementById( 'lookAhead' ).checked;
 
 
-			showCameraHelper = document.getElementById('cameraHelper').checked;
+			showCameraHelper = document.getElementById( 'cameraHelper' ).checked;
 
 
 			cameraHelper.visible = showCameraHelper;
 			cameraHelper.visible = showCameraHelper;
 			cameraEye.visible = showCameraHelper;
 			cameraEye.visible = showCameraHelper;
-		}
 
 
+		}
 
 
 		init();
 		init();
 		animate();
 		animate();
 
 
 		function init() {
 		function init() {
 
 
-			container = document.createElement('div');
-			document.body.appendChild(container);
+			container = document.createElement( 'div' );
+			document.body.appendChild( container );
 
 
-			var info = document.createElement('div');
+			var info = document.createElement( 'div' );
 			info.style.position = 'absolute';
 			info.style.position = 'absolute';
 			info.style.top = '10px';
 			info.style.top = '10px';
 			info.style.width = '100%';
 			info.style.width = '100%';
@@ -188,12 +202,12 @@
 
 
 			info.innerHTML += '<br/><br/><input id="animation" type="button" onclick="animateCamera(true)" value="Camera Spline Animation View: OFF"/><br/> Look Ahead <input id="lookAhead" type="checkbox" onchange="animateCamera()" /> Camera Helper <input id="cameraHelper" type="checkbox" onchange="animateCamera()" />';
 			info.innerHTML += '<br/><br/><input id="animation" type="button" onclick="animateCamera(true)" value="Camera Spline Animation View: OFF"/><br/> Look Ahead <input id="lookAhead" type="checkbox" onchange="animateCamera()" /> Camera Helper <input id="cameraHelper" type="checkbox" onchange="animateCamera()" />';
 
 
-			container.appendChild(info);
+			container.appendChild( info );
 
 
 			//
 			//
 
 
-			camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 1000);
-			camera.position.set(0, 50, 500);
+			camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.01, 10000 );
+			camera.position.set( 0, 50, 500 );
 
 
 			scene = new THREE.Scene();
 			scene = new THREE.Scene();
 
 
@@ -202,7 +216,6 @@
 			scene.add( light );
 			scene.add( light );
 
 
 			parent = new THREE.Object3D();
 			parent = new THREE.Object3D();
-			parent.position.y = 100;
 			scene.add( parent );
 			scene.add( parent );
 
 
 			splineCamera = new THREE.PerspectiveCamera( 84, window.innerWidth / window.innerHeight, 0.01, 1000 );
 			splineCamera = new THREE.PerspectiveCamera( 84, window.innerWidth / window.innerHeight, 0.01, 1000 );
@@ -213,7 +226,7 @@
 
 
 			addTube();
 			addTube();
 
 
-			// Debug point
+			// debug camera
 
 
 			cameraEye = new THREE.Mesh( new THREE.SphereGeometry( 5 ), new THREE.MeshBasicMaterial( { color: 0xdddddd } ) );
 			cameraEye = new THREE.Mesh( new THREE.SphereGeometry( 5 ), new THREE.MeshBasicMaterial( { color: 0xdddddd } ) );
 			parent.add( cameraEye );
 			parent.add( cameraEye );
@@ -232,9 +245,9 @@
 			stats = new Stats();
 			stats = new Stats();
 			container.appendChild( stats.dom );
 			container.appendChild( stats.dom );
 
 
-			renderer.domElement.addEventListener( 'mousedown', onDocumentMouseDown, false );
-			renderer.domElement.addEventListener( 'touchstart', onDocumentTouchStart, false );
-			renderer.domElement.addEventListener( 'touchmove', onDocumentTouchMove, false );
+			//
+
+			controls = new THREE.OrbitControls( camera, renderer.domElement );
 
 
 			//
 			//
 
 
@@ -256,71 +269,6 @@
 
 
 		//
 		//
 
 
-		function onDocumentMouseDown(event) {
-
-			event.preventDefault();
-
-			renderer.domElement.addEventListener( 'mousemove', onDocumentMouseMove, false );
-			renderer.domElement.addEventListener( 'mouseup', onDocumentMouseUp, false );
-			renderer.domElement.addEventListener( 'mouseout', onDocumentMouseOut, false );
-
-			mouseXOnMouseDown = event.clientX - windowHalfX;
-			targetRotationOnMouseDown = targetRotation;
-
-		}
-
-		function onDocumentMouseMove(event) {
-
-			mouseX = event.clientX - windowHalfX;
-
-			targetRotation = targetRotationOnMouseDown + (mouseX - mouseXOnMouseDown) * 0.02;
-
-		}
-
-		function onDocumentMouseUp(event) {
-
-			renderer.domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false );
-			renderer.domElement.removeEventListener( 'mouseup', onDocumentMouseUp, false );
-			renderer.domElement.removeEventListener( 'mouseout', onDocumentMouseOut, false );
-
-		}
-
-		function onDocumentMouseOut(event) {
-
-			renderer.domElement.removeEventListener( 'mousemove', onDocumentMouseMove, false );
-			renderer.domElement.removeEventListener( 'mouseup', onDocumentMouseUp, false );
-			renderer.domElement.removeEventListener( 'mouseout', onDocumentMouseOut, false );
-
-		}
-
-		function onDocumentTouchStart(event) {
-
-			if (event.touches.length == 1) {
-
-				event.preventDefault();
-
-				mouseXOnMouseDown = event.touches[ 0 ].pageX - windowHalfX;
-				targetRotationOnMouseDown = targetRotation;
-
-			}
-
-		}
-
-		function onDocumentTouchMove(event) {
-
-			if (event.touches.length == 1) {
-
-				event.preventDefault();
-
-				mouseX = event.touches[ 0 ].pageX - windowHalfX;
-				targetRotation = targetRotationOnMouseDown + ( mouseX - mouseXOnMouseDown ) * 0.05;
-
-			}
-
-		}
-
-		//
-
 		function animate() {
 		function animate() {
 
 
 			requestAnimationFrame( animate );
 			requestAnimationFrame( animate );
@@ -362,23 +310,16 @@
 			splineCamera.position.copy( pos );
 			splineCamera.position.copy( pos );
 			cameraEye.position.copy( pos );
 			cameraEye.position.copy( pos );
 
 
-
-			// Camera Orientation 1 - default look at
-			// splineCamera.lookAt( lookAt );
-
 			// Using arclength for stablization in look ahead.
 			// Using arclength for stablization in look ahead.
 			var lookAt = tube.parameters.path.getPointAt( ( t + 30 / tube.parameters.path.getLength() ) % 1 ).multiplyScalar( scale );
 			var lookAt = tube.parameters.path.getPointAt( ( t + 30 / tube.parameters.path.getLength() ) % 1 ).multiplyScalar( scale );
 
 
 			// Camera Orientation 2 - up orientation via normal
 			// Camera Orientation 2 - up orientation via normal
-			if (!lookAhead)
-			lookAt.copy( pos ).add( dir );
+			if ( !lookAhead ) lookAt.copy( pos ).add( dir );
 			splineCamera.matrix.lookAt(splineCamera.position, lookAt, normal);
 			splineCamera.matrix.lookAt(splineCamera.position, lookAt, normal);
 			splineCamera.rotation.setFromRotationMatrix( splineCamera.matrix, splineCamera.rotation.order );
 			splineCamera.rotation.setFromRotationMatrix( splineCamera.matrix, splineCamera.rotation.order );
 
 
 			cameraHelper.update();
 			cameraHelper.update();
 
 
-			parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05;
-
 			renderer.render( scene, animation === true ? splineCamera : camera );
 			renderer.render( scene, animation === true ? splineCamera : camera );
 
 
 		}
 		}

+ 1 - 0
src/geometries/Geometries.js

@@ -12,6 +12,7 @@ export { DodecahedronBufferGeometry } from './DodecahedronBufferGeometry.js';
 export { PolyhedronGeometry } from './PolyhedronGeometry.js';
 export { PolyhedronGeometry } from './PolyhedronGeometry.js';
 export { PolyhedronBufferGeometry } from './PolyhedronBufferGeometry.js';
 export { PolyhedronBufferGeometry } from './PolyhedronBufferGeometry.js';
 export { TubeGeometry } from './TubeGeometry.js';
 export { TubeGeometry } from './TubeGeometry.js';
+export { TubeBufferGeometry } from './TubeBufferGeometry.js';
 export { TorusKnotGeometry } from './TorusKnotGeometry.js';
 export { TorusKnotGeometry } from './TorusKnotGeometry.js';
 export { TorusKnotBufferGeometry } from './TorusKnotBufferGeometry.js';
 export { TorusKnotBufferGeometry } from './TorusKnotBufferGeometry.js';
 export { TorusGeometry } from './TorusGeometry.js';
 export { TorusGeometry } from './TorusGeometry.js';

+ 301 - 0
src/geometries/TubeBufferGeometry.js

@@ -0,0 +1,301 @@
+import { BufferGeometry } from '../core/BufferGeometry';
+import { Float32Attribute, Uint16Attribute, Uint32Attribute } from '../core/BufferAttribute';
+import { _Math } from '../math/Math';
+import { Vector2 } from '../math/Vector2';
+import { Vector3 } from '../math/Vector3';
+import { Matrix4 } from '../math/Matrix4';
+
+/**
+ * @author Mugen87 / https://github.com/Mugen87
+ *
+ * Creates a tube which extrudes along a 3d spline.
+ *
+ * Uses parallel transport frames as described in:
+ *
+ * http://www.cs.indiana.edu/pub/techreports/TR425.pdf
+ */
+
+function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) {
+
+	BufferGeometry.call( this );
+
+	this.type = 'TubeBufferGeometry';
+
+	this.parameters = {
+		path: path,
+		tubularSegments: tubularSegments,
+		radius: radius,
+		radialSegments: radialSegments,
+		closed: closed
+	};
+
+	tubularSegments = tubularSegments || 64;
+	radius = radius || 1;
+	radialSegments = radialSegments || 8;
+	closed = closed || false;
+
+	var frames = new FrenetFrames( path, tubularSegments, closed );
+
+	// expose internals
+
+	this.tangents = frames.tangents;
+	this.normals = frames.normals;
+	this.binormals = frames.binormals;
+
+	// helper variables
+
+	var vertex = new Vector3();
+	var normal = new Vector3();
+	var uv = new Vector2();
+
+	var i, j;
+
+	// buffer
+
+	var vertices = [];
+	var normals = [];
+	var uvs = [];
+	var indices = [];
+
+	// create buffer data
+
+	generateBufferData();
+
+	// build geometry
+
+	this.setIndex( ( indices.length > 65535 ? Uint32Attribute : Uint16Attribute )( indices, 1 ) );
+	this.addAttribute( 'position', Float32Attribute( vertices, 3 ) );
+	this.addAttribute( 'normal', Float32Attribute( normals, 3 ) );
+	this.addAttribute( 'uv', Float32Attribute( uvs, 2 ) );
+
+	// functions
+
+	function generateBufferData() {
+
+		for ( i = 0; i < tubularSegments; i ++ ) {
+
+			generateSegment( i );
+
+		}
+
+		// if the geometry is not closed, generate the last row of vertices and normals
+		// at the regular position on the given path
+		//
+		// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
+
+		generateSegment( ( closed === false ) ? tubularSegments : 0 );
+
+		// uvs are generated in a separate function.
+		// this makes it easy compute correct values for closed geometries
+
+		generateUVs();
+
+		// finally create faces
+
+		generateIndices();
+
+	}
+
+	function generateSegment( i ) {
+
+		// we use getPointAt to sample evenly distributed points from the given path
+
+		var P = path.getPointAt( i / tubularSegments );
+
+		// retrieve corresponding normal and binormal
+
+		var N = frames.normals[ i ];
+		var B = frames.binormals[ i ];
+
+		// generate normals and vertices for the current segment
+
+		for ( j = 0; j <= radialSegments; j ++ ) {
+
+			var v = j / radialSegments * Math.PI * 2;
+
+			var sin =   Math.sin( v );
+			var cos = - Math.cos( v );
+
+			// normal
+
+			normal.x = ( cos * N.x + sin * B.x );
+			normal.y = ( cos * N.y + sin * B.y );
+			normal.z = ( cos * N.z + sin * B.z );
+			normal.normalize();
+
+			normals.push( normal.x, normal.y, normal.z );
+
+			// vertex
+
+			vertex.x = P.x + radius * normal.x;
+			vertex.y = P.y + radius * normal.y;
+			vertex.z = P.z + radius * normal.z;
+
+			vertices.push( vertex.x, vertex.y, vertex.z );
+
+		}
+
+	}
+
+	function generateIndices() {
+
+		for ( j = 1; j <= tubularSegments; j ++ ) {
+
+			for ( i = 1; i <= radialSegments; i ++ ) {
+
+				var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
+				var b = ( radialSegments + 1 ) * j + ( i - 1 );
+				var c = ( radialSegments + 1 ) * j + i;
+				var d = ( radialSegments + 1 ) * ( j - 1 ) + i;
+
+				// faces
+
+				indices.push( a, b, d );
+				indices.push( b, c, d );
+
+			}
+
+		}
+
+	}
+
+	function generateUVs() {
+
+		for ( i = 0; i <= tubularSegments; i ++ ) {
+
+			for ( j = 0; j <= radialSegments; j ++ ) {
+
+				uv.x = i / tubularSegments;
+				uv.y = j / radialSegments;
+
+				uvs.push( uv.x, uv.y );
+
+			}
+
+		}
+
+	}
+
+}
+
+TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
+TubeBufferGeometry.prototype.constructor = TubeBufferGeometry;
+
+// For computing of Frenet frames, exposing the tangents, normals and binormals the spline
+
+function FrenetFrames( path, segments, closed ) {
+
+	var	normal = new Vector3();
+
+	var tangents = [];
+	var normals = [];
+	var binormals = [];
+
+	var vec = new Vector3();
+	var mat = new Matrix4();
+
+	var i, u, theta;
+
+	// expose internals
+
+	this.tangents = tangents;
+	this.normals = normals;
+	this.binormals = binormals;
+
+	// compute the tangent vectors for each segment on the path
+
+	for ( i = 0; i <= segments; i ++ ) {
+
+		u = i / segments;
+
+		tangents[ i ] = path.getTangentAt( u );
+		tangents[ i ].normalize();
+
+	}
+
+	// select an initial normal vector perpendicular to the first tangent vector,
+	// and in the direction of the minimum tangent xyz component
+
+	normals[ 0 ] = new Vector3();
+	binormals[ 0 ] = new Vector3();
+	var min = Number.MAX_VALUE;
+	var tx = Math.abs( tangents[ 0 ].x );
+	var ty = Math.abs( tangents[ 0 ].y );
+	var tz = Math.abs( tangents[ 0 ].z );
+
+	if ( tx <= min ) {
+
+		min = tx;
+		normal.set( 1, 0, 0 );
+
+	}
+
+	if ( ty <= min ) {
+
+		min = ty;
+		normal.set( 0, 1, 0 );
+
+	}
+
+	if ( tz <= min ) {
+
+		normal.set( 0, 0, 1 );
+
+	}
+
+	vec.crossVectors( tangents[ 0 ], normal ).normalize();
+
+	normals[ 0 ].crossVectors( tangents[ 0 ], vec );
+	binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
+
+
+	// compute the slowly-varying normal and binormal vectors for each segment on the path
+
+	for ( i = 1; i <= segments; i ++ ) {
+
+		normals[ i ] = normals[ i - 1 ].clone();
+
+		binormals[ i ] = binormals[ i - 1 ].clone();
+
+		vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
+
+		if ( vec.length() > Number.EPSILON ) {
+
+			vec.normalize();
+
+			theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
+
+			normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
+
+		}
+
+		binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
+
+	}
+
+	// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
+
+	if ( closed ) {
+
+		theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );
+		theta /= segments;
+
+		if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {
+
+			theta = - theta;
+
+		}
+
+		for ( i = 1; i <= segments; i ++ ) {
+
+			// twist a little...
+			normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
+			binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
+
+		}
+
+	}
+
+}
+
+export { TubeBufferGeometry };

+ 15 - 281
src/geometries/TubeGeometry.js

@@ -1,25 +1,17 @@
 import { Geometry } from '../core/Geometry';
 import { Geometry } from '../core/Geometry';
-import { _Math } from '../math/Math';
-import { Vector3 } from '../math/Vector3';
-import { Matrix4 } from '../math/Matrix4';
-import { Face3 } from '../core/Face3';
-import { Vector2 } from '../math/Vector2';
+import { TubeBufferGeometry } from './TubeBufferGeometry';
 
 
 /**
 /**
+ * @author oosmoxiecode / https://github.com/oosmoxiecode
  * @author WestLangley / https://github.com/WestLangley
  * @author WestLangley / https://github.com/WestLangley
  * @author zz85 / https://github.com/zz85
  * @author zz85 / https://github.com/zz85
  * @author miningold / https://github.com/miningold
  * @author miningold / https://github.com/miningold
  * @author jonobr1 / https://github.com/jonobr1
  * @author jonobr1 / https://github.com/jonobr1
  *
  *
- * Modified from the TorusKnotGeometry by @oosmoxiecode
- *
- * Creates a tube which extrudes along a 3d spline
- *
- * Uses parallel transport frames as described in
- * http://www.cs.indiana.edu/pub/techreports/TR425.pdf
+ * Creates a tube which extrudes along a 3d spline.
  */
  */
 
 
-function TubeGeometry( path, segments, radius, radialSegments, closed, taper ) {
+function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) {
 
 
 	Geometry.call( this );
 	Geometry.call( this );
 
 
@@ -27,289 +19,31 @@ function TubeGeometry( path, segments, radius, radialSegments, closed, taper ) {
 
 
 	this.parameters = {
 	this.parameters = {
 		path: path,
 		path: path,
-		segments: segments,
+		tubularSegments: tubularSegments,
 		radius: radius,
 		radius: radius,
 		radialSegments: radialSegments,
 		radialSegments: radialSegments,
-		closed: closed,
-		taper: taper
+		closed: closed
 	};
 	};
 
 
-	segments = segments || 64;
-	radius = radius || 1;
-	radialSegments = radialSegments || 8;
-	closed = closed || false;
-	taper = taper || TubeGeometry.NoTaper;
-
-	var grid = [];
-
-	var scope = this,
-
-		tangent,
-		normal,
-		binormal,
-
-		numpoints = segments + 1,
-
-		u, v, r,
-
-		cx, cy,
-		pos, pos2 = new Vector3(),
-		i, j,
-		ip, jp,
-		a, b, c, d,
-		uva, uvb, uvc, uvd;
-
-	var frames = new TubeGeometry.FrenetFrames( path, segments, closed ),
-		tangents = frames.tangents,
-		normals = frames.normals,
-		binormals = frames.binormals;
-
-	// proxy internals
-	this.tangents = tangents;
-	this.normals = normals;
-	this.binormals = binormals;
-
-	function vert( x, y, z ) {
-
-		return scope.vertices.push( new Vector3( x, y, z ) ) - 1;
-
-	}
-
-	// construct the grid
-
-	for ( i = 0; i < numpoints; i ++ ) {
-
-		grid[ i ] = [];
-
-		u = i / ( numpoints - 1 );
-
-		pos = path.getPointAt( u );
-
-		tangent = tangents[ i ];
-		normal = normals[ i ];
-		binormal = binormals[ i ];
-
-		r = radius * taper( u );
-
-		for ( j = 0; j < radialSegments; j ++ ) {
-
-			v = j / radialSegments * 2 * Math.PI;
-
-			cx = - r * Math.cos( v ); // TODO: Hack: Negating it so it faces outside.
-			cy = r * Math.sin( v );
-
-			pos2.copy( pos );
-			pos2.x += cx * normal.x + cy * binormal.x;
-			pos2.y += cx * normal.y + cy * binormal.y;
-			pos2.z += cx * normal.z + cy * binormal.z;
-
-			grid[ i ][ j ] = vert( pos2.x, pos2.y, pos2.z );
-
-		}
+	if( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );
 
 
-	}
+	var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );
 
 
+	// expose internals
 
 
-	// construct the mesh
-
-	for ( i = 0; i < segments; i ++ ) {
-
-		for ( j = 0; j < radialSegments; j ++ ) {
-
-			ip = ( closed ) ? ( i + 1 ) % segments : i + 1;
-			jp = ( j + 1 ) % radialSegments;
-
-			a = grid[ i ][ j ];		// *** NOT NECESSARILY PLANAR ! ***
-			b = grid[ ip ][ j ];
-			c = grid[ ip ][ jp ];
-			d = grid[ i ][ jp ];
-
-			uva = new Vector2( i / segments, j / radialSegments );
-			uvb = new Vector2( ( i + 1 ) / segments, j / radialSegments );
-			uvc = new Vector2( ( i + 1 ) / segments, ( j + 1 ) / radialSegments );
-			uvd = new Vector2( i / segments, ( j + 1 ) / radialSegments );
-
-			this.faces.push( new Face3( a, b, d ) );
-			this.faceVertexUvs[ 0 ].push( [ uva, uvb, uvd ] );
-
-			this.faces.push( new Face3( b, c, d ) );
-			this.faceVertexUvs[ 0 ].push( [ uvb.clone(), uvc, uvd.clone() ] );
-
-		}
+	this.tangents = bufferGeometry.tangents;
+	this.normals = bufferGeometry.normals;
+	this.binormals = bufferGeometry.binormals;
 
 
-	}
+	// create geometry
 
 
-	this.computeFaceNormals();
-	this.computeVertexNormals();
+	this.fromBufferGeometry( bufferGeometry );
+	this.mergeVertices();
 
 
 }
 }
 
 
 TubeGeometry.prototype = Object.create( Geometry.prototype );
 TubeGeometry.prototype = Object.create( Geometry.prototype );
 TubeGeometry.prototype.constructor = TubeGeometry;
 TubeGeometry.prototype.constructor = TubeGeometry;
 
 
-TubeGeometry.NoTaper = function ( u ) {
-
-	return 1;
-
-};
-
-TubeGeometry.SinusoidalTaper = function ( u ) {
-
-	return Math.sin( Math.PI * u );
-
-};
-
-// For computing of Frenet frames, exposing the tangents, normals and binormals the spline
-TubeGeometry.FrenetFrames = function ( path, segments, closed ) {
-
-	var	normal = new Vector3(),
-
-		tangents = [],
-		normals = [],
-		binormals = [],
-
-		vec = new Vector3(),
-		mat = new Matrix4(),
-
-		numpoints = segments + 1,
-		theta,
-		smallest,
-
-		tx, ty, tz,
-		i, u;
-
-
-	// expose internals
-	this.tangents = tangents;
-	this.normals = normals;
-	this.binormals = binormals;
-
-	// compute the tangent vectors for each segment on the path
-
-	for ( i = 0; i < numpoints; i ++ ) {
-
-		u = i / ( numpoints - 1 );
-
-		tangents[ i ] = path.getTangentAt( u );
-		tangents[ i ].normalize();
-
-	}
-
-	initialNormal3();
-
-	/*
-	function initialNormal1(lastBinormal) {
-		// fixed start binormal. Has dangers of 0 vectors
-		normals[ 0 ] = new THREE.Vector3();
-		binormals[ 0 ] = new THREE.Vector3();
-		if (lastBinormal===undefined) lastBinormal = new THREE.Vector3( 0, 0, 1 );
-		normals[ 0 ].crossVectors( lastBinormal, tangents[ 0 ] ).normalize();
-		binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize();
-	}
-
-	function initialNormal2() {
-
-		// This uses the Frenet-Serret formula for deriving binormal
-		var t2 = path.getTangentAt( epsilon );
-
-		normals[ 0 ] = new THREE.Vector3().subVectors( t2, tangents[ 0 ] ).normalize();
-		binormals[ 0 ] = new THREE.Vector3().crossVectors( tangents[ 0 ], normals[ 0 ] );
-
-		normals[ 0 ].crossVectors( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent
-		binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] ).normalize();
-
-	}
-	*/
-
-	function initialNormal3() {
-
-		// select an initial normal vector perpendicular to the first tangent vector,
-		// and in the direction of the smallest tangent xyz component
-
-		normals[ 0 ] = new Vector3();
-		binormals[ 0 ] = new Vector3();
-		smallest = Number.MAX_VALUE;
-		tx = Math.abs( tangents[ 0 ].x );
-		ty = Math.abs( tangents[ 0 ].y );
-		tz = Math.abs( tangents[ 0 ].z );
-
-		if ( tx <= smallest ) {
-
-			smallest = tx;
-			normal.set( 1, 0, 0 );
-
-		}
-
-		if ( ty <= smallest ) {
-
-			smallest = ty;
-			normal.set( 0, 1, 0 );
-
-		}
-
-		if ( tz <= smallest ) {
-
-			normal.set( 0, 0, 1 );
-
-		}
-
-		vec.crossVectors( tangents[ 0 ], normal ).normalize();
-
-		normals[ 0 ].crossVectors( tangents[ 0 ], vec );
-		binormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );
-
-	}
-
-
-	// compute the slowly-varying normal and binormal vectors for each segment on the path
-
-	for ( i = 1; i < numpoints; i ++ ) {
-
-		normals[ i ] = normals[ i - 1 ].clone();
-
-		binormals[ i ] = binormals[ i - 1 ].clone();
-
-		vec.crossVectors( tangents[ i - 1 ], tangents[ i ] );
-
-		if ( vec.length() > Number.EPSILON ) {
-
-			vec.normalize();
-
-			theta = Math.acos( _Math.clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors
-
-			normals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );
-
-		}
-
-		binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
-
-	}
-
-
-	// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same
-
-	if ( closed ) {
-
-		theta = Math.acos( _Math.clamp( normals[ 0 ].dot( normals[ numpoints - 1 ] ), - 1, 1 ) );
-		theta /= ( numpoints - 1 );
-
-		if ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ numpoints - 1 ] ) ) > 0 ) {
-
-			theta = - theta;
-
-		}
-
-		for ( i = 1; i < numpoints; i ++ ) {
-
-			// twist a little...
-			normals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );
-			binormals[ i ].crossVectors( tangents[ i ], normals[ i ] );
-
-		}
-
-	}
-
-};
-
 
 
 export { TubeGeometry };
 export { TubeGeometry };