topical media & game development

talk show tell print

mobile-query-three-plugins-rollercoster-examples-webgl-geometry-extrude-splines.htm / htm



  
  <!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>
    
      <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/helpers/CameraHelper.js"></script>
  
      <!-- where curves formulas are defined -->
      <script src="js/CurveExtras.js"></script>
  
      <script src="js/Stats.js"></script>
  
      <script>
      var container, stats;
  
      var camera, scene, renderer, splineCamera, cameraHelper, cameraEye;
  
      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;
  
      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([
        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),
      ]);
  
      // Keep a diction of Curve instances
      var splines = {
        GrannyKnot: new THREE.Curves.GrannyKnot(),
        HeartCurve: new THREE.Curves.HeartCurve(3.5),
        VivianiCurve: new THREE.Curves.VivianiCurve(70),
        KnotCurve: new THREE.Curves.KnotCurve(),
        HelixCurve: new THREE.Curves.HelixCurve(),
        TrefoilKnot: new THREE.Curves.TrefoilKnot(),
        TorusKnot: new THREE.Curves.TorusKnot(20),
        CinquefoilKnot: new THREE.Curves.CinquefoilKnot(20),
        TrefoilPolynomialKnot: new THREE.Curves.TrefoilPolynomialKnot(14),
        FigureEightPolynomialKnot: new THREE.Curves.FigureEightPolynomialKnot(),
        DecoratedTorusKnot4a: new THREE.Curves.DecoratedTorusKnot4a(),
        DecoratedTorusKnot4b: new THREE.Curves.DecoratedTorusKnot4b(),
        DecoratedTorusKnot5a: new THREE.Curves.DecoratedTorusKnot5a(),
        DecoratedTorusKnot5c: new THREE.Curves.DecoratedTorusKnot5c(),
        PipeSpline: pipeSpline,
        SampleClosedSpline: sampleClosedSpline
      };
  
      extrudePath = new THREE.Curves.TrefoilKnot();
  
      var dropdown = '<select id="dropdown" onchange="addTube(this.value)">';
  
      var s;
      for ( s in splines ) {
        dropdown += '<option value="' + s + '"';
        dropdown += '>' + s + '</option>';
      }
  
      dropdown += '</select>';
  
      var closed2 = true;
      var debug = true;
      var parent;
      var tube, tubeMesh;
      var animation = false, lookAhead = false;
      var scale;
      var showCameraHelper = false;
  
      function addTube() {
  
        var value = document.getElementById('dropdown').value;
        
        var segments = parseInt(document.getElementById('segments').value);
        closed2 = document.getElementById('closed').checked;
        debug = document.getElementById('debug').checked;
  
        var radiusSegments = parseInt(document.getElementById('radiusSegments').value);
  
        console.log('adding tube', value, closed2, debug, radiusSegments);
        if (tubeMesh) parent.remove(tubeMesh);
  
        extrudePath = splines[value];
        
        tube = new THREE.TubeGeometry(extrudePath, segments, 2, radiusSegments, closed2, debug);
  
        addGeometry(tube, 0xff00ff);
        setScale();
      
      }
  
      function setScale() {
  
        scale = parseInt(document.getElementById('scale').value);
        tubeMesh.scale.set(scale, scale, scale);
  
      }
  
      function addGeometry(geometry, color) {
  
          // 3d shape
          tubeMesh = THREE.SceneUtils.createMultiMaterialObject(geometry, [
            new THREE.MeshLambertMaterial({
                color: color,
                opacity: (geometry.debug) ? 0.2 : 0.8,
                transparent: true
            }),
           new THREE.MeshBasicMaterial({
              color: 0x000000,
              opacity: 0.5,
              wireframe: true
          })]);
  
          if (geometry.debug) tubeMesh.add(geometry.debug);
  
          //mesh.children[0].doubleSided = true;
          parent.add(tubeMesh);
  
      }
  
      function animateCamera(toggle) {
  
        if (toggle) {
          animation = !animation;
          document.getElementById('animation').value = 'Camera Spline Animation View: ' + (animation? 'ON': 'OFF');
        }
        
        lookAhead = document.getElementById('lookAhead').checked;
  
        showCameraHelper = document.getElementById('cameraHelper').checked;
  
        cameraHelper.children[0].visible = showCameraHelper;
        cameraEye.visible = showCameraHelper;
      }
  
      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 = 'Spline Extrusion Examples by <a href="http://www.lab4games.net/zz85/blog">zz85</a><br/>Select spline:';
  
        info.innerHTML += dropdown;
  
        info.innerHTML += '<br/>Scale: <select id="scale" onchange="setScale()"><option>1</option><option>2</option><option selected>4</option><option>6</option><option>10</option></select>';
        info.innerHTML += '<br/>Extrusion Segments: <select onchange="addTube()" id="segments"><option>50</option><option selected>100</option><option>200</option><option>400</option></select>';
        info.innerHTML += '<br/>Radius Segments: <select id="radiusSegments" onchange="addTube()"><option>1</option><option>2</option><option selected>3</option><option>4</option><option>5</option><option>6</option><option>8</option><option>12</option></select>';
        info.innerHTML += '<br/>Debug normals: <input id="debug" type="checkbox" onchange="addTube()"  /> Closed:<input id="closed" onchange="addTube()" type="checkbox" checked />';
  
        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);
  
        scene = new THREE.Scene();
  
        // 
        camera = new THREE.PerspectiveCamera(50, window.innerWidth / window.innerHeight, 0.01, 1000);
        splineCamera = new THREE.PerspectiveCamera(84, window.innerWidth / window.innerHeight, 0.01, 1000);
        cameraHelper = new THREE.CameraHelper(splineCamera);
  
        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 = 100;
        scene.add(parent);
  
        addTube();
  
        // Debug point
        cameraEye = new THREE.Mesh(new THREE.SphereGeometry(5), new THREE.MeshBasicMaterial({
            color: 0xdddddd
        }));
  
        cameraHelper.children[0].visible = showCameraHelper;
        cameraEye.visible = showCameraHelper;
  
        parent.add(cameraEye);
  
        cameraHelper.scale.multiplyScalar(0.1);
        splineCamera.add(cameraHelper);
        parent.add(splineCamera);
  
        //
        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);
  
        renderer.domElement.addEventListener('mousedown', onDocumentMouseDown, false);
        renderer.domElement.addEventListener('touchstart', onDocumentTouchStart, false);
        renderer.domElement.addEventListener('touchmove', onDocumentTouchMove, false);
  
      }
  
      //
  
      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() {
  
        requestAnimationFrame(animate);
  
        render();
        stats.update();
  
      }
  
      function render() {
  
        // Try Animate Camera Along Spline
        var time = Date.now();
        var looptime = 20 * 1000;
        var t = (time % looptime) / looptime;
  
        var pos = tube.path.getPointAt(t);
        pos.multiplyScalar(scale);
  
        // interpolation
        var segments = tube.tangents.length;
        var pickt = t * segments;
        var pick = Math.floor(pickt);
        var pickNext = (pick + 1) % segments;
  
        binormal.sub(tube.binormals[pickNext], tube.binormals[pick]);
        binormal.multiplyScalar(pickt - pick).addSelf(tube.binormals[pick]);
  
        var dir = tube.path.getTangentAt(t);
  
        var offset = 15;
  
        normal.copy(binormal).crossSelf(dir);
  
        // We move on a offset on its binormal
        pos.addSelf(normal.clone().multiplyScalar(offset));
  
        splineCamera.position = pos;
        cameraEye.position = pos;
  
        // Camera Orientation 1 - default look at
        // splineCamera.lookAt(lookAt);
  
        // Using arclength for stablization in look ahead.
        var lookAt = tube.path.getPointAt((t + 30/tube.path.getLength()) % 1).multiplyScalar(scale);
        
        // Camera Orientation 2 - up orientation via normal
        if (!lookAhead)
        lookAt.copy(pos).addSelf(dir);
        splineCamera.matrix.lookAt(splineCamera.position, lookAt, normal);
        splineCamera.rotation.getRotationFromMatrix(splineCamera.matrix);
  
        cameraHelper.update();
  
        parent.rotation.y += (targetRotation - parent.rotation.y) * 0.05;
  
        if (animation) {
  
          renderer.render(scene, splineCamera);
  
        } else {
  
          renderer.render(scene, camera);
  
        }
  
        
        
      }
          </script>
  
    </body>
  </html>
  


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.