Source: geometry/SphereGeometry.js

  1. import { Geometry } from './Geometry.js';
  2. import { BufferAttribute } from './BufferAttribute.js';
  3. import { Vector3 } from '../math/Vector3.js';
  4. /**
  5. * A class for generating sphere geometries.
  6. * The geometry is created by sweeping and calculating vertexes around the Y axis (horizontal sweep) and the Z axis (vertical sweep).
  7. * Thus, incomplete spheres (akin to 'sphere slices') can be created through the use of different values of phiStart, phiLength, thetaStart and thetaLength, in order to define the points in which we start (or end) calculating those vertices.
  8. * @constructor
  9. * @memberof zen3d
  10. * @extends zen3d.Geometry
  11. * @param {number} [radius=1] — sphere radius. Default is 1.
  12. * @param {Integer} [widthSegments=8] — number of horizontal segments. Minimum value is 3, and the default is 8.
  13. * @param {Integer} [heightSegments=6] — number of vertical segments. Minimum value is 2, and the default is 6.
  14. * @param {number} [phiStart=0] — specify horizontal starting angle. Default is 0.
  15. * @param {number} [phiLength=Math.PI*2] — specify horizontal sweep angle size. Default is Math.PI * 2.
  16. * @param {number} [thetaStart=0] — specify vertical starting angle. Default is 0.
  17. * @param {number} [thetaLength=Math.PI] — specify vertical sweep angle size. Default is Math.PI.
  18. */
  19. function SphereGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength) {
  20. Geometry.call(this);
  21. this.buildGeometry(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength);
  22. }
  23. SphereGeometry.prototype = Object.assign(Object.create(Geometry.prototype), {
  24. constructor: SphereGeometry,
  25. buildGeometry: function(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength) {
  26. radius = radius || 1;
  27. widthSegments = Math.max(3, Math.floor(widthSegments) || 8);
  28. heightSegments = Math.max(2, Math.floor(heightSegments) || 6);
  29. phiStart = phiStart !== undefined ? phiStart : 0;
  30. phiLength = phiLength !== undefined ? phiLength : Math.PI * 2;
  31. thetaStart = thetaStart !== undefined ? thetaStart : 0;
  32. thetaLength = thetaLength !== undefined ? thetaLength : Math.PI;
  33. var thetaEnd = thetaStart + thetaLength;
  34. var ix, iy;
  35. var index = 0;
  36. var grid = [];
  37. var vertex = new Vector3();
  38. var normal = new Vector3();
  39. // buffers
  40. var indices = [];
  41. var vertices = [];
  42. var normals = [];
  43. var uvs = [];
  44. // generate vertices, normals and uvs
  45. for (iy = 0; iy <= heightSegments; iy++) {
  46. var verticesRow = [];
  47. var v = iy / heightSegments;
  48. for (ix = 0; ix <= widthSegments; ix++) {
  49. var u = ix / widthSegments;
  50. // vertex
  51. vertex.x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
  52. vertex.y = radius * Math.cos(thetaStart + v * thetaLength);
  53. vertex.z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength);
  54. vertices.push(vertex.x, vertex.y, vertex.z);
  55. // normal
  56. normal.set(vertex.x, vertex.y, vertex.z).normalize();
  57. normals.push(normal.x, normal.y, normal.z);
  58. // uv
  59. uvs.push(u, 1 - v);
  60. verticesRow.push(index++);
  61. }
  62. grid.push(verticesRow);
  63. }
  64. // indices
  65. for (iy = 0; iy < heightSegments; iy++) {
  66. for (ix = 0; ix < widthSegments; ix++) {
  67. var a = grid[iy][ix + 1];
  68. var b = grid[iy][ix];
  69. var c = grid[iy + 1][ix];
  70. var d = grid[iy + 1][ix + 1];
  71. if (iy !== 0 || thetaStart > 0) indices.push(a, b, d);
  72. if (iy !== heightSegments - 1 || thetaEnd < Math.PI) indices.push(b, c, d);
  73. }
  74. }
  75. this.setIndex(indices);
  76. this.addAttribute('a_Position', new BufferAttribute(new Float32Array(vertices), 3));
  77. this.addAttribute('a_Normal', new BufferAttribute(new Float32Array(normals), 3));
  78. this.addAttribute('a_Uv', new BufferAttribute(new Float32Array(uvs), 2));
  79. this.computeBoundingBox();
  80. this.computeBoundingSphere();
  81. }
  82. });
  83. export { SphereGeometry };