TubeGeometry.js 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /**
  2. * @author oosmoxiecode / https://github.com/oosmoxiecode
  3. * @author WestLangley / https://github.com/WestLangley
  4. * @author zz85 / https://github.com/zz85
  5. * @author miningold / https://github.com/miningold
  6. * @author jonobr1 / https://github.com/jonobr1
  7. *
  8. * Creates a tube which extrudes along a 3d spline.
  9. */
  10. import { Geometry } from '../core/Geometry';
  11. function TubeGeometry( path, tubularSegments, radius, radialSegments, closed, taper ) {
  12. Geometry.call( this );
  13. this.type = 'TubeGeometry';
  14. this.parameters = {
  15. path: path,
  16. tubularSegments: tubularSegments,
  17. radius: radius,
  18. radialSegments: radialSegments,
  19. closed: closed
  20. };
  21. if ( taper !== undefined ) console.warn( 'THREE.TubeGeometry: taper has been removed.' );
  22. var bufferGeometry = new TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed );
  23. // expose internals
  24. this.tangents = bufferGeometry.tangents;
  25. this.normals = bufferGeometry.normals;
  26. this.binormals = bufferGeometry.binormals;
  27. // create geometry
  28. this.fromBufferGeometry( bufferGeometry );
  29. this.mergeVertices();
  30. }
  31. TubeGeometry.prototype = Object.create( Geometry.prototype );
  32. TubeGeometry.prototype.constructor = TubeGeometry;
  33. /**
  34. * @author Mugen87 / https://github.com/Mugen87
  35. */
  36. import { Float32BufferAttribute, Uint16BufferAttribute, Uint32BufferAttribute } from '../core/BufferAttribute';
  37. import { BufferGeometry } from '../core/BufferGeometry';
  38. import { Vector2 } from '../math/Vector2';
  39. import { Vector3 } from '../math/Vector3';
  40. function TubeBufferGeometry( path, tubularSegments, radius, radialSegments, closed ) {
  41. BufferGeometry.call( this );
  42. this.type = 'TubeBufferGeometry';
  43. this.parameters = {
  44. path: path,
  45. tubularSegments: tubularSegments,
  46. radius: radius,
  47. radialSegments: radialSegments,
  48. closed: closed
  49. };
  50. tubularSegments = tubularSegments || 64;
  51. radius = radius || 1;
  52. radialSegments = radialSegments || 8;
  53. closed = closed || false;
  54. var frames = path.computeFrenetFrames( tubularSegments, closed );
  55. // expose internals
  56. this.tangents = frames.tangents;
  57. this.normals = frames.normals;
  58. this.binormals = frames.binormals;
  59. // helper variables
  60. var vertex = new Vector3();
  61. var normal = new Vector3();
  62. var uv = new Vector2();
  63. var i, j;
  64. // buffer
  65. var vertices = [];
  66. var normals = [];
  67. var uvs = [];
  68. var indices = [];
  69. // create buffer data
  70. generateBufferData();
  71. // build geometry
  72. this.setIndex( new ( vertices.length > 65535 ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 ) );
  73. this.addAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  74. this.addAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  75. this.addAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  76. // functions
  77. function generateBufferData() {
  78. for ( i = 0; i < tubularSegments; i ++ ) {
  79. generateSegment( i );
  80. }
  81. // if the geometry is not closed, generate the last row of vertices and normals
  82. // at the regular position on the given path
  83. //
  84. // if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)
  85. generateSegment( ( closed === false ) ? tubularSegments : 0 );
  86. // uvs are generated in a separate function.
  87. // this makes it easy compute correct values for closed geometries
  88. generateUVs();
  89. // finally create faces
  90. generateIndices();
  91. }
  92. function generateSegment( i ) {
  93. // we use getPointAt to sample evenly distributed points from the given path
  94. var P = path.getPointAt( i / tubularSegments );
  95. // retrieve corresponding normal and binormal
  96. var N = frames.normals[ i ];
  97. var B = frames.binormals[ i ];
  98. // generate normals and vertices for the current segment
  99. for ( j = 0; j <= radialSegments; j ++ ) {
  100. var v = j / radialSegments * Math.PI * 2;
  101. var sin = Math.sin( v );
  102. var cos = - Math.cos( v );
  103. // normal
  104. normal.x = ( cos * N.x + sin * B.x );
  105. normal.y = ( cos * N.y + sin * B.y );
  106. normal.z = ( cos * N.z + sin * B.z );
  107. normal.normalize();
  108. normals.push( normal.x, normal.y, normal.z );
  109. // vertex
  110. vertex.x = P.x + radius * normal.x;
  111. vertex.y = P.y + radius * normal.y;
  112. vertex.z = P.z + radius * normal.z;
  113. vertices.push( vertex.x, vertex.y, vertex.z );
  114. }
  115. }
  116. function generateIndices() {
  117. for ( j = 1; j <= tubularSegments; j ++ ) {
  118. for ( i = 1; i <= radialSegments; i ++ ) {
  119. var a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );
  120. var b = ( radialSegments + 1 ) * j + ( i - 1 );
  121. var c = ( radialSegments + 1 ) * j + i;
  122. var d = ( radialSegments + 1 ) * ( j - 1 ) + i;
  123. // faces
  124. indices.push( a, b, d );
  125. indices.push( b, c, d );
  126. }
  127. }
  128. }
  129. function generateUVs() {
  130. for ( i = 0; i <= tubularSegments; i ++ ) {
  131. for ( j = 0; j <= radialSegments; j ++ ) {
  132. uv.x = i / tubularSegments;
  133. uv.y = j / radialSegments;
  134. uvs.push( uv.x, uv.y );
  135. }
  136. }
  137. }
  138. }
  139. TubeBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
  140. TubeBufferGeometry.prototype.constructor = TubeBufferGeometry;
  141. export { TubeGeometry, TubeBufferGeometry };