sphereBuilder.js 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import { Vector3, Matrix } from "../../Maths/math.vector.js";
  2. import { Mesh } from "../mesh.js";
  3. import { VertexData } from "../mesh.vertexData.js";
  4. import { CompatibilityOptions } from "../../Compat/compatibilityOptions.js";
  5. /**
  6. * Creates the VertexData for an ellipsoid, defaults to a sphere
  7. * @param options an object used to set the following optional parameters for the box, required but can be empty
  8. * * segments sets the number of horizontal strips optional, default 32
  9. * * diameter sets the axes dimensions, diameterX, diameterY and diameterZ to the value of diameter, optional default 1
  10. * * diameterX sets the diameterX (x direction) of the ellipsoid, overwrites the diameterX set by diameter, optional, default diameter
  11. * * diameterY sets the diameterY (y direction) of the ellipsoid, overwrites the diameterY set by diameter, optional, default diameter
  12. * * diameterZ sets the diameterZ (z direction) of the ellipsoid, overwrites the diameterZ set by diameter, optional, default diameter
  13. * * arc a number from 0 to 1, to create an unclosed ellipsoid based on the fraction of the circumference (latitude) given by the arc value, optional, default 1
  14. * * slice a number from 0 to 1, to create an unclosed ellipsoid based on the fraction of the height (latitude) given by the arc value, optional, default 1
  15. * * sideOrientation optional and takes the values : Mesh.FRONTSIDE (default), Mesh.BACKSIDE or Mesh.DOUBLESIDE
  16. * * frontUvs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the front side, optional, default vector4 (0, 0, 1, 1)
  17. * * backUVs only usable when you create a double-sided mesh, used to choose what parts of the texture image to crop and apply on the back side, optional, default vector4 (0, 0, 1, 1)
  18. * @returns the VertexData of the ellipsoid
  19. */
  20. export function CreateSphereVertexData(options) {
  21. const segments = (options.segments || 32) | 0;
  22. const diameterX = options.diameterX || options.diameter || 1;
  23. const diameterY = options.diameterY || options.diameter || 1;
  24. const diameterZ = options.diameterZ || options.diameter || 1;
  25. const arc = options.arc && (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
  26. const slice = options.slice && options.slice <= 0 ? 1.0 : options.slice || 1.0;
  27. const sideOrientation = options.sideOrientation === 0 ? 0 : options.sideOrientation || VertexData.DEFAULTSIDE;
  28. const dedupTopBottomIndices = !!options.dedupTopBottomIndices;
  29. const radius = new Vector3(diameterX / 2, diameterY / 2, diameterZ / 2);
  30. const totalZRotationSteps = 2 + segments;
  31. const totalYRotationSteps = 2 * totalZRotationSteps;
  32. const indices = [];
  33. const positions = [];
  34. const normals = [];
  35. const uvs = [];
  36. for (let zRotationStep = 0; zRotationStep <= totalZRotationSteps; zRotationStep++) {
  37. const normalizedZ = zRotationStep / totalZRotationSteps;
  38. const angleZ = normalizedZ * Math.PI * slice;
  39. for (let yRotationStep = 0; yRotationStep <= totalYRotationSteps; yRotationStep++) {
  40. const normalizedY = yRotationStep / totalYRotationSteps;
  41. const angleY = normalizedY * Math.PI * 2 * arc;
  42. const rotationZ = Matrix.RotationZ(-angleZ);
  43. const rotationY = Matrix.RotationY(angleY);
  44. const afterRotZ = Vector3.TransformCoordinates(Vector3.Up(), rotationZ);
  45. const complete = Vector3.TransformCoordinates(afterRotZ, rotationY);
  46. const vertex = complete.multiply(radius);
  47. const normal = complete.divide(radius).normalize();
  48. positions.push(vertex.x, vertex.y, vertex.z);
  49. normals.push(normal.x, normal.y, normal.z);
  50. uvs.push(normalizedY, CompatibilityOptions.UseOpenGLOrientationForUV ? 1.0 - normalizedZ : normalizedZ);
  51. }
  52. if (zRotationStep > 0) {
  53. const verticesCount = positions.length / 3;
  54. for (let firstIndex = verticesCount - 2 * (totalYRotationSteps + 1); firstIndex + totalYRotationSteps + 2 < verticesCount; firstIndex++) {
  55. if (dedupTopBottomIndices) {
  56. if (zRotationStep > 1) {
  57. indices.push(firstIndex);
  58. indices.push(firstIndex + 1);
  59. indices.push(firstIndex + totalYRotationSteps + 1);
  60. }
  61. if (zRotationStep < totalZRotationSteps || slice < 1.0) {
  62. indices.push(firstIndex + totalYRotationSteps + 1);
  63. indices.push(firstIndex + 1);
  64. indices.push(firstIndex + totalYRotationSteps + 2);
  65. }
  66. }
  67. else {
  68. indices.push(firstIndex);
  69. indices.push(firstIndex + 1);
  70. indices.push(firstIndex + totalYRotationSteps + 1);
  71. indices.push(firstIndex + totalYRotationSteps + 1);
  72. indices.push(firstIndex + 1);
  73. indices.push(firstIndex + totalYRotationSteps + 2);
  74. }
  75. }
  76. }
  77. }
  78. // Sides
  79. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, options.frontUVs, options.backUVs);
  80. // Result
  81. const vertexData = new VertexData();
  82. vertexData.indices = indices;
  83. vertexData.positions = positions;
  84. vertexData.normals = normals;
  85. vertexData.uvs = uvs;
  86. return vertexData;
  87. }
  88. /**
  89. * Creates a sphere mesh
  90. * * The parameter `diameter` sets the diameter size (float) of the sphere (default 1)
  91. * * You can set some different sphere dimensions, for instance to build an ellipsoid, by using the parameters `diameterX`, `diameterY` and `diameterZ` (all by default have the same value of `diameter`)
  92. * * The parameter `segments` sets the sphere number of horizontal stripes (positive integer, default 32)
  93. * * You can create an unclosed sphere with the parameter `arc` (positive float, default 1), valued between 0 and 1, what is the ratio of the circumference (latitude) : 2 x PI x ratio
  94. * * You can create an unclosed sphere on its height with the parameter `slice` (positive float, default1), valued between 0 and 1, what is the height ratio (longitude)
  95. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  96. * * If you create a double-sided mesh, you can choose what parts of the texture image to crop and stick respectively on the front and the back sides with the parameters `frontUVs` and `backUVs` (Vector4). Detail here : https://doc.babylonjs.com/features/featuresDeepDive/mesh/creation/set#side-orientation
  97. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  98. * @param name defines the name of the mesh
  99. * @param options defines the options used to create the mesh
  100. * @param scene defines the hosting scene
  101. * @returns the sphere mesh
  102. * @see https://doc.babylonjs.com/features/featuresDeepDive/mesh/creation/set#sphere
  103. */
  104. export function CreateSphere(name, options = {}, scene = null) {
  105. const sphere = new Mesh(name, scene);
  106. options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);
  107. sphere._originalBuilderSideOrientation = options.sideOrientation;
  108. const vertexData = CreateSphereVertexData(options);
  109. vertexData.applyToMesh(sphere, options.updatable);
  110. return sphere;
  111. }
  112. /**
  113. * Class containing static functions to help procedurally build meshes
  114. * @deprecated use CreateSphere directly
  115. */
  116. export const SphereBuilder = {
  117. // eslint-disable-next-line @typescript-eslint/naming-convention
  118. CreateSphere,
  119. };
  120. VertexData.CreateSphere = CreateSphereVertexData;
  121. Mesh.CreateSphere = (name, segments, diameter, scene, updatable, sideOrientation) => {
  122. const options = {
  123. segments: segments,
  124. diameterX: diameter,
  125. diameterY: diameter,
  126. diameterZ: diameter,
  127. sideOrientation: sideOrientation,
  128. updatable: updatable,
  129. };
  130. return CreateSphere(name, options, scene);
  131. };
  132. //# sourceMappingURL=sphereBuilder.js.map