babylon.meshBuilder.ts 96 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417
  1. module BABYLON {
  2. /**
  3. * Class containing static functions to help procedurally build meshes
  4. */
  5. export class MeshBuilder {
  6. private static updateSideOrientation(orientation?: number): number {
  7. if (orientation == Mesh.DOUBLESIDE) {
  8. return Mesh.DOUBLESIDE;
  9. }
  10. if (orientation === undefined || orientation === null) {
  11. return Mesh.FRONTSIDE;
  12. }
  13. return orientation;
  14. }
  15. /**
  16. * Creates a box mesh
  17. * * The parameter `size` sets the size (float) of each box side (default 1)
  18. * * You can set some different box dimensions by using the parameters `width`, `height` and `depth` (all by default have the same value of `size`)
  19. * * You can set different colors and different images to each box side by using the parameters `faceColors` (an array of 6 Color3 elements) and `faceUV` (an array of 6 Vector4 elements)
  20. * * Please read this tutorial : http://doc.babylonjs.com/tutorials/CreateBox_Per_Face_Textures_And_Colors
  21. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  22. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  23. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  24. * @see http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#box
  25. * @param name defines the name of the mesh
  26. * @param options defines the options used to create the mesh
  27. * @param scene defines the hosting scene
  28. * @returns the box mesh
  29. */
  30. public static CreateBox(name: string, options: { size?: number, width?: number, height?: number, depth?: number, faceUV?: Vector4[], faceColors?: Color4[], sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean }, scene: Nullable<Scene> = null): Mesh {
  31. var box = new Mesh(name, scene);
  32. options.sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  33. box._originalBuilderSideOrientation = options.sideOrientation;
  34. var vertexData = VertexData.CreateBox(options);
  35. vertexData.applyToMesh(box, options.updatable);
  36. return box;
  37. }
  38. /**
  39. * Creates a sphere mesh
  40. * * The parameter `diameter` sets the diameter size (float) of the sphere (default 1)
  41. * * 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`)
  42. * * The parameter `segments` sets the sphere number of horizontal stripes (positive integer, default 32)
  43. * * 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
  44. * * 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)
  45. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  46. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  47. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  48. * @param name defines the name of the mesh
  49. * @param options defines the options used to create the mesh
  50. * @param scene defines the hosting scene
  51. * @returns the sphere mesh
  52. * @see http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#sphere
  53. */
  54. public static CreateSphere(name: string, options: { segments?: number, diameter?: number, diameterX?: number, diameterY?: number, diameterZ?: number, arc?: number, slice?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean }, scene: any): Mesh {
  55. var sphere = new Mesh(name, scene);
  56. options.sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  57. sphere._originalBuilderSideOrientation = options.sideOrientation;
  58. var vertexData = VertexData.CreateSphere(options);
  59. vertexData.applyToMesh(sphere, options.updatable);
  60. return sphere;
  61. }
  62. /**
  63. * Creates a plane polygonal mesh. By default, this is a disc
  64. * * The parameter `radius` sets the radius size (float) of the polygon (default 0.5)
  65. * * The parameter `tessellation` sets the number of polygon sides (positive integer, default 64). So a tessellation valued to 3 will build a triangle, to 4 a square, etc
  66. * * You can create an unclosed polygon with the parameter `arc` (positive float, default 1), valued between 0 and 1, what is the ratio of the circumference : 2 x PI x ratio
  67. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  68. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  69. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  70. * @param name defines the name of the mesh
  71. * @param options defines the options used to create the mesh
  72. * @param scene defines the hosting scene
  73. * @returns the plane polygonal mesh
  74. * @see http://doc.babylonjs.com/how_to/set_shapes#disc-or-regular-polygon
  75. */
  76. public static CreateDisc(name: string, options: { radius?: number, tessellation?: number, arc?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Nullable<Scene> = null): Mesh {
  77. var disc = new Mesh(name, scene);
  78. options.sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  79. disc._originalBuilderSideOrientation = options.sideOrientation;
  80. var vertexData = VertexData.CreateDisc(options);
  81. vertexData.applyToMesh(disc, options.updatable);
  82. return disc;
  83. }
  84. /**
  85. * Creates a sphere based upon an icosahedron with 20 triangular faces which can be subdivided
  86. * * The parameter `radius` sets the radius size (float) of the icosphere (default 1)
  87. * * You can set some different icosphere dimensions, for instance to build an ellipsoid, by using the parameters `radiusX`, `radiusY` and `radiusZ` (all by default have the same value of `radius`)
  88. * * The parameter `subdivisions` sets the number of subdivisions (postive integer, default 4). The more subdivisions, the more faces on the icosphere whatever its size
  89. * * The parameter `flat` (boolean, default true) gives each side its own normals. Set it to false to get a smooth continuous light reflection on the surface
  90. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  91. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  92. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  93. * @param name defines the name of the mesh
  94. * @param options defines the options used to create the mesh
  95. * @param scene defines the hosting scene
  96. * @returns the icosahedron mesh
  97. * @see http://doc.babylonjs.com/how_to/polyhedra_shapes#icosphere
  98. */
  99. public static CreateIcoSphere(name: string, options: { radius?: number, radiusX?: number, radiusY?: number, radiusZ?: number, flat?: boolean, subdivisions?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean }, scene: Scene): Mesh {
  100. var sphere = new Mesh(name, scene);
  101. options.sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  102. sphere._originalBuilderSideOrientation = options.sideOrientation;
  103. var vertexData = VertexData.CreateIcoSphere(options);
  104. vertexData.applyToMesh(sphere, options.updatable);
  105. return sphere;
  106. };
  107. /**
  108. * Creates a ribbon mesh. The ribbon is a parametric shape. It has no predefined shape. Its final shape will depend on the input parameters
  109. * * The parameter `pathArray` is a required array of paths, what are each an array of successive Vector3. The pathArray parameter depicts the ribbon geometry
  110. * * The parameter `closeArray` (boolean, default false) creates a seam between the first and the last paths of the path array
  111. * * The parameter `closePath` (boolean, default false) creates a seam between the first and the last points of each path of the path array
  112. * * The parameter `offset` (positive integer, default : rounded half size of the pathArray length), is taken in account only if the `pathArray` is containing a single path
  113. * * It's the offset to join the points from the same path. Ex : offset = 10 means the point 1 is joined to the point 11
  114. * * The optional parameter `instance` is an instance of an existing Ribbon object to be updated with the passed `pathArray` parameter : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#ribbon
  115. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  116. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  117. * * The optional parameter `invertUV` (boolean, default false) swaps in the geometry the U and V coordinates to apply a texture
  118. * * The parameter `uvs` is an optional flat array of `Vector2` to update/set each ribbon vertex with its own custom UV values instead of the computed ones
  119. * * The parameters `colors` is an optional flat array of `Color4` to set/update each ribbon vertex with its own custom color values
  120. * * Note that if you use the parameters `uvs` or `colors`, the passed arrays must be populated with the right number of elements, it is to say the number of ribbon vertices. Remember that if you set `closePath` to `true`, there's one extra vertex per path in the geometry
  121. * * Moreover, you can use the parameter `color` with `instance` (to update the ribbon), only if you previously used it at creation time
  122. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  123. * @param name defines the name of the mesh
  124. * @param options defines the options used to create the mesh
  125. * @param scene defines the hosting scene
  126. * @returns the ribbon mesh
  127. * @see http://doc.babylonjs.com/tutorials/Ribbon_Tutorial
  128. * @see http://doc.babylonjs.com/tutorials/Parametric_Shapes
  129. */
  130. public static CreateRibbon(name: string, options: { pathArray: Vector3[][], closeArray?: boolean, closePath?: boolean, offset?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean, uvs?: Vector2[], colors?: Color4[] }, scene: Nullable<Scene> = null): Mesh {
  131. var pathArray = options.pathArray;
  132. var closeArray = options.closeArray;
  133. var closePath = options.closePath;
  134. var sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  135. var instance = options.instance;
  136. var updatable = options.updatable;
  137. if (instance) { // existing ribbon instance update
  138. // positionFunction : ribbon case
  139. // only pathArray and sideOrientation parameters are taken into account for positions update
  140. Vector3.FromFloatsToRef(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, Tmp.Vector3[0]); // minimum
  141. Vector3.FromFloatsToRef(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE, Tmp.Vector3[1]);
  142. var positionFunction = (positions: FloatArray) => {
  143. var minlg = pathArray[0].length;
  144. var mesh = (<Mesh>instance);
  145. var i = 0;
  146. var ns = (mesh._originalBuilderSideOrientation === Mesh.DOUBLESIDE) ? 2 : 1;
  147. for (var si = 1; si <= ns; si++) {
  148. for (var p = 0; p < pathArray.length; p++) {
  149. var path = pathArray[p];
  150. var l = path.length;
  151. minlg = (minlg < l) ? minlg : l;
  152. var j = 0;
  153. while (j < minlg) {
  154. positions[i] = path[j].x;
  155. positions[i + 1] = path[j].y;
  156. positions[i + 2] = path[j].z;
  157. if (path[j].x < Tmp.Vector3[0].x) {
  158. Tmp.Vector3[0].x = path[j].x;
  159. }
  160. if (path[j].x > Tmp.Vector3[1].x) {
  161. Tmp.Vector3[1].x = path[j].x;
  162. }
  163. if (path[j].y < Tmp.Vector3[0].y) {
  164. Tmp.Vector3[0].y = path[j].y;
  165. }
  166. if (path[j].y > Tmp.Vector3[1].y) {
  167. Tmp.Vector3[1].y = path[j].y;
  168. }
  169. if (path[j].z < Tmp.Vector3[0].z) {
  170. Tmp.Vector3[0].z = path[j].z;
  171. }
  172. if (path[j].z > Tmp.Vector3[1].z) {
  173. Tmp.Vector3[1].z = path[j].z;
  174. }
  175. j++;
  176. i += 3;
  177. }
  178. if (mesh._creationDataStorage && mesh._creationDataStorage.closePath) {
  179. positions[i] = path[0].x;
  180. positions[i + 1] = path[0].y;
  181. positions[i + 2] = path[0].z;
  182. i += 3;
  183. }
  184. }
  185. }
  186. };
  187. var positions = <FloatArray>instance.getVerticesData(VertexBuffer.PositionKind);
  188. positionFunction(positions);
  189. instance._boundingInfo = new BoundingInfo(Tmp.Vector3[2], Tmp.Vector3[3]);
  190. instance._boundingInfo.update(instance._worldMatrix);
  191. instance.updateVerticesData(VertexBuffer.PositionKind, positions, false, false);
  192. if (options.colors) {
  193. var colors = <FloatArray>instance.getVerticesData(VertexBuffer.ColorKind);
  194. for (var c = 0; c < options.colors.length; c++) {
  195. colors[c * 4] = options.colors[c].r;
  196. colors[c * 4 + 1] = options.colors[c].g;
  197. colors[c * 4 + 2] = options.colors[c].b;
  198. colors[c * 4 + 3] = options.colors[c].a;
  199. }
  200. instance.updateVerticesData(VertexBuffer.ColorKind, colors, false, false);
  201. }
  202. if (options.uvs) {
  203. var uvs = <FloatArray>instance.getVerticesData(VertexBuffer.UVKind);
  204. for (var i = 0; i < options.uvs.length; i++) {
  205. uvs[i * 2] = options.uvs[i].x;
  206. uvs[i * 2 + 1] = options.uvs[i].y;
  207. }
  208. instance.updateVerticesData(VertexBuffer.UVKind, uvs, false, false);
  209. }
  210. if (!instance.areNormalsFrozen || instance.isFacetDataEnabled) {
  211. var indices = instance.getIndices();
  212. var normals = <FloatArray>instance.getVerticesData(VertexBuffer.NormalKind);
  213. var params = instance.isFacetDataEnabled ? instance.getFacetDataParameters() : null;
  214. VertexData.ComputeNormals(positions, indices, normals, params);
  215. if (instance._creationDataStorage && instance._creationDataStorage.closePath) {
  216. var indexFirst: number = 0;
  217. var indexLast: number = 0;
  218. for (var p = 0; p < pathArray.length; p++) {
  219. indexFirst = instance._creationDataStorage!.idx[p] * 3;
  220. if (p + 1 < pathArray.length) {
  221. indexLast = (instance._creationDataStorage!.idx[p + 1] - 1) * 3;
  222. }
  223. else {
  224. indexLast = normals.length - 3;
  225. }
  226. normals[indexFirst] = (normals[indexFirst] + normals[indexLast]) * 0.5;
  227. normals[indexFirst + 1] = (normals[indexFirst + 1] + normals[indexLast + 1]) * 0.5;
  228. normals[indexFirst + 2] = (normals[indexFirst + 2] + normals[indexLast + 2]) * 0.5;
  229. normals[indexLast] = normals[indexFirst];
  230. normals[indexLast + 1] = normals[indexFirst + 1];
  231. normals[indexLast + 2] = normals[indexFirst + 2];
  232. }
  233. }
  234. if (!(instance.areNormalsFrozen)) {
  235. instance.updateVerticesData(VertexBuffer.NormalKind, normals, false, false);
  236. }
  237. }
  238. return instance;
  239. }
  240. else { // new ribbon creation
  241. var ribbon = new Mesh(name, scene);
  242. ribbon._originalBuilderSideOrientation = sideOrientation;
  243. ribbon._creationDataStorage = new _CreationDataStorage();
  244. var vertexData = VertexData.CreateRibbon(options);
  245. if (closePath) {
  246. ribbon._creationDataStorage.idx = (<any>vertexData)._idx;
  247. }
  248. ribbon._creationDataStorage.closePath = closePath;
  249. ribbon._creationDataStorage.closeArray = closeArray;
  250. vertexData.applyToMesh(ribbon, updatable);
  251. return ribbon;
  252. }
  253. }
  254. /**
  255. * Creates a cylinder or a cone mesh
  256. * * The parameter `height` sets the height size (float) of the cylinder/cone (float, default 2).
  257. * * The parameter `diameter` sets the diameter of the top and bottom cap at once (float, default 1).
  258. * * The parameters `diameterTop` and `diameterBottom` overwrite the parameter `diameter` and set respectively the top cap and bottom cap diameter (floats, default 1). The parameter "diameterBottom" can't be zero.
  259. * * The parameter `tessellation` sets the number of cylinder sides (positive integer, default 24). Set it to 3 to get a prism for instance.
  260. * * The parameter `subdivisions` sets the number of rings along the cylinder height (positive integer, default 1).
  261. * * The parameter `hasRings` (boolean, default false) makes the subdivisions independent from each other, so they become different faces.
  262. * * The parameter `enclose` (boolean, default false) adds two extra faces per subdivision to a sliced cylinder to close it around its height axis.
  263. * * The parameter `arc` (float, default 1) is the ratio (max 1) to apply to the circumference to slice the cylinder.
  264. * * You can set different colors and different images to each box side by using the parameters `faceColors` (an array of n Color3 elements) and `faceUV` (an array of n Vector4 elements).
  265. * * The value of n is the number of cylinder faces. If the cylinder has only 1 subdivisions, n equals : top face + cylinder surface + bottom face = 3
  266. * * Now, if the cylinder has 5 independent subdivisions (hasRings = true), n equals : top face + 5 stripe surfaces + bottom face = 2 + 5 = 7
  267. * * Finally, if the cylinder has 5 independent subdivisions and is enclose, n equals : top face + 5 x (stripe surface + 2 closing faces) + bottom face = 2 + 5 * 3 = 17
  268. * * Each array (color or UVs) is always ordered the same way : the first element is the bottom cap, the last element is the top cap. The other elements are each a ring surface.
  269. * * If `enclose` is false, a ring surface is one element.
  270. * * If `enclose` is true, a ring surface is 3 successive elements in the array : the tubular surface, then the two closing faces.
  271. * * Example how to set colors and textures on a sliced cylinder : http://www.html5gamedevs.com/topic/17945-creating-a-closed-slice-of-a-cylinder/#comment-106379
  272. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  273. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  274. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
  275. * @param name defines the name of the mesh
  276. * @param options defines the options used to create the mesh
  277. * @param scene defines the hosting scene
  278. * @returns the cylinder mesh
  279. * @see http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#cylinder-or-cone
  280. */
  281. public static CreateCylinder(name: string, options: { height?: number, diameterTop?: number, diameterBottom?: number, diameter?: number, tessellation?: number, subdivisions?: number, arc?: number, faceColors?: Color4[], faceUV?: Vector4[], updatable?: boolean, hasRings?: boolean, enclose?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: any): Mesh {
  282. var cylinder = new Mesh(name, scene);
  283. options.sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  284. cylinder._originalBuilderSideOrientation = options.sideOrientation;
  285. var vertexData = VertexData.CreateCylinder(options);
  286. vertexData.applyToMesh(cylinder, options.updatable);
  287. return cylinder;
  288. }
  289. /**
  290. * Creates a torus mesh
  291. * * The parameter `diameter` sets the diameter size (float) of the torus (default 1)
  292. * * The parameter `thickness` sets the diameter size of the tube of the torus (float, default 0.5)
  293. * * The parameter `tessellation` sets the number of torus sides (postive integer, default 16)
  294. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  295. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  296. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
  297. * @param name defines the name of the mesh
  298. * @param options defines the options used to create the mesh
  299. * @param scene defines the hosting scene
  300. * @returns the torus mesh
  301. * @see http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#torus
  302. */
  303. public static CreateTorus(name: string, options: { diameter?: number, thickness?: number, tessellation?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: any): Mesh {
  304. var torus = new Mesh(name, scene);
  305. options.sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  306. torus._originalBuilderSideOrientation = options.sideOrientation;
  307. var vertexData = VertexData.CreateTorus(options);
  308. vertexData.applyToMesh(torus, options.updatable);
  309. return torus;
  310. }
  311. /**
  312. * Creates a torus knot mesh
  313. * * The parameter `radius` sets the global radius size (float) of the torus knot (default 2)
  314. * * The parameter `radialSegments` sets the number of sides on each tube segments (positive integer, default 32)
  315. * * The parameter `tubularSegments` sets the number of tubes to decompose the knot into (positive integer, default 32)
  316. * * The parameters `p` and `q` are the number of windings on each axis (positive integers, default 2 and 3)
  317. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  318. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  319. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
  320. * @param name defines the name of the mesh
  321. * @param options defines the options used to create the mesh
  322. * @param scene defines the hosting scene
  323. * @returns the torus knot mesh
  324. * @see http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#torus-knot
  325. */
  326. public static CreateTorusKnot(name: string, options: { radius?: number, tube?: number, radialSegments?: number, tubularSegments?: number, p?: number, q?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: any): Mesh {
  327. var torusKnot = new Mesh(name, scene);
  328. options.sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  329. torusKnot._originalBuilderSideOrientation = options.sideOrientation;
  330. var vertexData = VertexData.CreateTorusKnot(options);
  331. vertexData.applyToMesh(torusKnot, options.updatable);
  332. return torusKnot;
  333. }
  334. /**
  335. * Creates a line system mesh. A line system is a pool of many lines gathered in a single mesh
  336. * * A line system mesh is considered as a parametric shape since it has no predefined original shape. Its shape is determined by the passed array of lines as an input parameter
  337. * * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineSystem to this static function
  338. * * The parameter `lines` is an array of lines, each line being an array of successive Vector3
  339. * * The optional parameter `instance` is an instance of an existing LineSystem object to be updated with the passed `lines` parameter
  340. * * The optional parameter `colors` is an array of line colors, each line colors being an array of successive Color4, one per line point
  341. * * The optional parameter `useVertexAlpha` is to be set to `false` (default `true`) when you don't need the alpha blending (faster)
  342. * * Updating a simple Line mesh, you just need to update every line in the `lines` array : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines
  343. * * When updating an instance, remember that only line point positions can change, not the number of points, neither the number of lines
  344. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  345. * @see http://doc.babylonjs.com/how_to/parametric_shapes#line-system
  346. * @param name defines the name of the new line system
  347. * @param options defines the options used to create the line system
  348. * @param scene defines the hosting scene
  349. * @returns a new line system mesh
  350. */
  351. public static CreateLineSystem(name: string, options: { lines: Vector3[][], updatable?: boolean, instance?: Nullable<LinesMesh>, colors?: Nullable<Color4[][]>, useVertexAlpha?: boolean }, scene: Nullable<Scene>): LinesMesh {
  352. var instance = options.instance;
  353. var lines = options.lines;
  354. var colors = options.colors;
  355. if (instance) { // lines update
  356. var positions = instance.getVerticesData(VertexBuffer.PositionKind)!;
  357. var vertexColor;
  358. var lineColors;
  359. if (colors) {
  360. vertexColor = instance.getVerticesData(VertexBuffer.ColorKind)!;
  361. }
  362. var i = 0;
  363. var c = 0;
  364. for (var l = 0; l < lines.length; l++) {
  365. var points = lines[l];
  366. for (var p = 0; p < points.length; p++) {
  367. positions[i] = points[p].x;
  368. positions[i + 1] = points[p].y;
  369. positions[i + 2] = points[p].z;
  370. if (colors && vertexColor) {
  371. lineColors = colors[l];
  372. vertexColor[c] = lineColors[p].r;
  373. vertexColor[c + 1] = lineColors[p].g;
  374. vertexColor[c + 2] = lineColors[p].b;
  375. vertexColor[c + 3] = lineColors[p].a;
  376. c += 4;
  377. }
  378. i += 3;
  379. }
  380. }
  381. instance.updateVerticesData(VertexBuffer.PositionKind, positions, false, false);
  382. if (colors && vertexColor) {
  383. instance.updateVerticesData(VertexBuffer.ColorKind, vertexColor, false, false)
  384. }
  385. return instance;
  386. }
  387. // line system creation
  388. var useVertexColor = (colors) ? true : false;
  389. var lineSystem = new LinesMesh(name, scene, null, undefined, undefined, useVertexColor, options.useVertexAlpha);
  390. var vertexData = VertexData.CreateLineSystem(options);
  391. vertexData.applyToMesh(lineSystem, options.updatable);
  392. return lineSystem;
  393. }
  394. /**
  395. * Creates a line mesh
  396. * A line mesh is considered as a parametric shape since it has no predefined original shape. Its shape is determined by the passed array of points as an input parameter
  397. * * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineMesh to this static function
  398. * * The parameter `points` is an array successive Vector3
  399. * * The optional parameter `instance` is an instance of an existing LineMesh object to be updated with the passed `points` parameter : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines
  400. * * The optional parameter `colors` is an array of successive Color4, one per line point
  401. * * The optional parameter `useVertexAlpha` is to be set to `false` (default `true`) when you don't need alpha blending (faster)
  402. * * When updating an instance, remember that only point positions can change, not the number of points
  403. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  404. * @see http://doc.babylonjs.com/how_to/parametric_shapes#lines
  405. * @param name defines the name of the new line system
  406. * @param options defines the options used to create the line system
  407. * @param scene defines the hosting scene
  408. * @returns a new line mesh
  409. */
  410. public static CreateLines(name: string, options: { points: Vector3[], updatable?: boolean, instance?: Nullable<LinesMesh>, colors?: Color4[], useVertexAlpha?: boolean }, scene: Nullable<Scene> = null): LinesMesh {
  411. var colors = (options.colors) ? [options.colors] : null;
  412. var lines = MeshBuilder.CreateLineSystem(name, { lines: [options.points], updatable: options.updatable, instance: options.instance, colors: colors, useVertexAlpha: options.useVertexAlpha }, scene);
  413. return lines;
  414. }
  415. /**
  416. * Creates a dashed line mesh
  417. * * A dashed line mesh is considered as a parametric shape since it has no predefined original shape. Its shape is determined by the passed array of points as an input parameter
  418. * * Like every other parametric shape, it is dynamically updatable by passing an existing instance of LineMesh to this static function
  419. * * The parameter `points` is an array successive Vector3
  420. * * The parameter `dashNb` is the intended total number of dashes (positive integer, default 200)
  421. * * The parameter `dashSize` is the size of the dashes relatively the dash number (positive float, default 3)
  422. * * The parameter `gapSize` is the size of the gap between two successive dashes relatively the dash number (positive float, default 1)
  423. * * The optional parameter `instance` is an instance of an existing LineMesh object to be updated with the passed `points` parameter : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#lines-and-dashedlines
  424. * * When updating an instance, remember that only point positions can change, not the number of points
  425. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  426. * @param name defines the name of the mesh
  427. * @param options defines the options used to create the mesh
  428. * @param scene defines the hosting scene
  429. * @returns the dashed line mesh
  430. * @see http://doc.babylonjs.com/how_to/parametric_shapes#dashed-lines
  431. */
  432. public static CreateDashedLines(name: string, options: { points: Vector3[], dashSize?: number, gapSize?: number, dashNb?: number, updatable?: boolean, instance?: LinesMesh }, scene: Nullable<Scene> = null): LinesMesh {
  433. var points = options.points;
  434. var instance = options.instance;
  435. var gapSize = options.gapSize || 1;
  436. var dashSize = options.dashSize || 3;
  437. if (instance) { // dashed lines update
  438. var positionFunction = (positions: FloatArray): void => {
  439. var curvect = Vector3.Zero();
  440. var nbSeg = positions.length / 6;
  441. var lg = 0;
  442. var nb = 0;
  443. var shft = 0;
  444. var dashshft = 0;
  445. var curshft = 0;
  446. var p = 0;
  447. var i = 0;
  448. var j = 0;
  449. for (i = 0; i < points.length - 1; i++) {
  450. points[i + 1].subtractToRef(points[i], curvect);
  451. lg += curvect.length();
  452. }
  453. shft = lg / nbSeg;
  454. let dashSize = instance!._creationDataStorage!.dashSize;
  455. let gapSize = instance!._creationDataStorage!.gapSize;
  456. dashshft = dashSize * shft / (dashSize + gapSize);
  457. for (i = 0; i < points.length - 1; i++) {
  458. points[i + 1].subtractToRef(points[i], curvect);
  459. nb = Math.floor(curvect.length() / shft);
  460. curvect.normalize();
  461. j = 0;
  462. while (j < nb && p < positions.length) {
  463. curshft = shft * j;
  464. positions[p] = points[i].x + curshft * curvect.x;
  465. positions[p + 1] = points[i].y + curshft * curvect.y;
  466. positions[p + 2] = points[i].z + curshft * curvect.z;
  467. positions[p + 3] = points[i].x + (curshft + dashshft) * curvect.x;
  468. positions[p + 4] = points[i].y + (curshft + dashshft) * curvect.y;
  469. positions[p + 5] = points[i].z + (curshft + dashshft) * curvect.z;
  470. p += 6;
  471. j++;
  472. }
  473. }
  474. while (p < positions.length) {
  475. positions[p] = points[i].x;
  476. positions[p + 1] = points[i].y;
  477. positions[p + 2] = points[i].z;
  478. p += 3;
  479. }
  480. };
  481. instance.updateMeshPositions(positionFunction, false);
  482. return instance;
  483. }
  484. // dashed lines creation
  485. var dashedLines = new LinesMesh(name, scene);
  486. var vertexData = VertexData.CreateDashedLines(options);
  487. vertexData.applyToMesh(dashedLines, options.updatable);
  488. dashedLines._creationDataStorage = new _CreationDataStorage();
  489. dashedLines._creationDataStorage.dashSize = dashSize;
  490. dashedLines._creationDataStorage.gapSize = gapSize;
  491. return dashedLines;
  492. }
  493. /**
  494. * Creates an extruded shape mesh. The extrusion is a parametric shape. It has no predefined shape. Its final shape will depend on the input parameters.
  495. * * The parameter `shape` is a required array of successive Vector3. This array depicts the shape to be extruded in its local space : the shape must be designed in the xOy plane and will be extruded along the Z axis.
  496. * * The parameter `path` is a required array of successive Vector3. This is the axis curve the shape is extruded along.
  497. * * The parameter `rotation` (float, default 0 radians) is the angle value to rotate the shape each step (each path point), from the former step (so rotation added each step) along the curve.
  498. * * The parameter `scale` (float, default 1) is the value to scale the shape.
  499. * * The parameter `cap` sets the way the extruded shape is capped. Possible values : BABYLON.Mesh.NO_CAP (default), BABYLON.Mesh.CAP_START, BABYLON.Mesh.CAP_END, BABYLON.Mesh.CAP_ALL
  500. * * The optional parameter `instance` is an instance of an existing ExtrudedShape object to be updated with the passed `shape`, `path`, `scale` or `rotation` parameters : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#extruded-shape
  501. * * Remember you can only change the shape or path point positions, not their number when updating an extruded shape.
  502. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  503. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  504. * * The optional parameter `invertUV` (boolean, default false) swaps in the geometry the U and V coordinates to apply a texture.
  505. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
  506. * @param name defines the name of the mesh
  507. * @param options defines the options used to create the mesh
  508. * @param scene defines the hosting scene
  509. * @returns the extruded shape mesh
  510. * @see http://doc.babylonjs.com/tutorials/Parametric_Shapes
  511. * @see http://doc.babylonjs.com/how_to/parametric_shapes#extruded-shapes
  512. * @see http://doc.babylonjs.com/how_to/parametric_shapes#extruded-shapes
  513. */
  514. public static ExtrudeShape(name: string, options: { shape: Vector3[], path: Vector3[], scale?: number, rotation?: number, cap?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Nullable<Scene> = null): Mesh {
  515. var path = options.path;
  516. var shape = options.shape;
  517. var scale = options.scale || 1;
  518. var rotation = options.rotation || 0;
  519. var cap = (options.cap === 0) ? 0 : options.cap || Mesh.NO_CAP;
  520. var updatable = options.updatable;
  521. var sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  522. var instance = options.instance || null;
  523. var invertUV = options.invertUV || false;
  524. return MeshBuilder._ExtrudeShapeGeneric(name, shape, path, scale, rotation, null, null, false, false, cap, false, scene, updatable ? true : false, sideOrientation, instance, invertUV, options.frontUVs || null, options.backUVs || null);
  525. }
  526. /**
  527. * Creates an custom extruded shape mesh.
  528. * The custom extrusion is a parametric shape. It has no predefined shape. Its final shape will depend on the input parameters.
  529. * * The parameter `shape` is a required array of successive Vector3. This array depicts the shape to be extruded in its local space : the shape must be designed in the xOy plane and will be extruded along the Z axis.
  530. * * The parameter `path` is a required array of successive Vector3. This is the axis curve the shape is extruded along.
  531. * * The parameter `rotationFunction` (JS function) is a custom Javascript function called on each path point. This function is passed the position i of the point in the path and the distance of this point from the begining of the path
  532. * * It must returns a float value that will be the rotation in radians applied to the shape on each path point.
  533. * * The parameter `scaleFunction` (JS function) is a custom Javascript function called on each path point. This function is passed the position i of the point in the path and the distance of this point from the begining of the path
  534. * * It must returns a float value that will be the scale value applied to the shape on each path point
  535. * * The parameter `ribbonClosePath` (boolean, default false) forces the extrusion underlying ribbon to close all the paths in its `pathArray`
  536. * * The parameter `ribbonCloseArray` (boolean, default false) forces the extrusion underlying ribbon to close its `pathArray`
  537. * * The parameter `cap` sets the way the extruded shape is capped. Possible values : BABYLON.Mesh.NO_CAP (default), BABYLON.Mesh.CAP_START, BABYLON.Mesh.CAP_END, BABYLON.Mesh.CAP_ALL
  538. * * The optional parameter `instance` is an instance of an existing ExtrudedShape object to be updated with the passed `shape`, `path`, `scale` or `rotation` parameters : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#extruded-shape
  539. * * Remember you can only change the shape or path point positions, not their number when updating an extruded shape
  540. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  541. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  542. * * The optional parameter `invertUV` (boolean, default false) swaps in the geometry the U and V coordinates to apply a texture
  543. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  544. * @param name defines the name of the mesh
  545. * @param options defines the options used to create the mesh
  546. * @param scene defines the hosting scene
  547. * @returns the custom extruded shape mesh
  548. * @see http://doc.babylonjs.com/how_to/parametric_shapes#custom-extruded-shapes
  549. * @see http://doc.babylonjs.com/tutorials/Parametric_Shapes
  550. * @see http://doc.babylonjs.com/how_to/parametric_shapes#extruded-shapes
  551. */
  552. public static ExtrudeShapeCustom(name: string, options: { shape: Vector3[], path: Vector3[], scaleFunction?: any, rotationFunction?: any, ribbonCloseArray?: boolean, ribbonClosePath?: boolean, cap?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Scene): Mesh {
  553. var path = options.path;
  554. var shape = options.shape;
  555. var scaleFunction = options.scaleFunction || (() => { return 1; });
  556. var rotationFunction = options.rotationFunction || (() => { return 0; });
  557. var ribbonCloseArray = options.ribbonCloseArray || false;
  558. var ribbonClosePath = options.ribbonClosePath || false;
  559. var cap = (options.cap === 0) ? 0 : options.cap || Mesh.NO_CAP;
  560. var updatable = options.updatable;
  561. var sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  562. var instance = options.instance;
  563. var invertUV = options.invertUV || false;
  564. return MeshBuilder._ExtrudeShapeGeneric(name, shape, path, null, null, scaleFunction, rotationFunction, ribbonCloseArray, ribbonClosePath, cap, true, scene, updatable ? true : false, sideOrientation, instance || null, invertUV, options.frontUVs || null, options.backUVs || null);
  565. }
  566. /**
  567. * Creates lathe mesh.
  568. * The lathe is a shape with a symetry axis : a 2D model shape is rotated around this axis to design the lathe
  569. * * The parameter `shape` is a required array of successive Vector3. This array depicts the shape to be rotated in its local space : the shape must be designed in the xOy plane and will be rotated around the Y axis. It's usually a 2D shape, so the Vector3 z coordinates are often set to zero
  570. * * The parameter `radius` (positive float, default 1) is the radius value of the lathe
  571. * * The parameter `tessellation` (positive integer, default 64) is the side number of the lathe
  572. * * The parameter `clip` (positive integer, default 0) is the number of sides to not create without effecting the general shape of the sides
  573. * * The parameter `arc` (positive float, default 1) is the ratio of the lathe. 0.5 builds for instance half a lathe, so an opened shape
  574. * * The parameter `closed` (boolean, default true) opens/closes the lathe circumference. This should be set to false when used with the parameter "arc"
  575. * * The parameter `cap` sets the way the extruded shape is capped. Possible values : BABYLON.Mesh.NO_CAP (default), BABYLON.Mesh.CAP_START, BABYLON.Mesh.CAP_END, BABYLON.Mesh.CAP_ALL
  576. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  577. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  578. * * The optional parameter `invertUV` (boolean, default false) swaps in the geometry the U and V coordinates to apply a texture
  579. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  580. * @param name defines the name of the mesh
  581. * @param options defines the options used to create the mesh
  582. * @param scene defines the hosting scene
  583. * @returns the lathe mesh
  584. * @see http://doc.babylonjs.com/how_to/parametric_shapes#lathe
  585. */
  586. public static CreateLathe(name: string, options: { shape: Vector3[], radius?: number, tessellation?: number, clip?: number, arc?: number, closed?: boolean, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, cap?: number, invertUV?: boolean }, scene: Scene): Mesh {
  587. var arc: number = options.arc ? ((options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc) : 1.0;
  588. var closed: boolean = (options.closed === undefined) ? true : options.closed;
  589. var shape = options.shape;
  590. var radius = options.radius || 1;
  591. var tessellation = options.tessellation || 64;
  592. var clip = options.clip || 0;
  593. var updatable = options.updatable;
  594. var sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  595. var cap = options.cap || Mesh.NO_CAP;
  596. var pi2 = Math.PI * 2;
  597. var paths = new Array();
  598. var invertUV = options.invertUV || false;
  599. var i = 0;
  600. var p = 0;
  601. var step = pi2 / tessellation * arc;
  602. var rotated;
  603. var path = new Array<Vector3>();
  604. for (i = 0; i <= tessellation-clip; i++) {
  605. var path: Vector3[] = [];
  606. if (cap == Mesh.CAP_START || cap == Mesh.CAP_ALL) {
  607. path.push(new Vector3(0, shape[0].y, 0));
  608. path.push(new Vector3(Math.cos(i * step) * shape[0].x * radius, shape[0].y, Math.sin(i * step) * shape[0].x * radius));
  609. }
  610. for (p = 0; p < shape.length; p++) {
  611. rotated = new Vector3(Math.cos(i * step) * shape[p].x * radius, shape[p].y, Math.sin(i * step) * shape[p].x * radius);
  612. path.push(rotated);
  613. }
  614. if (cap == Mesh.CAP_END || cap == Mesh.CAP_ALL) {
  615. path.push(new Vector3(Math.cos(i * step) * shape[shape.length - 1].x * radius, shape[shape.length - 1].y, Math.sin(i * step) * shape[shape.length - 1].x * radius));
  616. path.push(new Vector3(0, shape[shape.length - 1].y, 0));
  617. }
  618. paths.push(path);
  619. }
  620. // lathe ribbon
  621. var lathe = MeshBuilder.CreateRibbon(name, { pathArray: paths, closeArray: closed, sideOrientation: sideOrientation, updatable: updatable, invertUV: invertUV, frontUVs: options.frontUVs, backUVs: options.backUVs }, scene);
  622. return lathe;
  623. }
  624. /**
  625. * Creates a plane mesh
  626. * * The parameter `size` sets the size (float) of both sides of the plane at once (default 1)
  627. * * You can set some different plane dimensions by using the parameters `width` and `height` (both by default have the same value of `size`)
  628. * * The parameter `sourcePlane` is a Plane instance. It builds a mesh plane from a Math plane
  629. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  630. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  631. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  632. * @param name defines the name of the mesh
  633. * @param options defines the options used to create the mesh
  634. * @param scene defines the hosting scene
  635. * @returns the plane mesh
  636. * @see http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#plane
  637. */
  638. public static CreatePlane(name: string, options: { size?: number, width?: number, height?: number, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, updatable?: boolean, sourcePlane?: Plane }, scene: Scene): Mesh {
  639. var plane = new Mesh(name, scene);
  640. options.sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  641. plane._originalBuilderSideOrientation = options.sideOrientation;
  642. var vertexData = VertexData.CreatePlane(options);
  643. vertexData.applyToMesh(plane, options.updatable);
  644. if (options.sourcePlane) {
  645. plane.translate(options.sourcePlane.normal, options.sourcePlane.d);
  646. var product = Math.acos(Vector3.Dot(options.sourcePlane.normal, Axis.Z));
  647. var vectorProduct = Vector3.Cross(Axis.Z, options.sourcePlane.normal);
  648. if (vectorProduct.lengthSquared() > Epsilon) {
  649. plane.rotate(vectorProduct, product);
  650. }
  651. }
  652. return plane;
  653. }
  654. /**
  655. * Creates a ground mesh
  656. * * The parameters `width` and `height` (floats, default 1) set the width and height sizes of the ground
  657. * * The parameter `subdivisions` (positive integer) sets the number of subdivisions per side
  658. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  659. * @param name defines the name of the mesh
  660. * @param options defines the options used to create the mesh
  661. * @param scene defines the hosting scene
  662. * @returns the ground mesh
  663. * @see http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#plane
  664. */
  665. public static CreateGround(name: string, options: { width?: number, height?: number, subdivisions?: number, subdivisionsX?: number, subdivisionsY?: number, updatable?: boolean }, scene: any): Mesh {
  666. var ground = new GroundMesh(name, scene);
  667. ground._setReady(false);
  668. ground._subdivisionsX = options.subdivisionsX || options.subdivisions || 1;
  669. ground._subdivisionsY = options.subdivisionsY || options.subdivisions || 1;
  670. ground._width = options.width || 1;
  671. ground._height = options.height || 1;
  672. ground._maxX = ground._width / 2;
  673. ground._maxZ = ground._height / 2;
  674. ground._minX = -ground._maxX;
  675. ground._minZ = -ground._maxZ;
  676. var vertexData = VertexData.CreateGround(options);
  677. vertexData.applyToMesh(ground, options.updatable);
  678. ground._setReady(true);
  679. return ground;
  680. }
  681. /**
  682. * Creates a tiled ground mesh
  683. * * The parameters `xmin` and `xmax` (floats, default -1 and 1) set the ground minimum and maximum X coordinates
  684. * * The parameters `zmin` and `zmax` (floats, default -1 and 1) set the ground minimum and maximum Z coordinates
  685. * * The parameter `subdivisions` is a javascript object `{w: positive integer, h: positive integer}` (default `{w: 6, h: 6}`). `w` and `h` are the numbers of subdivisions on the ground width and height. Each subdivision is called a tile
  686. * * The parameter `precision` is a javascript object `{w: positive integer, h: positive integer}` (default `{w: 2, h: 2}`). `w` and `h` are the numbers of subdivisions on the ground width and height of each tile
  687. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
  688. * @param name defines the name of the mesh
  689. * @param options defines the options used to create the mesh
  690. * @param scene defines the hosting scene
  691. * @returns the tiled ground mesh
  692. * @see http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#tiled-ground
  693. */
  694. public static CreateTiledGround(name: string, options: { xmin: number, zmin: number, xmax: number, zmax: number, subdivisions?: { w: number; h: number; }, precision?: { w: number; h: number; }, updatable?: boolean }, scene: Scene): Mesh {
  695. var tiledGround = new Mesh(name, scene);
  696. var vertexData = VertexData.CreateTiledGround(options);
  697. vertexData.applyToMesh(tiledGround, options.updatable);
  698. return tiledGround;
  699. }
  700. /**
  701. * Creates a ground mesh from a height map
  702. * * The parameter `url` sets the URL of the height map image resource.
  703. * * The parameters `width` and `height` (positive floats, default 10) set the ground width and height sizes.
  704. * * The parameter `subdivisions` (positive integer, default 1) sets the number of subdivision per side.
  705. * * The parameter `minHeight` (float, default 0) is the minimum altitude on the ground.
  706. * * The parameter `maxHeight` (float, default 1) is the maximum altitude on the ground.
  707. * * The parameter `colorFilter` (optional Color3, default (0.3, 0.59, 0.11) ) is the filter to apply to the image pixel colors to compute the height.
  708. * * The parameter `onReady` is a javascript callback function that will be called once the mesh is just built (the height map download can last some time).
  709. * * The parameter `alphaFilter` will filter any data where the alpha channel is below this value, defaults 0 (all data visible)
  710. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created.
  711. * @param name defines the name of the mesh
  712. * @param url defines the url to the height map
  713. * @param options defines the options used to create the mesh
  714. * @param scene defines the hosting scene
  715. * @returns the ground mesh
  716. * @see http://doc.babylonjs.com/babylon101/height_map
  717. * @see http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#ground-from-a-height-map
  718. */
  719. public static CreateGroundFromHeightMap(name: string, url: string, options: { width?: number, height?: number, subdivisions?: number, minHeight?: number, maxHeight?: number, colorFilter?: Color3, alphaFilter?: number, updatable?: boolean, onReady?: (mesh: GroundMesh) => void }, scene: Scene): GroundMesh {
  720. var width = options.width || 10.0;
  721. var height = options.height || 10.0;
  722. var subdivisions = options.subdivisions || 1 | 0;
  723. var minHeight = options.minHeight || 0.0;
  724. var maxHeight = options.maxHeight || 1.0;
  725. var filter = options.colorFilter || new Color3(0.3, 0.59, 0.11);
  726. var alphaFilter = options.alphaFilter || 0.0;
  727. var updatable = options.updatable;
  728. var onReady = options.onReady;
  729. var ground = new GroundMesh(name, scene);
  730. ground._subdivisionsX = subdivisions;
  731. ground._subdivisionsY = subdivisions;
  732. ground._width = width;
  733. ground._height = height;
  734. ground._maxX = ground._width / 2.0;
  735. ground._maxZ = ground._height / 2.0;
  736. ground._minX = -ground._maxX;
  737. ground._minZ = -ground._maxZ;
  738. ground._setReady(false);
  739. var onload = (img: HTMLImageElement) => {
  740. // Getting height map data
  741. var canvas = document.createElement("canvas");
  742. var context = canvas.getContext("2d");
  743. if (!context) {
  744. throw new Error("Unable to get 2d context for CreateGroundFromHeightMap");
  745. }
  746. if (scene.isDisposed) {
  747. return;
  748. }
  749. var bufferWidth = img.width;
  750. var bufferHeight = img.height;
  751. canvas.width = bufferWidth;
  752. canvas.height = bufferHeight;
  753. context.drawImage(img, 0, 0);
  754. // Create VertexData from map data
  755. // Cast is due to wrong definition in lib.d.ts from ts 1.3 - https://github.com/Microsoft/TypeScript/issues/949
  756. var buffer = <Uint8Array>(<any>context.getImageData(0, 0, bufferWidth, bufferHeight).data);
  757. var vertexData = VertexData.CreateGroundFromHeightMap({
  758. width: width, height: height,
  759. subdivisions: subdivisions,
  760. minHeight: minHeight, maxHeight: maxHeight, colorFilter: filter,
  761. buffer: buffer, bufferWidth: bufferWidth, bufferHeight: bufferHeight,
  762. alphaFilter: alphaFilter
  763. });
  764. vertexData.applyToMesh(ground, updatable);
  765. //execute ready callback, if set
  766. if (onReady) {
  767. onReady(ground);
  768. }
  769. ground._setReady(true);
  770. };
  771. Tools.LoadImage(url, onload, () => { }, scene.database);
  772. return ground;
  773. }
  774. /**
  775. * Creates a polygon mesh
  776. * The polygon's shape will depend on the input parameters and is constructed parallel to a ground mesh
  777. * * 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
  778. * * You can set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  779. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  780. * * 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)
  781. * * Remember you can only change the shape positions, not their number when updating a polygon
  782. * @param name defines the name of the mesh
  783. * @param options defines the options used to create the mesh
  784. * @param scene defines the hosting scene
  785. * @returns the polygon mesh
  786. */
  787. public static CreatePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Scene): Mesh {
  788. options.sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  789. var shape = options.shape;
  790. var holes = options.holes || [];
  791. var depth = options.depth || 0;
  792. var contours: Array<Vector2> = [];
  793. var hole: Array<Vector2> = [];
  794. for (var i = 0; i < shape.length; i++) {
  795. contours[i] = new Vector2(shape[i].x, shape[i].z);
  796. }
  797. var epsilon = 0.00000001;
  798. if (contours[0].equalsWithEpsilon(contours[contours.length - 1], epsilon)) {
  799. contours.pop();
  800. }
  801. var polygonTriangulation = new PolygonMeshBuilder(name, contours, scene);
  802. for (var hNb = 0; hNb < holes.length; hNb++) {
  803. hole = [];
  804. for (var hPoint = 0; hPoint < holes[hNb].length; hPoint++) {
  805. hole.push(new Vector2(holes[hNb][hPoint].x, holes[hNb][hPoint].z));
  806. }
  807. polygonTriangulation.addHole(hole);
  808. }
  809. var polygon = polygonTriangulation.build(options.updatable, depth);
  810. polygon._originalBuilderSideOrientation = options.sideOrientation;
  811. var vertexData = VertexData.CreatePolygon(polygon, options.sideOrientation, options.faceUV, options.faceColors, options.frontUVs, options.backUVs);
  812. vertexData.applyToMesh(polygon, options.updatable);
  813. return polygon;
  814. };
  815. /**
  816. * Creates an extruded polygon mesh, with depth in the Y direction.
  817. * * 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)
  818. * @see http://doc.babylonjs.com/tutorials/CreateBox_Per_Face_Textures_And_Colors
  819. * @param name defines the name of the mesh
  820. * @param options defines the options used to create the mesh
  821. * @param scene defines the hosting scene
  822. * @returns the polygon mesh
  823. */
  824. public static ExtrudePolygon(name: string, options: { shape: Vector3[], holes?: Vector3[][], depth?: number, faceUV?: Vector4[], faceColors?: Color4[], updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Scene): Mesh {
  825. return MeshBuilder.CreatePolygon(name, options, scene);
  826. };
  827. /**
  828. * Creates a tube mesh.
  829. * The tube is a parametric shape. It has no predefined shape. Its final shape will depend on the input parameters
  830. * * The parameter `path` is a required array of successive Vector3. It is the curve used as the axis of the tube
  831. * * The parameter `radius` (positive float, default 1) sets the tube radius size
  832. * * The parameter `tessellation` (positive float, default 64) is the number of sides on the tubular surface
  833. * * The parameter `radiusFunction` (javascript function, default null) is a vanilla javascript function. If it is not null, it overwrittes the parameter `radius`
  834. * * This function is called on each point of the tube path and is passed the index `i` of the i-th point and the distance of this point from the first point of the path. It must return a radius value (positive float)
  835. * * The parameter `arc` (positive float, maximum 1, default 1) is the ratio to apply to the tube circumference : 2 x PI x arc
  836. * * The parameter `cap` sets the way the extruded shape is capped. Possible values : BABYLON.Mesh.NO_CAP (default), BABYLON.Mesh.CAP_START, BABYLON.Mesh.CAP_END, BABYLON.Mesh.CAP_ALL
  837. * * The optional parameter `instance` is an instance of an existing Tube object to be updated with the passed `pathArray` parameter : http://doc.babylonjs.com/tutorials/How_to_dynamically_morph_a_mesh#tube
  838. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  839. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  840. * * The optional parameter `invertUV` (boolean, default false) swaps in the geometry the U and V coordinates to apply a texture
  841. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  842. * @param name defines the name of the mesh
  843. * @param options defines the options used to create the mesh
  844. * @param scene defines the hosting scene
  845. * @returns the tube mesh
  846. * @see http://doc.babylonjs.com/tutorials/Parametric_Shapes
  847. * @see http://doc.babylonjs.com/tutorials/Mesh_CreateXXX_Methods_With_Options_Parameter#tube
  848. */
  849. public static CreateTube(name: string, options: { path: Vector3[], radius?: number, tessellation?: number, radiusFunction?: { (i: number, distance: number): number; }, cap?: number, arc?: number, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4, instance?: Mesh, invertUV?: boolean }, scene: Scene): Mesh {
  850. var path = options.path;
  851. var instance = options.instance;
  852. var radius = 1.0;
  853. if (options.radius !== undefined) {
  854. radius = options.radius;
  855. } else if (instance) {
  856. radius = instance._creationDataStorage!.radius;
  857. }
  858. var tessellation = options.tessellation || 64 | 0;
  859. var radiusFunction = options.radiusFunction || null;
  860. var cap = options.cap || Mesh.NO_CAP;
  861. var invertUV = options.invertUV || false;
  862. var updatable = options.updatable;
  863. var sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  864. options.arc = options.arc && (options.arc <= 0.0 || options.arc > 1.0) ? 1.0 : options.arc || 1.0;
  865. // tube geometry
  866. var tubePathArray = (path: Vector3[], path3D: Path3D, circlePaths: Vector3[][], radius: number, tessellation: number,
  867. radiusFunction: Nullable<{ (i: number, distance: number): number; }>, cap: number, arc: number) => {
  868. var tangents = path3D.getTangents();
  869. var normals = path3D.getNormals();
  870. var distances = path3D.getDistances();
  871. var pi2 = Math.PI * 2;
  872. var step = pi2 / tessellation * arc;
  873. var returnRadius: { (i: number, distance: number): number; } = () => radius;
  874. var radiusFunctionFinal: { (i: number, distance: number): number; } = radiusFunction || returnRadius;
  875. var circlePath: Vector3[];
  876. var rad: number;
  877. var normal: Vector3;
  878. var rotated: Vector3;
  879. var rotationMatrix: Matrix = Tmp.Matrix[0];
  880. var index = (cap === Mesh.NO_CAP || cap === Mesh.CAP_END) ? 0 : 2;
  881. for (var i = 0; i < path.length; i++) {
  882. rad = radiusFunctionFinal(i, distances[i]); // current radius
  883. circlePath = Array<Vector3>(); // current circle array
  884. normal = normals[i]; // current normal
  885. for (var t = 0; t < tessellation; t++) {
  886. Matrix.RotationAxisToRef(tangents[i], step * t, rotationMatrix);
  887. rotated = circlePath[t] ? circlePath[t] : Vector3.Zero();
  888. Vector3.TransformCoordinatesToRef(normal, rotationMatrix, rotated);
  889. rotated.scaleInPlace(rad).addInPlace(path[i]);
  890. circlePath[t] = rotated;
  891. }
  892. circlePaths[index] = circlePath;
  893. index++;
  894. }
  895. // cap
  896. var capPath = (nbPoints: number, pathIndex: number): Array<Vector3> => {
  897. var pointCap = Array<Vector3>();
  898. for (var i = 0; i < nbPoints; i++) {
  899. pointCap.push(path[pathIndex]);
  900. }
  901. return pointCap;
  902. };
  903. switch (cap) {
  904. case Mesh.NO_CAP:
  905. break;
  906. case Mesh.CAP_START:
  907. circlePaths[0] = capPath(tessellation, 0);
  908. circlePaths[1] = circlePaths[2].slice(0);
  909. break;
  910. case Mesh.CAP_END:
  911. circlePaths[index] = circlePaths[index - 1].slice(0);
  912. circlePaths[index + 1] = capPath(tessellation, path.length - 1);
  913. break;
  914. case Mesh.CAP_ALL:
  915. circlePaths[0] = capPath(tessellation, 0);
  916. circlePaths[1] = circlePaths[2].slice(0);
  917. circlePaths[index] = circlePaths[index - 1].slice(0);
  918. circlePaths[index + 1] = capPath(tessellation, path.length - 1);
  919. break;
  920. default:
  921. break;
  922. }
  923. return circlePaths;
  924. };
  925. var path3D;
  926. var pathArray;
  927. if (instance) { // tube update
  928. let storage = instance._creationDataStorage!;
  929. var arc = options.arc || storage.arc;
  930. path3D = storage.path3D.update(path);
  931. pathArray = tubePathArray(path, path3D, storage.pathArray, radius, storage.tessellation, radiusFunction, storage.cap, arc);
  932. instance = MeshBuilder.CreateRibbon("", { pathArray: pathArray, instance: instance });
  933. // Update mode, no need to recreate the storage.
  934. storage.path3D = path3D;
  935. storage.pathArray = pathArray;
  936. storage.arc = arc;
  937. storage.radius = radius;
  938. return instance;
  939. }
  940. // tube creation
  941. path3D = <any>new Path3D(path);
  942. var newPathArray = new Array<Array<Vector3>>();
  943. cap = (cap < 0 || cap > 3) ? 0 : cap;
  944. pathArray = tubePathArray(path, path3D, newPathArray, radius, tessellation, radiusFunction, cap, options.arc);
  945. var tube = MeshBuilder.CreateRibbon(name, { pathArray: pathArray, closePath: true, closeArray: false, updatable: updatable, sideOrientation: sideOrientation, invertUV: invertUV, frontUVs: options.frontUVs, backUVs: options.backUVs }, scene);
  946. tube._creationDataStorage!.pathArray = pathArray;
  947. tube._creationDataStorage!.path3D = path3D;
  948. tube._creationDataStorage!.tessellation = tessellation;
  949. tube._creationDataStorage!.cap = cap;
  950. tube._creationDataStorage!.arc = options.arc;
  951. tube._creationDataStorage!.radius = radius;
  952. return tube;
  953. }
  954. /**
  955. * Creates a polyhedron mesh
  956. * * The parameter `type` (positive integer, max 14, default 0) sets the polyhedron type to build among the 15 embbeded types. Please refer to the type sheet in the tutorial to choose the wanted type
  957. * * The parameter `size` (positive float, default 1) sets the polygon size
  958. * * You can overwrite the `size` on each dimension bu using the parameters `sizeX`, `sizeY` or `sizeZ` (positive floats, default to `size` value)
  959. * * You can build other polyhedron types than the 15 embbeded ones by setting the parameter `custom` (`polyhedronObject`, default null). If you set the parameter `custom`, this overwrittes the parameter `type`
  960. * * A `polyhedronObject` is a formatted javascript object. You'll find a full file with pre-set polyhedra here : https://github.com/BabylonJS/Extensions/tree/master/Polyhedron
  961. * * You can set the color and the UV of each side of the polyhedron with the parameters `faceColors` (Color4, default `(1, 1, 1, 1)`) and faceUV (Vector4, default `(0, 0, 1, 1)`)
  962. * * To understand how to set `faceUV` or `faceColors`, please read this by considering the right number of faces of your polyhedron, instead of only 6 for the box : http://doc.babylonjs.com/tutorials/CreateBox_Per_Face_Textures_And_Colors
  963. * * The parameter `flat` (boolean, default true). If set to false, it gives the polyhedron a single global face, so less vertices and shared normals. In this case, `faceColors` and `faceUV` are ignored
  964. * * You can also set the mesh side orientation with the values : BABYLON.Mesh.FRONTSIDE (default), BABYLON.Mesh.BACKSIDE or BABYLON.Mesh.DOUBLESIDE
  965. * * 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 : http://doc.babylonjs.com/babylon101/discover_basic_elements#side-orientation
  966. * * The mesh can be set to updatable with the boolean parameter `updatable` (default false) if its internal geometry is supposed to change once created
  967. * @param name defines the name of the mesh
  968. * @param options defines the options used to create the mesh
  969. * @param scene defines the hosting scene
  970. * @returns the polyhedron mesh
  971. * @see http://doc.babylonjs.com/how_to/polyhedra_shapes
  972. */
  973. public static CreatePolyhedron(name: string, options: { type?: number, size?: number, sizeX?: number, sizeY?: number, sizeZ?: number, custom?: any, faceUV?: Vector4[], faceColors?: Color4[], flat?: boolean, updatable?: boolean, sideOrientation?: number, frontUVs?: Vector4, backUVs?: Vector4 }, scene: Scene): Mesh {
  974. var polyhedron = new Mesh(name, scene);
  975. options.sideOrientation = MeshBuilder.updateSideOrientation(options.sideOrientation);
  976. polyhedron._originalBuilderSideOrientation = options.sideOrientation;
  977. var vertexData = VertexData.CreatePolyhedron(options);
  978. vertexData.applyToMesh(polyhedron, options.updatable);
  979. return polyhedron;
  980. }
  981. /**
  982. * Creates a decal mesh.
  983. * A decal is a mesh usually applied as a model onto the surface of another mesh. So don't forget the parameter `sourceMesh` depicting the decal
  984. * * The parameter `position` (Vector3, default `(0, 0, 0)`) sets the position of the decal in World coordinates
  985. * * The parameter `normal` (Vector3, default `Vector3.Up`) sets the normal of the mesh where the decal is applied onto in World coordinates
  986. * * The parameter `size` (Vector3, default `(1, 1, 1)`) sets the decal scaling
  987. * * The parameter `angle` (float in radian, default 0) sets the angle to rotate the decal
  988. * @param name defines the name of the mesh
  989. * @param sourceMesh defines the mesh where the decal must be applied
  990. * @param options defines the options used to create the mesh
  991. * @param scene defines the hosting scene
  992. * @returns the decal mesh
  993. * @see http://doc.babylonjs.com/how_to/decals
  994. */
  995. public static CreateDecal(name: string, sourceMesh: AbstractMesh, options: { position?: Vector3, normal?: Vector3, size?: Vector3, angle?: number }): Mesh {
  996. var indices = <IndicesArray>sourceMesh.getIndices();
  997. var positions = sourceMesh.getVerticesData(VertexBuffer.PositionKind);
  998. var normals = sourceMesh.getVerticesData(VertexBuffer.NormalKind);
  999. var position = options.position || Vector3.Zero();
  1000. var normal = options.normal || Vector3.Up();
  1001. var size = options.size || Vector3.One();
  1002. var angle = options.angle || 0;
  1003. // Getting correct rotation
  1004. if (!normal) {
  1005. var target = new Vector3(0, 0, 1);
  1006. var camera = <Camera>sourceMesh.getScene().activeCamera;
  1007. var cameraWorldTarget = Vector3.TransformCoordinates(target, camera.getWorldMatrix());
  1008. normal = camera.globalPosition.subtract(cameraWorldTarget);
  1009. }
  1010. var yaw = -Math.atan2(normal.z, normal.x) - Math.PI / 2;
  1011. var len = Math.sqrt(normal.x * normal.x + normal.z * normal.z);
  1012. var pitch = Math.atan2(normal.y, len);
  1013. // Matrix
  1014. var decalWorldMatrix = Matrix.RotationYawPitchRoll(yaw, pitch, angle).multiply(Matrix.Translation(position.x, position.y, position.z));
  1015. var inverseDecalWorldMatrix = Matrix.Invert(decalWorldMatrix);
  1016. var meshWorldMatrix = sourceMesh.getWorldMatrix();
  1017. var transformMatrix = meshWorldMatrix.multiply(inverseDecalWorldMatrix);
  1018. var vertexData = new VertexData();
  1019. vertexData.indices = [];
  1020. vertexData.positions = [];
  1021. vertexData.normals = [];
  1022. vertexData.uvs = [];
  1023. var currentVertexDataIndex = 0;
  1024. var extractDecalVector3 = (indexId: number): PositionNormalVertex => {
  1025. var result = new PositionNormalVertex();
  1026. if (!indices || !positions || !normals) {
  1027. return result;
  1028. }
  1029. var vertexId = indices[indexId];
  1030. result.position = new Vector3(positions[vertexId * 3], positions[vertexId * 3 + 1], positions[vertexId * 3 + 2]);
  1031. // Send vector to decal local world
  1032. result.position = Vector3.TransformCoordinates(result.position, transformMatrix);
  1033. // Get normal
  1034. result.normal = new Vector3(normals[vertexId * 3], normals[vertexId * 3 + 1], normals[vertexId * 3 + 2]);
  1035. result.normal = Vector3.TransformNormal(result.normal, transformMatrix);
  1036. return result;
  1037. }; // Inspired by https://github.com/mrdoob/three.js/blob/eee231960882f6f3b6113405f524956145148146/examples/js/geometries/DecalGeometry.js
  1038. var clip = (vertices: PositionNormalVertex[], axis: Vector3): PositionNormalVertex[] => {
  1039. if (vertices.length === 0) {
  1040. return vertices;
  1041. }
  1042. var clipSize = 0.5 * Math.abs(Vector3.Dot(size, axis));
  1043. var clipVertices = (v0: PositionNormalVertex, v1: PositionNormalVertex): PositionNormalVertex => {
  1044. var clipFactor = Vector3.GetClipFactor(v0.position, v1.position, axis, clipSize);
  1045. return new PositionNormalVertex(
  1046. Vector3.Lerp(v0.position, v1.position, clipFactor),
  1047. Vector3.Lerp(v0.normal, v1.normal, clipFactor)
  1048. );
  1049. };
  1050. var result = new Array<PositionNormalVertex>();
  1051. for (var index = 0; index < vertices.length; index += 3) {
  1052. var v1Out: boolean;
  1053. var v2Out: boolean;
  1054. var v3Out: boolean;
  1055. var total = 0;
  1056. let nV1: Nullable<PositionNormalVertex> = null;
  1057. let nV2: Nullable<PositionNormalVertex> = null;
  1058. let nV3: Nullable<PositionNormalVertex> = null;
  1059. let nV4: Nullable<PositionNormalVertex> = null;
  1060. var d1 = Vector3.Dot(vertices[index].position, axis) - clipSize;
  1061. var d2 = Vector3.Dot(vertices[index + 1].position, axis) - clipSize;
  1062. var d3 = Vector3.Dot(vertices[index + 2].position, axis) - clipSize;
  1063. v1Out = d1 > 0;
  1064. v2Out = d2 > 0;
  1065. v3Out = d3 > 0;
  1066. total = (v1Out ? 1 : 0) + (v2Out ? 1 : 0) + (v3Out ? 1 : 0);
  1067. switch (total) {
  1068. case 0:
  1069. result.push(vertices[index]);
  1070. result.push(vertices[index + 1]);
  1071. result.push(vertices[index + 2]);
  1072. break;
  1073. case 1:
  1074. if (v1Out) {
  1075. nV1 = vertices[index + 1];
  1076. nV2 = vertices[index + 2];
  1077. nV3 = clipVertices(vertices[index], nV1);
  1078. nV4 = clipVertices(vertices[index], nV2);
  1079. }
  1080. if (v2Out) {
  1081. nV1 = vertices[index];
  1082. nV2 = vertices[index + 2];
  1083. nV3 = clipVertices(vertices[index + 1], nV1);
  1084. nV4 = clipVertices(vertices[index + 1], nV2);
  1085. result.push(nV3);
  1086. result.push(nV2.clone());
  1087. result.push(nV1.clone());
  1088. result.push(nV2.clone());
  1089. result.push(nV3.clone());
  1090. result.push(nV4);
  1091. break;
  1092. }
  1093. if (v3Out) {
  1094. nV1 = vertices[index];
  1095. nV2 = vertices[index + 1];
  1096. nV3 = clipVertices(vertices[index + 2], nV1);
  1097. nV4 = clipVertices(vertices[index + 2], nV2);
  1098. }
  1099. if (nV1 && nV2 && nV3 && nV4) {
  1100. result.push(nV1.clone());
  1101. result.push(nV2.clone());
  1102. result.push(nV3);
  1103. result.push(nV4);
  1104. result.push(nV3.clone());
  1105. result.push(nV2.clone());
  1106. }
  1107. break;
  1108. case 2:
  1109. if (!v1Out) {
  1110. nV1 = vertices[index].clone();
  1111. nV2 = clipVertices(nV1, vertices[index + 1]);
  1112. nV3 = clipVertices(nV1, vertices[index + 2]);
  1113. result.push(nV1);
  1114. result.push(nV2);
  1115. result.push(nV3);
  1116. }
  1117. if (!v2Out) {
  1118. nV1 = vertices[index + 1].clone();
  1119. nV2 = clipVertices(nV1, vertices[index + 2]);
  1120. nV3 = clipVertices(nV1, vertices[index]);
  1121. result.push(nV1);
  1122. result.push(nV2);
  1123. result.push(nV3);
  1124. }
  1125. if (!v3Out) {
  1126. nV1 = vertices[index + 2].clone();
  1127. nV2 = clipVertices(nV1, vertices[index]);
  1128. nV3 = clipVertices(nV1, vertices[index + 1]);
  1129. result.push(nV1);
  1130. result.push(nV2);
  1131. result.push(nV3);
  1132. }
  1133. break;
  1134. case 3:
  1135. break;
  1136. }
  1137. }
  1138. return result;
  1139. };
  1140. for (var index = 0; index < indices.length; index += 3) {
  1141. var faceVertices = new Array<PositionNormalVertex>();
  1142. faceVertices.push(extractDecalVector3(index));
  1143. faceVertices.push(extractDecalVector3(index + 1));
  1144. faceVertices.push(extractDecalVector3(index + 2));
  1145. // Clip
  1146. faceVertices = clip(faceVertices, new Vector3(1, 0, 0));
  1147. faceVertices = clip(faceVertices, new Vector3(-1, 0, 0));
  1148. faceVertices = clip(faceVertices, new Vector3(0, 1, 0));
  1149. faceVertices = clip(faceVertices, new Vector3(0, -1, 0));
  1150. faceVertices = clip(faceVertices, new Vector3(0, 0, 1));
  1151. faceVertices = clip(faceVertices, new Vector3(0, 0, -1));
  1152. if (faceVertices.length === 0) {
  1153. continue;
  1154. }
  1155. // Add UVs and get back to world
  1156. for (var vIndex = 0; vIndex < faceVertices.length; vIndex++) {
  1157. var vertex = faceVertices[vIndex];
  1158. //TODO check for Int32Array | Uint32Array | Uint16Array
  1159. (<number[]>vertexData.indices).push(currentVertexDataIndex);
  1160. vertex.position.toArray(vertexData.positions, currentVertexDataIndex * 3);
  1161. vertex.normal.toArray(vertexData.normals, currentVertexDataIndex * 3);
  1162. (<number[]>vertexData.uvs).push(0.5 + vertex.position.x / size.x);
  1163. (<number[]>vertexData.uvs).push(0.5 + vertex.position.y / size.y);
  1164. currentVertexDataIndex++;
  1165. }
  1166. }
  1167. // Return mesh
  1168. var decal = new Mesh(name, sourceMesh.getScene());
  1169. vertexData.applyToMesh(decal);
  1170. decal.position = position.clone();
  1171. decal.rotation = new Vector3(pitch, yaw, angle);
  1172. return decal;
  1173. }
  1174. // Privates
  1175. private static _ExtrudeShapeGeneric(name: string, shape: Vector3[], curve: Vector3[], scale: Nullable<number>, rotation: Nullable<number>, scaleFunction: Nullable<{ (i: number, distance: number): number; }>,
  1176. rotateFunction: Nullable<{ (i: number, distance: number): number; }>, rbCA: boolean, rbCP: boolean, cap: number, custom: boolean,
  1177. scene: Nullable<Scene>, updtbl: boolean, side: number, instance: Nullable<Mesh>, invertUV: boolean, frontUVs: Nullable<Vector4>, backUVs: Nullable<Vector4>): Mesh {
  1178. // extrusion geometry
  1179. var extrusionPathArray = (shape: Vector3[], curve: Vector3[], path3D: Path3D, shapePaths: Vector3[][], scale: Nullable<number>, rotation: Nullable<number>,
  1180. scaleFunction: Nullable<{ (i: number, distance: number): number; }>, rotateFunction: Nullable<{ (i: number, distance: number): number; }>, cap: number, custom: boolean) => {
  1181. var tangents = path3D.getTangents();
  1182. var normals = path3D.getNormals();
  1183. var binormals = path3D.getBinormals();
  1184. var distances = path3D.getDistances();
  1185. var angle = 0;
  1186. var returnScale: { (i: number, distance: number): number; } = () => { return scale !== null ? scale : 1; };
  1187. var returnRotation: { (i: number, distance: number): number; } = () => { return rotation !== null ? rotation : 0; };
  1188. var rotate: { (i: number, distance: number): number; } = custom && rotateFunction ? rotateFunction : returnRotation;
  1189. var scl: { (i: number, distance: number): number; } = custom && scaleFunction ? scaleFunction : returnScale;
  1190. var index = (cap === Mesh.NO_CAP || cap === Mesh.CAP_END) ? 0 : 2;
  1191. var rotationMatrix: Matrix = Tmp.Matrix[0];
  1192. for (var i = 0; i < curve.length; i++) {
  1193. var shapePath = new Array<Vector3>();
  1194. var angleStep = rotate(i, distances[i]);
  1195. var scaleRatio = scl(i, distances[i]);
  1196. for (var p = 0; p < shape.length; p++) {
  1197. Matrix.RotationAxisToRef(tangents[i], angle, rotationMatrix);
  1198. var planed = ((tangents[i].scale(shape[p].z)).add(normals[i].scale(shape[p].x)).add(binormals[i].scale(shape[p].y)));
  1199. var rotated = shapePath[p] ? shapePath[p] : Vector3.Zero();
  1200. Vector3.TransformCoordinatesToRef(planed, rotationMatrix, rotated);
  1201. rotated.scaleInPlace(scaleRatio).addInPlace(curve[i]);
  1202. shapePath[p] = rotated;
  1203. }
  1204. shapePaths[index] = shapePath;
  1205. angle += angleStep;
  1206. index++;
  1207. }
  1208. // cap
  1209. var capPath = (shapePath: Vector3[]) => {
  1210. var pointCap = Array<Vector3>();
  1211. var barycenter = Vector3.Zero();
  1212. var i: number;
  1213. for (i = 0; i < shapePath.length; i++) {
  1214. barycenter.addInPlace(shapePath[i]);
  1215. }
  1216. barycenter.scaleInPlace(1.0 / shapePath.length);
  1217. for (i = 0; i < shapePath.length; i++) {
  1218. pointCap.push(barycenter);
  1219. }
  1220. return pointCap;
  1221. };
  1222. switch (cap) {
  1223. case Mesh.NO_CAP:
  1224. break;
  1225. case Mesh.CAP_START:
  1226. shapePaths[0] = capPath(shapePaths[2]);
  1227. shapePaths[1] = shapePaths[2];
  1228. break;
  1229. case Mesh.CAP_END:
  1230. shapePaths[index] = shapePaths[index - 1];
  1231. shapePaths[index + 1] = capPath(shapePaths[index - 1]);
  1232. break;
  1233. case Mesh.CAP_ALL:
  1234. shapePaths[0] = capPath(shapePaths[2]);
  1235. shapePaths[1] = shapePaths[2];
  1236. shapePaths[index] = shapePaths[index - 1];
  1237. shapePaths[index + 1] = capPath(shapePaths[index - 1]);
  1238. break;
  1239. default:
  1240. break;
  1241. }
  1242. return shapePaths;
  1243. };
  1244. var path3D;
  1245. var pathArray;
  1246. if (instance) { // instance update
  1247. let storage = instance._creationDataStorage!;
  1248. path3D = storage.path3D.update(curve);
  1249. pathArray = extrusionPathArray(shape, curve, storage.path3D, storage.pathArray, scale, rotation, scaleFunction, rotateFunction, storage.cap, custom);
  1250. instance = Mesh.CreateRibbon("", pathArray, false, false, 0, scene || undefined, false, 0, instance);
  1251. return instance;
  1252. }
  1253. // extruded shape creation
  1254. path3D = <any>new Path3D(curve);
  1255. var newShapePaths = new Array<Array<Vector3>>();
  1256. cap = (cap < 0 || cap > 3) ? 0 : cap;
  1257. pathArray = extrusionPathArray(shape, curve, path3D, newShapePaths, scale, rotation, scaleFunction, rotateFunction, cap, custom);
  1258. var extrudedGeneric = MeshBuilder.CreateRibbon(name, { pathArray: pathArray, closeArray: rbCA, closePath: rbCP, updatable: updtbl, sideOrientation: side, invertUV: invertUV, frontUVs: frontUVs || undefined, backUVs: backUVs || undefined }, scene);
  1259. extrudedGeneric._creationDataStorage!.pathArray = pathArray;
  1260. extrudedGeneric._creationDataStorage!.path3D = path3D;
  1261. extrudedGeneric._creationDataStorage!.cap = cap;
  1262. return extrudedGeneric;
  1263. }
  1264. }
  1265. }