BoxGeometry.js 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import { BufferGeometry } from '../core/BufferGeometry.js';
  2. import { Float32BufferAttribute } from '../core/BufferAttribute.js';
  3. import { Vector3 } from '../math/Vector3.js';
  4. /**
  5. * A geometry class for a rectangular cuboid with a given width, height, and depth.
  6. * On creation, the cuboid is centred on the origin, with each edge parallel to one
  7. * of the axes.
  8. *
  9. * ```js
  10. * const geometry = new THREE.BoxGeometry( 1, 1, 1 );
  11. * const material = new THREE.MeshBasicMaterial( { color: 0x00ff00 } );
  12. * const cube = new THREE.Mesh( geometry, material );
  13. * scene.add( cube );
  14. * ```
  15. *
  16. * @augments BufferGeometry
  17. * @demo scenes/geometry-browser.html#BoxGeometry
  18. */
  19. class BoxGeometry extends BufferGeometry {
  20. /**
  21. * Constructs a new box geometry.
  22. *
  23. * @param {number} [width=1] - The width. That is, the length of the edges parallel to the X axis.
  24. * @param {number} [height=1] - The height. That is, the length of the edges parallel to the Y axis.
  25. * @param {number} [depth=1] - The depth. That is, the length of the edges parallel to the Z axis.
  26. * @param {number} [widthSegments=1] - Number of segmented rectangular faces along the width of the sides.
  27. * @param {number} [heightSegments=1] - Number of segmented rectangular faces along the height of the sides.
  28. * @param {number} [depthSegments=1] - Number of segmented rectangular faces along the depth of the sides.
  29. */
  30. constructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {
  31. super();
  32. this.type = 'BoxGeometry';
  33. /**
  34. * Holds the constructor parameters that have been
  35. * used to generate the geometry. Any modification
  36. * after instantiation does not change the geometry.
  37. *
  38. * @type {Object}
  39. */
  40. this.parameters = {
  41. width: width,
  42. height: height,
  43. depth: depth,
  44. widthSegments: widthSegments,
  45. heightSegments: heightSegments,
  46. depthSegments: depthSegments
  47. };
  48. const scope = this;
  49. // segments
  50. widthSegments = Math.floor( widthSegments );
  51. heightSegments = Math.floor( heightSegments );
  52. depthSegments = Math.floor( depthSegments );
  53. // buffers
  54. const indices = [];
  55. const vertices = [];
  56. const normals = [];
  57. const uvs = [];
  58. // helper variables
  59. let numberOfVertices = 0;
  60. let groupStart = 0;
  61. // build each side of the box geometry
  62. buildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px
  63. buildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx
  64. buildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py
  65. buildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny
  66. buildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz
  67. buildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz
  68. // build geometry
  69. this.setIndex( indices );
  70. this.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );
  71. this.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );
  72. this.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );
  73. function buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {
  74. const segmentWidth = width / gridX;
  75. const segmentHeight = height / gridY;
  76. const widthHalf = width / 2;
  77. const heightHalf = height / 2;
  78. const depthHalf = depth / 2;
  79. const gridX1 = gridX + 1;
  80. const gridY1 = gridY + 1;
  81. let vertexCounter = 0;
  82. let groupCount = 0;
  83. const vector = new Vector3();
  84. // generate vertices, normals and uvs
  85. for ( let iy = 0; iy < gridY1; iy ++ ) {
  86. const y = iy * segmentHeight - heightHalf;
  87. for ( let ix = 0; ix < gridX1; ix ++ ) {
  88. const x = ix * segmentWidth - widthHalf;
  89. // set values to correct vector component
  90. vector[ u ] = x * udir;
  91. vector[ v ] = y * vdir;
  92. vector[ w ] = depthHalf;
  93. // now apply vector to vertex buffer
  94. vertices.push( vector.x, vector.y, vector.z );
  95. // set values to correct vector component
  96. vector[ u ] = 0;
  97. vector[ v ] = 0;
  98. vector[ w ] = depth > 0 ? 1 : - 1;
  99. // now apply vector to normal buffer
  100. normals.push( vector.x, vector.y, vector.z );
  101. // uvs
  102. uvs.push( ix / gridX );
  103. uvs.push( 1 - ( iy / gridY ) );
  104. // counters
  105. vertexCounter += 1;
  106. }
  107. }
  108. // indices
  109. // 1. you need three indices to draw a single face
  110. // 2. a single segment consists of two faces
  111. // 3. so we need to generate six (2*3) indices per segment
  112. for ( let iy = 0; iy < gridY; iy ++ ) {
  113. for ( let ix = 0; ix < gridX; ix ++ ) {
  114. const a = numberOfVertices + ix + gridX1 * iy;
  115. const b = numberOfVertices + ix + gridX1 * ( iy + 1 );
  116. const c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );
  117. const d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;
  118. // faces
  119. indices.push( a, b, d );
  120. indices.push( b, c, d );
  121. // increase counter
  122. groupCount += 6;
  123. }
  124. }
  125. // add a group to the geometry. this will ensure multi material support
  126. scope.addGroup( groupStart, groupCount, materialIndex );
  127. // calculate new start value for groups
  128. groupStart += groupCount;
  129. // update total number of vertices
  130. numberOfVertices += vertexCounter;
  131. }
  132. }
  133. copy( source ) {
  134. super.copy( source );
  135. this.parameters = Object.assign( {}, source.parameters );
  136. return this;
  137. }
  138. /**
  139. * Factory method for creating an instance of this class from the given
  140. * JSON object.
  141. *
  142. * @param {Object} data - A JSON object representing the serialized geometry.
  143. * @return {BoxGeometry} A new instance.
  144. */
  145. static fromJSON( data ) {
  146. return new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments );
  147. }
  148. }
  149. export { BoxGeometry };
粤ICP备19079148号