CylinderGeometry.js 6.7 KB

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