TubeGeometry.js 4.3 KB

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