polygonBuilder.ts 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. import { Scene } from "../../scene";
  2. import { Vector3, Vector2, Vector4 } from "../../Maths/math.vector";
  3. import { Color4 } from '../../Maths/math.color';
  4. import { Mesh, _CreationDataStorage } from "../mesh";
  5. import { VertexData } from "../mesh.vertexData";
  6. import { PolygonMeshBuilder } from "../polygonMesh";
  7. import { FloatArray, IndicesArray, Nullable } from "../../types";
  8. import { VertexBuffer } from "../../Meshes/buffer";
  9. import { EngineStore } from '../../Engines/engineStore';
  10. declare var earcut: any;
  11. VertexData.CreatePolygon = function(polygon: Mesh, sideOrientation: number, fUV?: Vector4[], fColors?: Color4[], frontUVs?: Vector4, backUVs?: Vector4, wrp?: boolean) {
  12. var faceUV: Vector4[] = fUV || new Array<Vector4>(3);
  13. var faceColors = fColors;
  14. var colors = [];
  15. var wrap: boolean = wrp || false;
  16. // default face colors and UV if undefined
  17. for (var f = 0; f < 3; f++) {
  18. if (faceUV[f] === undefined) {
  19. faceUV[f] = new Vector4(0, 0, 1, 1);
  20. }
  21. if (faceColors && faceColors[f] === undefined) {
  22. faceColors[f] = new Color4(1, 1, 1, 1);
  23. }
  24. }
  25. var positions = <FloatArray>polygon.getVerticesData(VertexBuffer.PositionKind);
  26. var normals = <FloatArray>polygon.getVerticesData(VertexBuffer.NormalKind);
  27. var uvs = <FloatArray>polygon.getVerticesData(VertexBuffer.UVKind);
  28. var indices = <IndicesArray>polygon.getIndices();
  29. var startIndex = positions.length / 9;
  30. var disp = 0;
  31. var distX = 0;
  32. var distZ = 0;
  33. var dist = 0;
  34. var totalLen = 0;
  35. var cumulate = [0];
  36. if (wrap) {
  37. for (var idx = startIndex; idx < positions.length / 3; idx += 4) {
  38. distX = positions[3 * (idx + 2)] - positions[3 * idx];
  39. distZ = positions[3 * (idx + 2) + 2] - positions[3 * idx + 2];
  40. dist = Math.sqrt(distX * distX + distZ * distZ);
  41. totalLen += dist;
  42. cumulate.push(totalLen);
  43. }
  44. }
  45. // set face colours and textures
  46. var idx: number = 0;
  47. var face: number = 0;
  48. for (var index = 0; index < normals.length; index += 3) {
  49. //Edge Face no. 1
  50. if (Math.abs(normals[index + 1]) < 0.001) {
  51. face = 1;
  52. }
  53. //Top Face no. 0
  54. if (Math.abs(normals[index + 1] - 1) < 0.001) {
  55. face = 0;
  56. }
  57. //Bottom Face no. 2
  58. if (Math.abs(normals[index + 1] + 1) < 0.001) {
  59. face = 2;
  60. }
  61. idx = index / 3;
  62. if (face === 1) {
  63. disp = idx - startIndex;
  64. if (disp % 4 < 1.5) {
  65. if (wrap) {
  66. uvs[2 * idx] = faceUV[face].x + (faceUV[face].z - faceUV[face].x) * cumulate[Math.floor(disp / 4)] / totalLen;
  67. }
  68. else {
  69. uvs[2 * idx] = faceUV[face].x;
  70. }
  71. }
  72. else {
  73. if (wrap) {
  74. uvs[2 * idx] = faceUV[face].x + (faceUV[face].z - faceUV[face].x) * cumulate[Math.floor(disp / 4) + 1] / totalLen;
  75. }
  76. else {
  77. uvs[2 * idx] = faceUV[face].z;
  78. }
  79. }
  80. if (disp % 2 === 0) {
  81. uvs[2 * idx + 1] = faceUV[face].w;
  82. }
  83. else {
  84. uvs[2 * idx + 1] = faceUV[face].y;
  85. }
  86. }
  87. else {
  88. uvs[2 * idx] = (1 - uvs[2 * idx]) * faceUV[face].x + uvs[2 * idx] * faceUV[face].z;
  89. uvs[2 * idx + 1] = (1 - uvs[2 * idx + 1]) * faceUV[face].y + uvs[2 * idx + 1] * faceUV[face].w;
  90. }
  91. if (faceColors) {
  92. colors.push(faceColors[face].r, faceColors[face].g, faceColors[face].b, faceColors[face].a);
  93. }
  94. }
  95. // sides
  96. VertexData._ComputeSides(sideOrientation, positions, indices, normals, uvs, frontUVs, backUVs);
  97. // Result
  98. var vertexData = new VertexData();
  99. vertexData.indices = indices;
  100. vertexData.positions = positions;
  101. vertexData.normals = normals;
  102. vertexData.uvs = uvs;
  103. if (faceColors) {
  104. var totalColors = (sideOrientation === VertexData.DOUBLESIDE) ? colors.concat(colors) : colors;
  105. vertexData.colors = totalColors;
  106. }
  107. return vertexData;
  108. };
  109. Mesh.CreatePolygon = (name: string, shape: Vector3[], scene: Scene, holes?: Vector3[][], updatable?: boolean, sideOrientation?: number, earcutInjection = earcut): Mesh => {
  110. var options = {
  111. shape: shape,
  112. holes: holes,
  113. updatable: updatable,
  114. sideOrientation: sideOrientation
  115. };
  116. return PolygonBuilder.CreatePolygon(name, options, scene, earcutInjection);
  117. };
  118. Mesh.ExtrudePolygon = (name: string, shape: Vector3[], depth: number, scene: Scene, holes?: Vector3[][], updatable?: boolean, sideOrientation?: number, earcutInjection = earcut): Mesh => {
  119. var options = {
  120. shape: shape,
  121. holes: holes,
  122. depth: depth,
  123. updatable: updatable,
  124. sideOrientation: sideOrientation
  125. };
  126. return PolygonBuilder.ExtrudePolygon(name, options, scene, earcutInjection);
  127. };
  128. /**
  129. * Class containing static functions to help procedurally build meshes
  130. */
  131. export class PolygonBuilder {
  132. /**
  133. * Creates a polygon mesh
  134. * The polygon's shape will depend on the input parameters and is constructed parallel to a ground mesh
  135. * * The parameter `shape` is a required array of successive Vector3 representing the corners of the polygon in th XoZ plane, that is y = 0 for all vectors
  136. * * You can set the mesh side orientation with the values : Mesh.FRONTSIDE (default), Mesh.BACKSIDE or Mesh.DOUBLESIDE
  137. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  138. * * 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)
  139. * * Remember you can only change the shape positions, not their number when updating a polygon
  140. * @param name defines the name of the mesh
  141. * @param options defines the options used to create the mesh
  142. * @param scene defines the hosting scene
  143. * @param earcutInjection can be used to inject your own earcut reference
  144. * @returns the polygon mesh
  145. */
  146. public static CreatePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, wrap?: boolean}, scene: Nullable<Scene> = null, earcutInjection = earcut): Mesh {
  147. options.sideOrientation = Mesh._GetDefaultSideOrientation(options.sideOrientation);
  148. var shape = options.shape;
  149. var holes = options.holes || [];
  150. var depth = options.depth || 0;
  151. var contours: Array<Vector2> = [];
  152. var hole: Array<Vector2> = [];
  153. for (var i = 0; i < shape.length; i++) {
  154. contours[i] = new Vector2(shape[i].x, shape[i].z);
  155. }
  156. var epsilon = 0.00000001;
  157. if (contours[0].equalsWithEpsilon(contours[contours.length - 1], epsilon)) {
  158. contours.pop();
  159. }
  160. var polygonTriangulation = new PolygonMeshBuilder(name, contours, scene || EngineStore.LastCreatedScene!, earcutInjection);
  161. for (var hNb = 0; hNb < holes.length; hNb++) {
  162. hole = [];
  163. for (var hPoint = 0; hPoint < holes[hNb].length; hPoint++) {
  164. hole.push(new Vector2(holes[hNb][hPoint].x, holes[hNb][hPoint].z));
  165. }
  166. polygonTriangulation.addHole(hole);
  167. }
  168. var polygon = polygonTriangulation.build(options.updatable, depth);
  169. polygon._originalBuilderSideOrientation = options.sideOrientation;
  170. var vertexData = VertexData.CreatePolygon(polygon, options.sideOrientation, options.faceUV, options.faceColors, options.frontUVs, options.backUVs, options.wrap);
  171. vertexData.applyToMesh(polygon, options.updatable);
  172. return polygon;
  173. }
  174. /**
  175. * Creates an extruded polygon mesh, with depth in the Y direction.
  176. * * You can set different colors and different images to the top, bottom and extruded side by using the parameters `faceColors` (an array of 3 Color3 elements) and `faceUV` (an array of 3 Vector4 elements)
  177. * @see https://doc.babylonjs.com/how_to/createbox_per_face_textures_and_colors
  178. * @param name defines the name of the mesh
  179. * @param options defines the options used to create the mesh
  180. * @param scene defines the hosting scene
  181. * @param earcutInjection can be used to inject your own earcut reference
  182. * @returns the polygon mesh
  183. */
  184. public static ExtrudePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, wrap?: boolean }, scene: Nullable<Scene> = null, earcutInjection = earcut): Mesh {
  185. return PolygonBuilder.CreatePolygon(name, options, scene, earcutInjection);
  186. }
  187. }