CylinderBufferGeometry.js 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  1. import { BufferGeometry } from '../core/BufferGeometry';
  2. import { Vector3 } from '../math/Vector3';
  3. import { Vector2 } from '../math/Vector2';
  4. import { BufferAttribute } from '../core/BufferAttribute';
  5. /**
  6. * @author Mugen87 / https://github.com/Mugen87
  7. */
  8. function CylinderBufferGeometry( radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength ) {
  9. BufferGeometry.call( this );
  10. this.type = 'CylinderBufferGeometry';
  11. this.parameters = {
  12. radiusTop: radiusTop,
  13. radiusBottom: radiusBottom,
  14. height: height,
  15. radialSegments: radialSegments,
  16. heightSegments: heightSegments,
  17. openEnded: openEnded,
  18. thetaStart: thetaStart,
  19. thetaLength: thetaLength
  20. };
  21. var scope = this;
  22. radiusTop = radiusTop !== undefined ? radiusTop : 20;
  23. radiusBottom = radiusBottom !== undefined ? radiusBottom : 20;
  24. height = height !== undefined ? height : 100;
  25. radialSegments = Math.floor( radialSegments ) || 8;
  26. heightSegments = Math.floor( heightSegments ) || 1;
  27. openEnded = openEnded !== undefined ? openEnded : false;
  28. thetaStart = thetaStart !== undefined ? thetaStart : 0.0;
  29. thetaLength = thetaLength !== undefined ? thetaLength : 2.0 * Math.PI;
  30. // used to calculate buffer length
  31. var nbCap = 0;
  32. if ( openEnded === false ) {
  33. if ( radiusTop > 0 ) nbCap ++;
  34. if ( radiusBottom > 0 ) nbCap ++;
  35. }
  36. var vertexCount = calculateVertexCount();
  37. var indexCount = calculateIndexCount();
  38. // buffers
  39. var indices = new BufferAttribute( new ( indexCount > 65535 ? Uint32Array : Uint16Array )( indexCount ), 1 );
  40. var vertices = new BufferAttribute( new Float32Array( vertexCount * 3 ), 3 );
  41. var normals = new BufferAttribute( new Float32Array( vertexCount * 3 ), 3 );
  42. var uvs = new BufferAttribute( new Float32Array( vertexCount * 2 ), 2 );
  43. // helper variables
  44. var index = 0,
  45. indexOffset = 0,
  46. indexArray = [],
  47. halfHeight = height / 2;
  48. // group variables
  49. var groupStart = 0;
  50. // generate geometry
  51. generateTorso();
  52. if ( openEnded === false ) {
  53. if ( radiusTop > 0 ) generateCap( true );
  54. if ( radiusBottom > 0 ) generateCap( false );
  55. }
  56. // build geometry
  57. this.setIndex( indices );
  58. this.addAttribute( 'position', vertices );
  59. this.addAttribute( 'normal', normals );
  60. this.addAttribute( 'uv', uvs );
  61. // helper functions
  62. function calculateVertexCount() {
  63. var count = ( radialSegments + 1 ) * ( heightSegments + 1 );
  64. if ( openEnded === false ) {
  65. count += ( ( radialSegments + 1 ) * nbCap ) + ( radialSegments * nbCap );
  66. }
  67. return count;
  68. }
  69. function calculateIndexCount() {
  70. var count = radialSegments * heightSegments * 2 * 3;
  71. if ( openEnded === false ) {
  72. count += radialSegments * nbCap * 3;
  73. }
  74. return count;
  75. }
  76. function generateTorso() {
  77. var x, y;
  78. var normal = new Vector3();
  79. var vertex = new Vector3();
  80. var groupCount = 0;
  81. // this will be used to calculate the normal
  82. var slope = ( radiusBottom - radiusTop ) / height;
  83. // generate vertices, normals and uvs
  84. for ( y = 0; y <= heightSegments; y ++ ) {
  85. var indexRow = [];
  86. var v = y / heightSegments;
  87. // calculate the radius of the current row
  88. var radius = v * ( radiusBottom - radiusTop ) + radiusTop;
  89. for ( x = 0; x <= radialSegments; x ++ ) {
  90. var u = x / radialSegments;
  91. var theta = u * thetaLength + thetaStart;
  92. var sinTheta = Math.sin( theta );
  93. var cosTheta = Math.cos( theta );
  94. // vertex
  95. vertex.x = radius * sinTheta;
  96. vertex.y = - v * height + halfHeight;
  97. vertex.z = radius * cosTheta;
  98. vertices.setXYZ( index, vertex.x, vertex.y, vertex.z );
  99. // normal
  100. normal.set( sinTheta, slope, cosTheta ).normalize();
  101. normals.setXYZ( index, normal.x, normal.y, normal.z );
  102. // uv
  103. uvs.setXY( index, u, 1 - v );
  104. // save index of vertex in respective row
  105. indexRow.push( index );
  106. // increase index
  107. index ++;
  108. }
  109. // now save vertices of the row in our index array
  110. indexArray.push( indexRow );
  111. }
  112. // generate indices
  113. for ( x = 0; x < radialSegments; x ++ ) {
  114. for ( y = 0; y < heightSegments; y ++ ) {
  115. // we use the index array to access the correct indices
  116. var i1 = indexArray[ y ][ x ];
  117. var i2 = indexArray[ y + 1 ][ x ];
  118. var i3 = indexArray[ y + 1 ][ x + 1 ];
  119. var i4 = indexArray[ y ][ x + 1 ];
  120. // face one
  121. indices.setX( indexOffset, i1 ); indexOffset ++;
  122. indices.setX( indexOffset, i2 ); indexOffset ++;
  123. indices.setX( indexOffset, i4 ); indexOffset ++;
  124. // face two
  125. indices.setX( indexOffset, i2 ); indexOffset ++;
  126. indices.setX( indexOffset, i3 ); indexOffset ++;
  127. indices.setX( indexOffset, i4 ); indexOffset ++;
  128. // update counters
  129. groupCount += 6;
  130. }
  131. }
  132. // add a group to the geometry. this will ensure multi material support
  133. scope.addGroup( groupStart, groupCount, 0 );
  134. // calculate new start value for groups
  135. groupStart += groupCount;
  136. }
  137. function generateCap( top ) {
  138. var x, centerIndexStart, centerIndexEnd;
  139. var uv = new Vector2();
  140. var vertex = new Vector3();
  141. var groupCount = 0;
  142. var radius = ( top === true ) ? radiusTop : radiusBottom;
  143. var sign = ( top === true ) ? 1 : - 1;
  144. // save the index of the first center vertex
  145. centerIndexStart = index;
  146. // first we generate the center vertex data of the cap.
  147. // because the geometry needs one set of uvs per face,
  148. // we must generate a center vertex per face/segment
  149. for ( x = 1; x <= radialSegments; x ++ ) {
  150. // vertex
  151. vertices.setXYZ( index, 0, halfHeight * sign, 0 );
  152. // normal
  153. normals.setXYZ( index, 0, sign, 0 );
  154. // uv
  155. uv.x = 0.5;
  156. uv.y = 0.5;
  157. uvs.setXY( index, uv.x, uv.y );
  158. // increase index
  159. index ++;
  160. }
  161. // save the index of the last center vertex
  162. centerIndexEnd = index;
  163. // now we generate the surrounding vertices, normals and uvs
  164. for ( x = 0; x <= radialSegments; x ++ ) {
  165. var u = x / radialSegments;
  166. var theta = u * thetaLength + thetaStart;
  167. var cosTheta = Math.cos( theta );
  168. var sinTheta = Math.sin( theta );
  169. // vertex
  170. vertex.x = radius * sinTheta;
  171. vertex.y = halfHeight * sign;
  172. vertex.z = radius * cosTheta;
  173. vertices.setXYZ( index, vertex.x, vertex.y, vertex.z );
  174. // normal
  175. normals.setXYZ( index, 0, sign, 0 );
  176. // uv
  177. uv.x = ( cosTheta * 0.5 ) + 0.5;
  178. uv.y = ( sinTheta * 0.5 * sign ) + 0.5;
  179. uvs.setXY( index, uv.x, uv.y );
  180. // increase index
  181. index ++;
  182. }
  183. // generate indices
  184. for ( x = 0; x < radialSegments; x ++ ) {
  185. var c = centerIndexStart + x;
  186. var i = centerIndexEnd + x;
  187. if ( top === true ) {
  188. // face top
  189. indices.setX( indexOffset, i ); indexOffset ++;
  190. indices.setX( indexOffset, i + 1 ); indexOffset ++;
  191. indices.setX( indexOffset, c ); indexOffset ++;
  192. } else {
  193. // face bottom
  194. indices.setX( indexOffset, i + 1 ); indexOffset ++;
  195. indices.setX( indexOffset, i ); indexOffset ++;
  196. indices.setX( indexOffset, c ); indexOffset ++;
  197. }
  198. // update counters
  199. groupCount += 3;
  200. }
  201. // add a group to the geometry. this will ensure multi material support
  202. scope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );
  203. // calculate new start value for groups
  204. groupStart += groupCount;
  205. }
  206. }
  207. CylinderBufferGeometry.prototype = Object.create( BufferGeometry.prototype );
  208. CylinderBufferGeometry.prototype.constructor = CylinderBufferGeometry;
  209. export { CylinderBufferGeometry };
粤ICP备19079148号