Browse Source

Add webgl_geometry_extrude_splines for examples with TubeGeometry, Curve

zz85 13 years ago
parent
commit
f3fbacf43a
2 changed files with 340 additions and 5 deletions
  1. 313 0
      examples/webgl_geometry_extrude_splines.html
  2. 27 5
      src/extras/geometries/TubeGeometry.js

+ 313 - 0
examples/webgl_geometry_extrude_splines.html

@@ -0,0 +1,313 @@
+
+<!doctype html>
+<html lang="en">
+  <head>
+    <title>three.js webgl - geometry - shapes</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="js/Stats.js"></script>
+
+
+    <script>
+
+    // Lets define some curves
+
+    // Formula from http://mathworld.wolfram.com/HeartCurve.html
+    THREE.HeartCurve = THREE.Curve.create(
+
+      function(s) {
+        this.scale = (s === undefined) ? 5 : s ;
+      },
+
+      function(t) {
+          t *= 2 * Math.PI;
+          var tx = 16 * Math.pow(Math.sin(t), 3);
+              ty = 13 * Math.cos(t)
+                - 5 * Math.cos(2 * t)
+                - 2 * Math.cos(3 * t)
+                - Math.cos(4 * t ),
+              tz = 0;
+
+          return new THREE.Vector3(tx, ty, tz).multiplyScalar(this.scale);
+
+      }
+
+    );
+
+
+
+    // Viviani's Curve
+    // http://en.wikipedia.org/wiki/Viviani%27s_curve
+    THREE.VivianiCurve = THREE.Curve.create(
+
+      function(radius) {
+
+          this.radius = radius;
+      },
+
+      function(t) {
+          t = t * 4 * Math.PI; // Normalized to 0..1
+          var a = this.radius / 2;
+          var tx = a * (1 + Math.cos(t)),
+              ty = a * Math.sin(t),
+              tz = 2 * a * Math.sin(t / 2);
+
+          return new THREE.Vector3(tx, ty, tz);
+
+      }
+
+    );
+
+
+    THREE.KnotCurve = THREE.Curve.create(
+
+    function() {
+
+    },
+
+    function(t) {
+        t *= 2 * Math.PI;
+        
+        var R = 10;
+        var s = 50;
+        var tx = s * Math.sin(t),
+            ty = Math.cos(t) * (R + s * Math.cos(t)),
+            tz = Math.sin(t) * (R + s * Math.cos(t));
+        
+        return new THREE.Vector3(tx, ty, tz);
+
+    }
+
+    );
+
+    THREE.HelixCurve = THREE.Curve.create(
+
+    function() {
+
+    },
+
+    function(t) {
+        var a = 30; // radius
+        var b = 150; //height
+        var t2 = 2 * Math.PI * t * b / 30;
+        var tx = Math.cos(t2) * a,
+            ty = Math.sin(t2) * a,
+            tz = b * t;
+
+        return new THREE.Vector3(tx, ty, tz);
+
+    }
+
+    );
+
+    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 = 'Simple procedurally generated 3D shapes example by <a href="http://www.lab4games.net/zz85/blog">zz85</a><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, 50, 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
+          }), new THREE.MeshBasicMaterial({
+              color: 0x000000,
+              wireframe: true,
+              transparent: true
+          })]);
+
+          if (geometry.debug) mesh.add(geometry.debug);
+          
+          mesh.position.set(x, y, z - 75);
+          mesh.rotation.set(rx, ry, rz);
+          mesh.scale.set(s, s, s);
+          parent.add(mesh);
+
+      }
+
+      
+      // var extrudePath = 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 extrudePath = new THREE.HeartCurve(3.5);
+      // var extrudePath = new THREE.VivianiCurve(70);
+      // var extrudePath = new THREE.KnotCurve();
+      // extrudePath = new THREE.HelixCurve();
+    
+      // var extrudePath = 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 tube = new THREE.TubeGeometry(5, 100, 10, extrudePath, true);
+      
+
+      addGeometry(tube, 0xff00ff, 0, -80, 0, 0, 0, 0, 3);
+
+
+      //
+      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>

+ 27 - 5
src/extras/geometries/TubeGeometry.js

@@ -7,7 +7,7 @@
  * Creates a tube which extrudes along a 3d spline
  */
 
-THREE.TubeGeometry = function(radius, segments, segmentsRadius, path) {
+THREE.TubeGeometry = function(radius, segments, segmentsRadius, path, debug) {
 
 	THREE.Geometry.call(this);
 
@@ -18,6 +18,8 @@ THREE.TubeGeometry = function(radius, segments, segmentsRadius, path) {
 	this.segmentsRadius = segmentsRadius || 8;
 	this.grid = new Array(this.segments);
 	this.path = path;
+	if (debug) this.debug = new THREE.Object3D();
+
 
 	var tang = new THREE.Vector3();
 
@@ -46,10 +48,27 @@ THREE.TubeGeometry = function(radius, segments, segmentsRadius, path) {
 		tang = this.path.getTangentAt(u);
 
 		if (oldB === undefined) {
-			//arbitrary vector
+			//arbitrary vector method 1
 			//oldB = new THREE.Vector3(Math.random(), Math.random(), Math.random()).normalize();
+
+			// Method 2
 			//oldB = new THREE.Vector3( 0, -1, 0 ); // test to see what happens to a known binormal vector
 
+			// Method 3
+			// t1 = u - epsilon;
+			// if (t1 < 0) t1 = 0;
+			// t1 = this.path.getTangentAt(t1);
+			// t2 = u + epsilon;
+			// if (t2 > 1) t2 = 1;
+			// t2 = this.path.getTangentAt(t2);
+
+			// normal.sub(t2, t1).normalize();
+
+			// binormal.cross(tang, normal);
+			// oldB = binormal;
+
+			// Method 4
+
 			// Find the smallest componenet of the tangent vector (x, y, or z) and set the binormal
 			// equal to the unit vector in that direction ((1, 0, 0), (0, 1, 0), or (0, 0, 1))
 			var smallest = Number.MAX_VALUE;
@@ -88,13 +107,16 @@ THREE.TubeGeometry = function(radius, segments, segmentsRadius, path) {
 		oldB = binormal;
 
 
-		addArrow(parent, pos, normal, radius * 2, 0xffff00);
+		if (this.debug) {
+			this.debug.add(new THREE.ArrowHelper(normal, pos, radius * 2, 0xff0000));
+		}
+		
 
 		for (var j = 0; j < this.segmentsRadius; ++j) {
 
 			v = j / this.segmentsRadius * 2 * Math.PI;
 
-			cx = this.radius * Math.cos(v); // TODO: Hack: Negating it so it faces outside.
+			cx = -this.radius * Math.cos(v); // TODO: Hack: Negating it so it faces outside.
 			cy = this.radius * Math.sin(v);
 
             var pos2 = new THREE.Vector3().copy(pos);
@@ -107,7 +129,7 @@ THREE.TubeGeometry = function(radius, segments, segmentsRadius, path) {
 		}
 	}
 
-	for (var i = 0; i < this.segments - 1; ++i) {
+	for (var i = 0; i < this.segments; ++i) { // segments -1 for non-closed loops, segment - 0 for closed ?
 
 		for (var j = 0; j < this.segmentsRadius; ++j) {