babylon.meshBuilder.ts 91 KB

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