webgl_geometry_extrude_splines.html 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329
  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <title>three.js webgl - geometry - spline extrusion</title>
  5. <meta charset="utf-8">
  6. <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  7. <style>
  8. body {
  9. font-family: Monospace;
  10. background-color: #f0f0f0;
  11. margin: 0px;
  12. overflow: hidden;
  13. }
  14. </style>
  15. </head>
  16. <body>
  17. <script src="../build/three.js"></script>
  18. <script src="js/controls/OrbitControls.js"></script>
  19. <!-- where curves formulas are defined -->
  20. <script src="js/CurveExtras.js"></script>
  21. <script src="js/libs/stats.min.js"></script>
  22. <script>
  23. var container, stats;
  24. var camera, scene, renderer, splineCamera, cameraHelper, cameraEye;
  25. var text, plane;
  26. var targetRotation = 0;
  27. var targetRotationOnMouseDown = 0;
  28. var mouseX = 0;
  29. var mouseXOnMouseDown = 0;
  30. var windowHalfX = window.innerWidth / 2;
  31. var windowHalfY = window.innerHeight / 2;
  32. var binormal = new THREE.Vector3();
  33. var normal = new THREE.Vector3();
  34. var pipeSpline = new THREE.CatmullRomCurve3( [
  35. new THREE.Vector3( 0, 10, -10 ), new THREE.Vector3( 10, 0, -10 ),
  36. new THREE.Vector3( 20, 0, 0 ), new THREE.Vector3( 30, 0, 10 ),
  37. new THREE.Vector3( 30, 0, 20 ), new THREE.Vector3( 20, 0, 30 ),
  38. new THREE.Vector3( 10, 0, 30 ), new THREE.Vector3( 0, 0, 30 ),
  39. new THREE.Vector3( -10, 10, 30 ), new THREE.Vector3( -10, 20, 30 ),
  40. new THREE.Vector3( 0, 30, 30 ), new THREE.Vector3( 10, 30, 30 ),
  41. new THREE.Vector3( 20, 30, 15 ), new THREE.Vector3( 10, 30, 10 ),
  42. new THREE.Vector3( 0, 30, 10 ), new THREE.Vector3( -10, 20, 10 ),
  43. new THREE.Vector3( -10, 10, 10 ), new THREE.Vector3( 0, 0, 10 ),
  44. new THREE.Vector3( 10, -10, 10 ), new THREE.Vector3( 20, -15, 10 ),
  45. new THREE.Vector3( 30, -15, 10 ), new THREE.Vector3( 40, -15, 10 ),
  46. new THREE.Vector3( 50, -15, 10 ), new THREE.Vector3( 60, 0, 10 ),
  47. new THREE.Vector3( 70, 0, 0 ), new THREE.Vector3( 80, 0, 0 ),
  48. new THREE.Vector3( 90, 0, 0 ), new THREE.Vector3( 100, 0, 0 )
  49. ] );
  50. var sampleClosedSpline = new THREE.CatmullRomCurve3( [
  51. new THREE.Vector3( 0, -40, -40 ),
  52. new THREE.Vector3( 0, 40, -40 ),
  53. new THREE.Vector3( 0, 140, -40 ),
  54. new THREE.Vector3( 0, 40, 40 ),
  55. new THREE.Vector3( 0, -40, 40 )
  56. ] );
  57. sampleClosedSpline.type = 'catmullrom';
  58. sampleClosedSpline.closed = true;
  59. // Keep a dictionary of Curve instances
  60. var splines = {
  61. GrannyKnot: new THREE.Curves.GrannyKnot(),
  62. HeartCurve: new THREE.Curves.HeartCurve( 3.5 ),
  63. VivianiCurve: new THREE.Curves.VivianiCurve( 70 ),
  64. KnotCurve: new THREE.Curves.KnotCurve(),
  65. HelixCurve: new THREE.Curves.HelixCurve(),
  66. TrefoilKnot: new THREE.Curves.TrefoilKnot(),
  67. TorusKnot: new THREE.Curves.TorusKnot( 20 ),
  68. CinquefoilKnot: new THREE.Curves.CinquefoilKnot( 20 ),
  69. TrefoilPolynomialKnot: new THREE.Curves.TrefoilPolynomialKnot( 14 ),
  70. FigureEightPolynomialKnot: new THREE.Curves.FigureEightPolynomialKnot(),
  71. DecoratedTorusKnot4a: new THREE.Curves.DecoratedTorusKnot4a(),
  72. DecoratedTorusKnot4b: new THREE.Curves.DecoratedTorusKnot4b(),
  73. DecoratedTorusKnot5a: new THREE.Curves.DecoratedTorusKnot5a(),
  74. DecoratedTorusKnot5c: new THREE.Curves.DecoratedTorusKnot5c(),
  75. PipeSpline: pipeSpline,
  76. SampleClosedSpline: sampleClosedSpline
  77. };
  78. extrudePath = new THREE.Curves.TrefoilKnot();
  79. var dropdown = '<select id="dropdown" onchange="addTube(this.value)">';
  80. var s;
  81. for ( s in splines ) {
  82. dropdown += '<option value="' + s + '"';
  83. dropdown += '>' + s + '</option>';
  84. }
  85. dropdown += '</select>';
  86. var closed2 = true;
  87. var parent;
  88. var tube, tubeMesh;
  89. var animation = false, lookAhead = false;
  90. var scale;
  91. var showCameraHelper = false;
  92. function addTube() {
  93. var value = document.getElementById( 'dropdown' ).value;
  94. var segments = parseInt( document.getElementById( 'segments' ).value );
  95. closed2 = document.getElementById( 'closed' ).checked;
  96. var radiusSegments = parseInt( document.getElementById( 'radiusSegments' ).value );
  97. if ( tubeMesh !== undefined ) parent.remove( tubeMesh );
  98. extrudePath = splines[ value ];
  99. tube = new THREE.TubeBufferGeometry( extrudePath, segments, 2, radiusSegments, closed2 );
  100. addGeometry( tube, 0xff00ff );
  101. setScale();
  102. }
  103. function setScale() {
  104. scale = parseInt( document.getElementById( 'scale' ).value );
  105. tubeMesh.scale.set( scale, scale, scale );
  106. }
  107. function addGeometry( geometry, color ) {
  108. // 3d shape
  109. tubeMesh = THREE.SceneUtils.createMultiMaterialObject( geometry, [
  110. new THREE.MeshLambertMaterial( {
  111. color: color
  112. } ),
  113. new THREE.MeshBasicMaterial( {
  114. color: 0x000000,
  115. opacity: 0.3,
  116. wireframe: true,
  117. transparent: true
  118. } ) ] );
  119. parent.add( tubeMesh );
  120. }
  121. function animateCamera( toggle ) {
  122. if ( toggle === true ) {
  123. animation = animation === false;
  124. document.getElementById( 'animation' ).value = 'Camera Spline Animation View: ' + ( animation ? 'ON' : 'OFF' );
  125. }
  126. lookAhead = document.getElementById( 'lookAhead' ).checked;
  127. showCameraHelper = document.getElementById( 'cameraHelper' ).checked;
  128. cameraHelper.visible = showCameraHelper;
  129. cameraEye.visible = showCameraHelper;
  130. }
  131. init();
  132. animate();
  133. function init() {
  134. container = document.createElement( 'div' );
  135. document.body.appendChild( container );
  136. var info = document.createElement( 'div' );
  137. info.style.position = 'absolute';
  138. info.style.top = '10px';
  139. info.style.width = '100%';
  140. info.style.textAlign = 'center';
  141. info.innerHTML = 'Spline Extrusion Examples by <a href="http://www.lab4games.net/zz85/blog">zz85</a><br/>Select spline:';
  142. info.innerHTML += dropdown;
  143. 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>';
  144. info.innerHTML += '<br/>Extrusion Segments: <select onchange="addTube()" id="segments"><option>50</option><option selected>100</option><option>200</option><option>400</option></select>';
  145. 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>';
  146. info.innerHTML += '<br/>Closed:<input id="closed" onchange="addTube()" type="checkbox" checked />';
  147. 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()" />';
  148. container.appendChild( info );
  149. //
  150. camera = new THREE.PerspectiveCamera( 50, window.innerWidth / window.innerHeight, 0.01, 10000 );
  151. camera.position.set( 0, 50, 500 );
  152. scene = new THREE.Scene();
  153. var light = new THREE.DirectionalLight( 0xffffff );
  154. light.position.set( 0, 0, 1 );
  155. scene.add( light );
  156. parent = new THREE.Object3D();
  157. scene.add( parent );
  158. splineCamera = new THREE.PerspectiveCamera( 84, window.innerWidth / window.innerHeight, 0.01, 1000 );
  159. parent.add( splineCamera );
  160. cameraHelper = new THREE.CameraHelper( splineCamera );
  161. scene.add( cameraHelper );
  162. addTube();
  163. // debug camera
  164. cameraEye = new THREE.Mesh( new THREE.SphereGeometry( 5 ), new THREE.MeshBasicMaterial( { color: 0xdddddd } ) );
  165. parent.add( cameraEye );
  166. cameraHelper.visible = showCameraHelper;
  167. cameraEye.visible = showCameraHelper;
  168. //
  169. renderer = new THREE.WebGLRenderer( { antialias: true } );
  170. renderer.setClearColor( 0xf0f0f0 );
  171. renderer.setPixelRatio( window.devicePixelRatio );
  172. renderer.setSize( window.innerWidth, window.innerHeight );
  173. container.appendChild( renderer.domElement );
  174. stats = new Stats();
  175. container.appendChild( stats.dom );
  176. //
  177. controls = new THREE.OrbitControls( camera, renderer.domElement );
  178. //
  179. window.addEventListener( 'resize', onWindowResize, false );
  180. }
  181. function onWindowResize() {
  182. windowHalfX = window.innerWidth / 2;
  183. windowHalfY = window.innerHeight / 2;
  184. camera.aspect = window.innerWidth / window.innerHeight;
  185. camera.updateProjectionMatrix();
  186. renderer.setSize( window.innerWidth, window.innerHeight );
  187. }
  188. //
  189. function animate() {
  190. requestAnimationFrame( animate );
  191. render();
  192. stats.update();
  193. }
  194. function render() {
  195. // Try Animate Camera Along Spline
  196. var time = Date.now();
  197. var looptime = 20 * 1000;
  198. var t = ( time % looptime ) / looptime;
  199. var pos = tube.parameters.path.getPointAt( t );
  200. pos.multiplyScalar( scale );
  201. // interpolation
  202. var segments = tube.tangents.length;
  203. var pickt = t * segments;
  204. var pick = Math.floor( pickt );
  205. var pickNext = ( pick + 1 ) % segments;
  206. binormal.subVectors( tube.binormals[ pickNext ], tube.binormals[ pick ] );
  207. binormal.multiplyScalar( pickt - pick ).add( tube.binormals[ pick ] );
  208. var dir = tube.parameters.path.getTangentAt( t );
  209. var offset = 15;
  210. normal.copy( binormal ).cross( dir );
  211. // We move on a offset on its binormal
  212. pos.add( normal.clone().multiplyScalar( offset ) );
  213. splineCamera.position.copy( pos );
  214. cameraEye.position.copy( pos );
  215. // Using arclength for stablization in look ahead.
  216. var lookAt = tube.parameters.path.getPointAt( ( t + 30 / tube.parameters.path.getLength() ) % 1 ).multiplyScalar( scale );
  217. // Camera Orientation 2 - up orientation via normal
  218. if ( !lookAhead ) lookAt.copy( pos ).add( dir );
  219. splineCamera.matrix.lookAt(splineCamera.position, lookAt, normal);
  220. splineCamera.rotation.setFromRotationMatrix( splineCamera.matrix, splineCamera.rotation.order );
  221. cameraHelper.update();
  222. renderer.render( scene, animation === true ? splineCamera : camera );
  223. }
  224. </script>
  225. </body>
  226. </html>