Browse Source

Merge remote-tracking branch 'zz85/extrude_spline_rebasing' into dev

Mr.doob 13 years ago
parent
commit
cbf75917e0

+ 329 - 0
examples/webgl_geometry_extrude_shapes.html

@@ -0,0 +1,329 @@
+
+<!doctype html>
+<html lang="en">
+  <head>
+    <title>three.js webgl - geometry - extrude splines</title>
+    <meta charset="utf-8">
+    <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
+    <style>
+      body {
+        font-family: Monospace;
+        background-color: #f0f0f0;
+        margin: 0px;
+        overflow: hidden;
+      }
+    </style>
+  </head>
+  <body>
+    <canvas id="debug" style="position:absolute; left:100px"></canvas>
+
+    <script src="../build/Three.js"></script>
+    <script src="../src/extras/core/Curve.js"></script>
+    <script src="../src/extras/geometries/TubeGeometry.js"></script>
+    <script src="../src/extras/geometries/ExtrudeGeometry.js"></script>
+    <script src="js/Stats.js"></script>
+
+
+    <script>
+
+      var container, stats;
+
+      var camera, scene, renderer;
+
+      var text, plane;
+
+      var targetRotation = 0;
+      var targetRotationOnMouseDown = 0;
+
+      var mouseX = 0;
+      var mouseXOnMouseDown = 0;
+
+      var windowHalfX = window.innerWidth / 2;
+      var windowHalfY = window.innerHeight / 2;
+
+      init();
+      animate();
+
+      function init() {
+
+        container = document.createElement( 'div' );
+        document.body.appendChild( container );
+
+        var info = document.createElement( 'div' );
+        info.style.position = 'absolute';
+        info.style.top = '10px';
+        info.style.width = '100%';
+        info.style.textAlign = 'center';
+        info.innerHTML = 'Shapes Extrusion via Spline path<br/>Drag to spin';
+        container.appendChild( info );
+
+        scene = new THREE.Scene();
+
+        camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 1, 1000 );
+        camera.position.set( 0, 150, 500 );
+        scene.add( camera );
+
+        var light = new THREE.DirectionalLight( 0xffffff );
+        light.position.set( 0, 0, 1 );
+        scene.add( light );
+
+        parent = new THREE.Object3D();
+        parent.position.y = 50;
+        scene.add( parent );
+
+        function addGeometry( geometry, color, x, y, z, rx, ry, rz, s ) {
+
+          // 3d shape
+
+          var mesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [ new THREE.MeshLambertMaterial( { color: color, opacity: 0.2, transparent: true } ), new THREE.MeshBasicMaterial( { color: 0x000000, wireframe: true,  opacity: 0.3 } ) ] );
+
+
+       
+
+          mesh.position.set( x, y, z - 75 );
+          // mesh.rotation.set( rx, ry, rz );
+          mesh.scale.set( s, s, s );
+
+          if (geometry.debug) mesh.add(geometry.debug);
+
+          parent.add( mesh );
+
+
+
+
+        }
+
+        var extrudeSettings = { amount: 200,  bevelEnabled: true, bevelSegments: 2, steps: 150 }; // bevelSegments: 2, steps: 2 , bevelSegments: 5, bevelSize: 8, bevelThickness:5,
+
+        // var extrudePath = new THREE.Path();
+
+        // extrudePath.moveTo( 0, 0 );
+        // extrudePath.lineTo( 10, 10 );
+        // extrudePath.quadraticCurveTo( 80, 60, 160, 10 );
+        // extrudePath.quadraticCurveTo( 240, -40, 320, 10 );
+
+        
+        extrudeSettings.bevelEnabled = false;
+
+        var extrudeBend = new THREE.SplineCurve3( //Closed
+        [
+
+          new THREE.Vector3( 30, 12, 83),
+          new THREE.Vector3( 40, 20, 67),
+          new THREE.Vector3( 60, 40, 99),
+          new THREE.Vector3( 10, 60, 49),
+          new THREE.Vector3( 25, 80, 40)
+
+          // new THREE.Vector3( 0, 12, 83),
+          // new THREE.Vector3( 0, 20, 67),
+          // new THREE.Vector3( 0, 40, 99),
+          // new THREE.Vector3( 0, 60, 49),
+          // new THREE.Vector3( 0, 80, 40)
+
+          // new THREE.Vector3( 12, 83, 0 ),
+          // new THREE.Vector3( 20, 67, 0 ),
+          // new THREE.Vector3( 40, 99, 0 ),
+          // new THREE.Vector3( 60, 49, 0 ),
+          // new THREE.Vector3( 80, 40, 0 )
+          ]);
+
+            var pipeSpline = new THREE.SplineCurve3([
+        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.ClosedSplineCurve3([
+          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 randomPoints = [];
+
+        for (var i=0; i<10;i++) {
+          randomPoints.push(
+            new THREE.Vector3(Math.random() * 200,Math.random() * 200,Math.random() * 200 )
+            );
+        }
+
+        var randomSpline =  new THREE.SplineCurve3(randomPoints);
+
+        extrudeSettings.extrudePath = randomSpline; // extrudeBend sampleClosedSpline pipeSpline randomSpline
+
+        // Circle
+
+        var circleRadius = 4;
+        var circleShape = new THREE.Shape();
+        circleShape.moveTo( 0, circleRadius );
+        circleShape.quadraticCurveTo( circleRadius, circleRadius, circleRadius, 0 );
+        circleShape.quadraticCurveTo( circleRadius, -circleRadius, 0, -circleRadius );
+        circleShape.quadraticCurveTo( -circleRadius, -circleRadius, -circleRadius, 0 );
+        circleShape.quadraticCurveTo( -circleRadius, circleRadius, 0, circleRadius);
+
+        var rectLength = 12, rectWidth = 4;
+
+        var rectShape = new THREE.Shape();
+        // rectShape.moveTo( 0,0 );
+        // rectShape.lineTo( 0, rectWidth );
+        // rectShape.lineTo( rectLength, rectWidth );
+        // rectShape.lineTo( rectLength, 0 );
+        // rectShape.lineTo( 0, 0 );
+
+        rectShape.moveTo( -rectLength/2, -rectWidth/2 );
+        rectShape.lineTo( -rectLength/2, rectWidth/2 );
+        rectShape.lineTo( rectLength/2, rectWidth/2 );
+        rectShape.lineTo( rectLength/2, -rectLength/2 );
+        rectShape.lineTo( -rectLength/2, -rectLength/2 );
+
+
+        // Smiley
+
+        var smileyShape = new THREE.Shape();
+        smileyShape.moveTo( 80, 40 );
+        smileyShape.arc( 40, 40, 40, 0, Math.PI*2, false );
+
+        var smileyEye1Path = new THREE.Path();
+        smileyEye1Path.moveTo( 35, 20 );
+        smileyEye1Path.arc( 25, 20, 10, 0, Math.PI*2, true );
+        smileyShape.holes.push( smileyEye1Path );
+
+        var smileyEye2Path = new THREE.Path();
+        smileyEye2Path.moveTo( 65, 20 );
+        smileyEye2Path.arc( 55, 20, 10, 0, Math.PI*2, true );
+        smileyShape.holes.push( smileyEye2Path );
+
+        var smileyMouthPath = new THREE.Path();
+        // ugly box mouth
+        // smileyMouthPath.moveTo( 20, 40 );
+        // smileyMouthPath.lineTo( 60, 40 );
+        // smileyMouthPath.lineTo( 60, 60 );
+        // smileyMouthPath.lineTo( 20, 60 );
+        // smileyMouthPath.lineTo( 20, 40 );
+
+        smileyMouthPath.moveTo( 20, 40 );
+        smileyMouthPath.quadraticCurveTo( 40, 60, 60, 40 );
+        smileyMouthPath.bezierCurveTo( 70, 45, 70, 50, 60, 60 );
+        smileyMouthPath.quadraticCurveTo( 40, 80, 20, 60 );
+        smileyMouthPath.quadraticCurveTo( 5, 50, 20, 40 );
+
+        smileyShape.holes.push( smileyMouthPath );
+
+
+
+
+        var circle3d = rectShape.extrude( extrudeSettings ); //circleShape rectShape smileyShape
+        // var circle3d = new THREE.ExtrudeGeometry(circleShape, extrudeBend, extrudeSettings );
+        
+        var tube = new THREE.TubeGeometry(extrudeSettings.extrudePath, 150, 4, 5, false, true);
+        // new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed2, debug);
+      
+
+        addGeometry( circle3d, 0xff1111,  -100,  0, 0,     0, 0, 0, 1 );
+        addGeometry( tube, 0x00ff11,  0,  0, 0,     0, 0, 0, 1 );  
+        console.log(tube);
+
+        //
+
+        renderer = new THREE.WebGLRenderer( { antialias: true } );
+        renderer.setSize( window.innerWidth, window.innerHeight );
+
+        container.appendChild( renderer.domElement );
+
+        stats = new Stats();
+        stats.domElement.style.position = 'absolute';
+        stats.domElement.style.top = '0px';
+        container.appendChild( stats.domElement );
+
+        document.addEventListener( 'mousedown', onDocumentMouseDown, false );
+        document.addEventListener( 'touchstart', onDocumentTouchStart, false );
+        document.addEventListener( 'touchmove', onDocumentTouchMove, false );
+
+      }
+
+      //
+
+      function onDocumentMouseDown( event ) {
+
+        event.preventDefault();
+
+        document.addEventListener( 'mousemove', onDocumentMouseMove, false );
+        document.addEventListener( 'mouseup', onDocumentMouseUp, false );
+        document.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 ) {
+
+        document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
+        document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
+        document.removeEventListener( 'mouseout', onDocumentMouseOut, false );
+
+      }
+
+      function onDocumentMouseOut( event ) {
+
+        document.removeEventListener( 'mousemove', onDocumentMouseMove, false );
+        document.removeEventListener( 'mouseup', onDocumentMouseUp, false );
+        document.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() {
+
+        requestAnimationFrame( animate );
+
+        render();
+        stats.update();
+
+      }
+
+      function render() {
+
+        parent.rotation.y += ( targetRotation - parent.rotation.y ) * 0.05;
+        renderer.render( scene, camera );
+
+      }
+
+    </script>
+
+  </body>
+</html>

+ 8 - 5
examples/webgl_geometry_extrude_splines.html

@@ -362,7 +362,11 @@
     var windowHalfX = window.innerWidth / 2;
     var windowHalfY = window.innerHeight / 2;
 
-    var PipeSpline = new THREE.SplineCurve3([
+    var binormal = new THREE.Vector3();
+    var normal = new THREE.Vector3();
+
+
+    var pipeSpline = new THREE.SplineCurve3([
         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.ClosedSplineCurve3([
@@ -386,7 +390,9 @@
       DecoratedTorusKnot4a: new THREE.Curves.DecoratedTorusKnot4a(),
       DecoratedTorusKnot4b: new THREE.Curves.DecoratedTorusKnot4b(),
       DecoratedTorusKnot5a: new THREE.Curves.DecoratedTorusKnot5a(),
-      DecoratedTorusKnot5c: new THREE.Curves.DecoratedTorusKnot5c()
+      DecoratedTorusKnot5c: new THREE.Curves.DecoratedTorusKnot5c(),
+      PipeSpline: pipeSpline,
+      SampleClosedSpline: sampleClosedSpline
     };
 
 
@@ -649,7 +655,6 @@
       var pick = Math.floor(pickt);
       var pickNext = (pick + 1) % segments;
 
-      var binormal = new THREE.Vector3();
       binormal.sub(tube.binormals[pickNext], tube.binormals[pick]);
       binormal.multiplyScalar(pickt - pick).addSelf(tube.binormals[pick]);
 
@@ -658,12 +663,10 @@
 
       var offset = 15;
 
-      var normal = new THREE.Vector3();
       normal.copy(binormal).crossSelf(dir);
 
       // We move on a offset on its binormal
       pos.addSelf(normal.clone().multiplyScalar(offset));
-      // console.log(t, pos);
 
       splineCamera.position = pos;
       cameraPos.position = pos;

+ 13 - 1
examples/webgl_geometry_shapes.html

@@ -341,6 +341,7 @@
 
 				//splineShape.debug( document.getElementById("debug") );
 
+				// TODO 3d path?
 				var extrudePath = new THREE.Path();
 
 				extrudePath.moveTo( 0, 0 );
@@ -348,8 +349,19 @@
 				extrudePath.quadraticCurveTo( 80, 60, 160, 10 );
 				extrudePath.quadraticCurveTo( 240, -40, 320, 10 );
 
-				extrudeSettings.extrudePath = extrudePath;
+				// QUICK HACK, conversion from 2d to 3d spline
+				// Still broken and need fixes.
+				var apath = new THREE.SplineCurve3();
+				var tmpPoints = extrudePath.getPoints();
+				for (t in tmpPoints) {
+					var tmpPt = tmpPoints[t];
+					apath.points.push(new THREE.Vector3(tmpPt.x, tmpPt.y,0 ));
+				}
+
+
+				extrudeSettings.extrudePath = apath;
 				extrudeSettings.bevelEnabled = false;
+				extrudeSettings.steps = 20;
 
 				var splineShape3d = splineShape.extrude( extrudeSettings );
 				var splinePoints = splineShape.createPointsGeometry( );

+ 5 - 0
src/extras/core/Path.js

@@ -206,6 +206,11 @@ THREE.Path.prototype.getSpacedPoints = function ( divisions, closedPath ) {
 
 THREE.Path.prototype.getPoints = function( divisions, closedPath ) {
 
+	if (this.useSpacedPoints) {
+		console.log('tata');
+		return this.getSpacedPoints( divisions, closedPath );
+	}
+
 	divisions = divisions || 12;
 
 	var points = [];

+ 10 - 0
src/extras/core/Shape.js

@@ -74,6 +74,16 @@ THREE.Shape.prototype.extractAllPoints = function ( divisions ) {
 
 };
 
+THREE.Shape.prototype.extractPoints = function ( divisions ) {
+
+	if (this.useSpacedPoints) {
+		return this.extractAllSpacedPoints(divisions);
+	}
+
+	return this.extractAllPoints(divisions);
+
+};
+
 //
 // THREE.Shape.prototype.extractAllPointsWithBend = function ( divisions, bend ) {
 //

+ 39 - 29
src/extras/geometries/ExtrudeGeometry.js

@@ -8,19 +8,16 @@
  *  size: 			<float>, 	// size of the text
  *  height: 		<float>, 	// thickness to extrude text
  *  curveSegments: 	<int>,		// number of points on the curves
- *  steps: 			<int>,		// number of points for z-side extrusions
- *
- *  font: 			<string>,		// font name
- *  weight: 		<string>,		// font weight (normal, bold)
- *  style: 			<string>,		// font style  (normal, italics)
+ *  steps: 			<int>,		// number of points for z-side extrusions / used for subdividing segements of extrude spline too
+ 	amount: <int>,	// Amount 
  *
  *  bevelEnabled:	<bool>,			// turn on bevel
  *  bevelThickness: <float>, 		// how deep into text bevel goes
  *  bevelSize:		<float>, 		// how far from text outline is bevel
  *  bevelSegments:	<int>, 			// number of bevel layers
  *
- *  extrudePath:	<THREE.CurvePath>	// path to extrude shape along
- *  bendPath:		<THREE.CurvePath> 	// path to bend the geometry around
+ *  extrudePath:	<THREE.CurvePath>	// 2d/3d spline path to extrude shape orthogonality to
+ *  bendPath:		<THREE.CurvePath> 	// 2d path for bend the shape around x/y plane
  *
  *  material:		 <int>	// material index for front and back faces
  *  extrudeMaterial: <int>	// material index for extrusion and beveled faces
@@ -28,6 +25,7 @@
  *  }
   **/
 
+
 THREE.ExtrudeGeometry = function( shapes, options ) {
 
 	if ( typeof( shapes ) === "undefined" ) {
@@ -87,8 +85,6 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 	var extrudePath = options.extrudePath;
 	var extrudePts, extrudeByPath = false;
 
-	var useSpacedPoints = options.useSpacedPoints !== undefined ? options.useSpacedPoints : false;
-
 	var material = options.material;
 	var extrudeMaterial = options.extrudeMaterial;
 
@@ -96,13 +92,28 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 	//shapebb = shape.getBoundingBox();
 
 
+
+	var splineTube, binormal, normal, position2;
 	if ( extrudePath ) {
 
-		extrudePts = extrudePath.getPoints( curveSegments );
-		steps = extrudePts.length;
+		extrudePts = extrudePath.getSpacedPoints( steps );
+
 		extrudeByPath = true;
 		bevelEnabled = false; // bevels not supported for path extrusion
 
+		// SETUP TNB variables
+
+		// Reuse TNB from TubeGeomtry for now.
+		// TODO1 - have a .isClosed in spline?
+		// TODO2 - have have TNBs calculation refactored from TubeGeometry?
+		splineTube = new THREE.TubeGeometry(extrudePath, steps, 1, 1, false, false);
+		
+		// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);
+
+		binormal = new THREE.Vector3();
+		normal = new THREE.Vector3();
+		position2 = new THREE.Vector3();
+
 	}
 
 	// Safeguards if bevels are not enabled
@@ -115,9 +126,6 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 
 	}
 
-
-	// TODO, extrude by path's tangents? also via 3d path?
-
 	// Variables initalization
 
 	var ahole, h, hl; // looping of holes
@@ -132,19 +140,7 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 
 	}
 
-	var shapePoints;
-
-	if ( ! useSpacedPoints ) {
-
-	  	shapePoints = shape.extractAllPoints( curveSegments ); //
-
-	} else {
-
-		// QN - Would it be better to pass useSpacePoints parameter to shape, just like bendpath ?
-
-		shapePoints = shape.extractAllSpacedPoints( curveSegments ) // for points with equal divisions
-
-	}
+	var shapePoints = shape.extractPoints();
 
     var vertices = shapePoints.shape;
 	var holes = shapePoints.holes;
@@ -436,7 +432,14 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 
 		} else {
 
-			v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
+			// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );
+
+			normal.copy(splineTube.normals[0]).multiplyScalar(vert.x);
+			binormal.copy(splineTube.binormals[0]).multiplyScalar(vert.y);
+
+			position2.copy(extrudePts[0]).addSelf(normal).addSelf(binormal);
+			
+			v(position2.x, position2.y, position2.z);
 
 		}
 
@@ -459,7 +462,14 @@ THREE.ExtrudeGeometry.prototype.addShape = function( shape, options ) {
 
 			} else {
 
-				v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
+				// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );
+
+				normal.copy(splineTube.normals[s]).multiplyScalar(vert.x);
+				binormal.copy(splineTube.binormals[s]).multiplyScalar(vert.y);
+
+				position2.copy(extrudePts[s]).addSelf(normal).addSelf(binormal);
+
+				v(position2.x, position2.y, position2.z );
 
 			}
 

+ 46 - 21
src/extras/geometries/TubeGeometry.js

@@ -74,35 +74,60 @@ THREE.TubeGeometry = function( path, segments, radius, segmentsRadius, closed, d
 
 	}
 
+	initialNormal3();
+
+	function initialNormal1() {
+		// fixed start binormal. Has dangers of 0 vectors
+		normals[ 0 ] = new THREE.Vector3();
+		binormals[ 0 ] = new THREE.Vector3();
+		var lastBinormal = new THREE.Vector3( 0, 0, 1 );
+		normals[ 0 ].cross( lastBinormal, tangents[ 0 ] ).normalize();
+		binormals[ 0 ].cross( tangents[ 0 ], normals[ 0 ] ).normalize();
+	}
 
-	// select an initial normal vector perpenicular to the first tangent vector,
-	// and in the direction of the smallest tangent xyz component
+	function initialNormal2() {
 
-	normals[ 0 ] = new THREE.Vector3();
-	binormals[ 0 ] = new THREE.Vector3();
-	smallest = Number.MAX_VALUE;
-	tx = Math.abs( tangents[ 0 ].x );
-	ty = Math.abs( tangents[ 0 ].y );
-	tz = Math.abs( tangents[ 0 ].z );
+		// This uses the Frenet-Serret formula for deriving binormal
+		var t2 = path.getTangentAt( epsilon );
 
-	if ( tx <= smallest ) {
-		smallest = tx;
-		normal.set( 1, 0, 0 );
-	}
+		normals[ 0 ] = new THREE.Vector3().sub( t2, tangents[ 0 ] ).normalize()
+		binormals[ 0 ] = new THREE.Vector3().cross( tangents[ 0 ], normals[ 0 ] );
 
-	if ( ty <= smallest ) {
-		smallest = ty;
-		normal.set( 0, 1, 0 );
-	}
+		normals[ 0 ].cross( binormals[ 0 ], tangents[ 0 ] ).normalize(); // last binormal x tangent
+		binormals[ 0 ].cross( tangents[ 0 ], normals[ 0 ] ).normalize();
 
-	if ( tz <= smallest ) {
-		normal.set( 0, 0, 1 );
 	}
 
-	vec.cross( tangents[ 0 ], normal ).normalize();
+	function initialNormal3() {
+		// select an initial normal vector perpenicular to the first tangent vector,
+		// and in the direction of the smallest tangent xyz component
+
+		normals[ 0 ] = new THREE.Vector3();
+		binormals[ 0 ] = new THREE.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;
+			vec.set( 1, 0, 0 );
+		}
+
+		if ( ty <= smallest ) {
+			smallest = ty;
+			vec.set( 0, 1, 0 );
+		}
+
+		if ( tz <= smallest ) {
+			vec.set( 0, 0, 1 );
+		}
+
+		// vec.cross( tangents[ 0 ], normal ).normalize();
 
-	normals[ 0 ].cross( tangents[ 0 ], vec );
-	binormals[ 0 ].cross( tangents[ 0 ], normals[ 0 ] );
+		normals[ 0 ].cross( tangents[ 0 ], vec );
+		binormals[ 0 ].cross( tangents[ 0 ], normals[ 0 ] );
+	}
 
 
 	// compute the slowly-varying normal and binormal vectors for each segment on the path