babylon.meshBuilder.ts 73 KB

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