CylinderGeometry.js 6.6 KB

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