TubeGeometry.js 4.8 KB

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