babylon.meshBuilder.ts 41 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815
  1. module BABYLON {
  2. export class MeshBuilder {
  3. public static CreateBox(name: string, options: { width?: number, height?: number, depth?: number, faceUV?: Vector4[], faceColors?: Color4[], sideOrientation?: number, updatable?: boolean }, scene: Scene): Mesh {
  4. var box = new Mesh(name, scene);
  5. var vertexData = VertexData.CreateBox(options);
  6. vertexData.applyToMesh(box, options.updatable);
  7. return box;
  8. }
  9. 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 {
  10. var sphere = new Mesh(name, scene);
  11. var vertexData = VertexData.CreateSphere(options);
  12. vertexData.applyToMesh(sphere, options.updatable);
  13. return sphere;
  14. }
  15. public static CreateDisc(name: string, options: { radius?: number, tessellation?: number, arc?: number, updatable?: boolean, sideOrientation?: number }, scene: Scene): Mesh {
  16. var disc = new Mesh(name, scene);
  17. var vertexData = VertexData.CreateDisc(options);
  18. vertexData.applyToMesh(disc, options.updatable);
  19. return disc;
  20. }
  21. public static CreateIcoSphere(name: string, options: { radius?: number, radiusX?: number, radiusY?: number, radiusZ?: number, flat?: number, subdivisions?: number, sideOrientation?: number, updatable?: boolean }, scene: Scene): Mesh {
  22. var sphere = new Mesh(name, scene);
  23. var vertexData = VertexData.CreateIcoSphere(options);
  24. vertexData.applyToMesh(sphere, options.updatable);
  25. return sphere;
  26. };
  27. public static CreateRibbon(name: string, options: { pathArray: Vector3[][], closeArray?: boolean, closePath?: boolean, offset?: number, updatable?: boolean, sideOrientation?: number, instance?: Mesh }, scene?: Scene): Mesh {
  28. var pathArray = options.pathArray;
  29. var closeArray = options.closeArray;
  30. var closePath = options.closePath;
  31. var offset = options.offset;
  32. var sideOrientation = options.sideOrientation;
  33. var instance = options.instance;
  34. var updatable = options.updatable;
  35. if (instance) { // existing ribbon instance update
  36. // positionFunction : ribbon case
  37. // only pathArray and sideOrientation parameters are taken into account for positions update
  38. var positionFunction = positions => {
  39. var minlg = pathArray[0].length;
  40. var i = 0;
  41. var ns = (instance.sideOrientation === Mesh.DOUBLESIDE) ? 2 : 1;
  42. for (var si = 1; si <= ns; si++) {
  43. for (var p = 0; p < pathArray.length; p++) {
  44. var path = pathArray[p];
  45. var l = path.length;
  46. minlg = (minlg < l) ? minlg : l;
  47. var j = 0;
  48. while (j < minlg) {
  49. positions[i] = path[j].x;
  50. positions[i + 1] = path[j].y;
  51. positions[i + 2] = path[j].z;
  52. j++;
  53. i += 3;
  54. }
  55. if ((<any>instance)._closePath) {
  56. positions[i] = path[0].x;
  57. positions[i + 1] = path[0].y;
  58. positions[i + 2] = path[0].z;
  59. i += 3;
  60. }
  61. }
  62. }
  63. };
  64. var positions = instance.getVerticesData(VertexBuffer.PositionKind);
  65. positionFunction(positions);
  66. instance.updateVerticesData(VertexBuffer.PositionKind, positions, false, false);
  67. if (!(instance.areNormalsFrozen)) {
  68. var indices = instance.getIndices();
  69. var normals = instance.getVerticesData(VertexBuffer.NormalKind);
  70. VertexData.ComputeNormals(positions, indices, normals);
  71. if ((<any>instance)._closePath) {
  72. var indexFirst: number = 0;
  73. var indexLast: number = 0;
  74. for (var p = 0; p < pathArray.length; p++) {
  75. indexFirst = (<any>instance)._idx[p] * 3;
  76. if (p + 1 < pathArray.length) {
  77. indexLast = ((<any>instance)._idx[p + 1] - 1) * 3;
  78. }
  79. else {
  80. indexLast = normals.length - 3;
  81. }
  82. normals[indexFirst] = (normals[indexFirst] + normals[indexLast]) * 0.5;
  83. normals[indexFirst + 1] = (normals[indexFirst + 1] + normals[indexLast + 1]) * 0.5;
  84. normals[indexFirst + 2] = (normals[indexFirst + 2] + normals[indexLast + 2]) * 0.5;
  85. normals[indexLast] = normals[indexFirst];
  86. normals[indexLast + 1] = normals[indexFirst + 1];
  87. normals[indexLast + 2] = normals[indexFirst + 2];
  88. }
  89. }
  90. instance.updateVerticesData(VertexBuffer.NormalKind, normals, false, false);
  91. }
  92. return instance;
  93. }
  94. else { // new ribbon creation
  95. var ribbon = new Mesh(name, scene);
  96. ribbon.sideOrientation = sideOrientation;
  97. var vertexData = VertexData.CreateRibbon(options);
  98. if (closePath) {
  99. (<any>ribbon)._idx = (<any>vertexData)._idx;
  100. }
  101. (<any>ribbon)._closePath = closePath;
  102. (<any>ribbon)._closeArray = closeArray;
  103. vertexData.applyToMesh(ribbon, updatable);
  104. return ribbon;
  105. }
  106. }
  107. 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 {
  108. var cylinder = new Mesh(name, scene);
  109. var vertexData = VertexData.CreateCylinder(options);
  110. vertexData.applyToMesh(cylinder, options.updatable);
  111. return cylinder;
  112. }
  113. public static CreateTorus(name: string, options: { diameter?: number, thickness?: number, tessellation?: number, updatable?: boolean, sideOrientation?: number }, scene: any): Mesh {
  114. var torus = new Mesh(name, scene);
  115. var vertexData = VertexData.CreateTorus(options);
  116. vertexData.applyToMesh(torus, options.updatable);
  117. return torus;
  118. }
  119. 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 {
  120. var torusKnot = new Mesh(name, scene);
  121. var vertexData = VertexData.CreateTorusKnot(options);
  122. vertexData.applyToMesh(torusKnot, options.updatable);
  123. return torusKnot;
  124. }
  125. public static CreateLines(name: string, options: { points: Vector3[], updatable?: boolean, instance?: LinesMesh }, scene: Scene): LinesMesh {
  126. var instance = options.instance;
  127. var points = options.points;
  128. if (instance) { // lines update
  129. var positionFunction = positions => {
  130. var i = 0;
  131. for (var p = 0; p < points.length; p++) {
  132. positions[i] = points[p].x;
  133. positions[i + 1] = points[p].y;
  134. positions[i + 2] = points[p].z;
  135. i += 3;
  136. }
  137. };
  138. instance.updateMeshPositions(positionFunction, false);
  139. return instance;
  140. }
  141. // lines creation
  142. var lines = new LinesMesh(name, scene);
  143. var vertexData = VertexData.CreateLines(options);
  144. vertexData.applyToMesh(lines, options.updatable);
  145. return lines;
  146. }
  147. public static CreateDashedLines(name: string, options: { points: Vector3[], dashSize?: number, gapSize?: number, dashNb?: number, updatable?: boolean, instance?: LinesMesh }, scene: Scene): LinesMesh {
  148. var points = options.points;
  149. var instance = options.instance;
  150. var gapSize = options.gapSize;
  151. var dashNb = options.dashNb;
  152. var dashSize = options.dashSize;
  153. if (instance) { // dashed lines update
  154. var positionFunction = (positions: number[]): void => {
  155. var curvect = Vector3.Zero();
  156. var nbSeg = positions.length / 6;
  157. var lg = 0;
  158. var nb = 0;
  159. var shft = 0;
  160. var dashshft = 0;
  161. var curshft = 0;
  162. var p = 0;
  163. var i = 0;
  164. var j = 0;
  165. for (i = 0; i < points.length - 1; i++) {
  166. points[i + 1].subtractToRef(points[i], curvect);
  167. lg += curvect.length();
  168. }
  169. shft = lg / nbSeg;
  170. dashshft = (<any>instance).dashSize * shft / ((<any>instance).dashSize + (<any>instance).gapSize);
  171. for (i = 0; i < points.length - 1; i++) {
  172. points[i + 1].subtractToRef(points[i], curvect);
  173. nb = Math.floor(curvect.length() / shft);
  174. curvect.normalize();
  175. j = 0;
  176. while (j < nb && p < positions.length) {
  177. curshft = shft * j;
  178. positions[p] = points[i].x + curshft * curvect.x;
  179. positions[p + 1] = points[i].y + curshft * curvect.y;
  180. positions[p + 2] = points[i].z + curshft * curvect.z;
  181. positions[p + 3] = points[i].x + (curshft + dashshft) * curvect.x;
  182. positions[p + 4] = points[i].y + (curshft + dashshft) * curvect.y;
  183. positions[p + 5] = points[i].z + (curshft + dashshft) * curvect.z;
  184. p += 6;
  185. j++;
  186. }
  187. }
  188. while (p < positions.length) {
  189. positions[p] = points[i].x;
  190. positions[p + 1] = points[i].y;
  191. positions[p + 2] = points[i].z;
  192. p += 3;
  193. }
  194. };
  195. instance.updateMeshPositions(positionFunction, false);
  196. return instance;
  197. }
  198. // dashed lines creation
  199. var dashedLines = new LinesMesh(name, scene);
  200. var vertexData = VertexData.CreateDashedLines(options);
  201. vertexData.applyToMesh(dashedLines, options.updatable);
  202. (<any>dashedLines).dashSize = dashSize;
  203. (<any>dashedLines).gapSize = gapSize;
  204. return dashedLines;
  205. }
  206. 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 {
  207. var path = options.path;
  208. var shape = options.shape;
  209. var scale = options.scale || 1;
  210. var rotation = options.rotation || 0;
  211. var cap = (options.cap === 0) ? 0 : options.cap || Mesh.NO_CAP;
  212. var updatable = options.updatable;
  213. var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  214. var instance = options.instance;
  215. return MeshBuilder._ExtrudeShapeGeneric(name, shape, path, scale, rotation, null, null, false, false, cap, false, scene, updatable, sideOrientation, instance);
  216. }
  217. public static ExtrudeShapeCustom(name: string, options: { shape: Vector3[], path: Vector3[], scaleFunction?, rotationFunction?, ribbonCloseArray?: boolean, ribbonClosePath?: boolean, cap?: number, updatable?: boolean, sideOrientation?: number, instance?: Mesh }, scene: Scene): Mesh {
  218. var path = options.path;
  219. var shape = options.shape;
  220. var scaleFunction = options.scaleFunction || (() => { return 1; });
  221. var rotationFunction = options.rotationFunction || (() => { return 0; });
  222. var ribbonCloseArray = options.ribbonCloseArray || false;
  223. var ribbonClosePath = options.ribbonClosePath || false;
  224. var cap = (options.cap === 0) ? 0 : options.cap || Mesh.NO_CAP;
  225. var updatable = options.updatable;
  226. var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  227. var instance = options.instance;
  228. return MeshBuilder._ExtrudeShapeGeneric(name, shape, path, null, null, scaleFunction, rotationFunction, ribbonCloseArray, ribbonClosePath, cap, true, scene, updatable, sideOrientation, instance);
  229. }
  230. 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 {
  231. var arc: number = (options.arc <= 0 || options.arc > 1) ? 1.0 : options.arc || 1.0;
  232. var closed: boolean = (options.closed === undefined) ? true : options.closed;
  233. var shape = options.shape;
  234. var radius = options.radius || 1;
  235. var tessellation = options.tessellation || 64;
  236. var updatable = options.updatable;
  237. var sideOrientation = (options.sideOrientation === 0) ? 0 : options.sideOrientation || Mesh.DEFAULTSIDE;
  238. var cap = options.cap || Mesh.NO_CAP;
  239. var pi2 = Math.PI * 2;
  240. var paths = new Array();
  241. var i = 0;
  242. var p = 0;
  243. var step = pi2 / tessellation * arc;
  244. var rotated;
  245. var path = new Array<Vector3>();;
  246. for (i = 0; i <= tessellation; i++) {
  247. var path: Vector3[] = [];
  248. if (cap == Mesh.CAP_START || cap == Mesh.CAP_ALL) {
  249. path.push(new Vector3(0, shape[0].y, 0));
  250. path.push(new Vector3(shape[0].x, shape[0].y, shape[0].x));
  251. }
  252. for (p = 0; p < shape.length; p++) {
  253. rotated = new Vector3(Math.cos(i * step) * shape[p].x * radius, shape[p].y, Math.sin(i * step) * shape[p].x * radius);
  254. path.push(rotated);
  255. }
  256. if (cap == Mesh.CAP_END || cap == Mesh.CAP_ALL) {
  257. 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));
  258. path.push(new Vector3(0, shape[shape.length - 1].y, 0));
  259. }
  260. paths.push(path);
  261. }
  262. // lathe ribbon
  263. var lathe = MeshBuilder.CreateRibbon(name, { pathArray: paths, closeArray: closed, sideOrientation: sideOrientation, updatable: updatable }, scene);
  264. return lathe;
  265. }
  266. public static CreatePlane(name: string, options: { size?: number, width?: number, height?: number, sideOrientation?: number, updatable?: boolean, sourcePlane?: Plane }, scene: Scene): Mesh {
  267. var plane = new Mesh(name, scene);
  268. var vertexData = VertexData.CreatePlane(options);
  269. vertexData.applyToMesh(plane, options.updatable);
  270. if (options.sourcePlane) {
  271. plane.translate(options.sourcePlane.normal, options.sourcePlane.d);
  272. var product = Math.acos(Vector3.Dot(options.sourcePlane.normal, Axis.Z));
  273. var vectorProduct = Vector3.Cross(Axis.Z, options.sourcePlane.normal);
  274. plane.rotate(vectorProduct, product);
  275. }
  276. return plane;
  277. }
  278. public static CreateGround(name: string, options: { width?: number, height?: number, subdivisions?: number, updatable?: boolean }, scene: any): Mesh {
  279. var ground = new GroundMesh(name, scene);
  280. ground._setReady(false);
  281. ground._subdivisions = options.subdivisions || 1;
  282. ground._width = options.width || 1;
  283. ground._height = options.height || 1;
  284. ground._maxX = ground._width / 2;
  285. ground._maxZ = ground._height / 2;
  286. ground._minX = -ground._maxX;
  287. ground._minZ = -ground._maxZ;
  288. var vertexData = VertexData.CreateGround(options);
  289. vertexData.applyToMesh(ground, options.updatable);
  290. ground._setReady(true);
  291. return ground;
  292. }
  293. 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 {
  294. var tiledGround = new Mesh(name, scene);
  295. var vertexData = VertexData.CreateTiledGround(options);
  296. vertexData.applyToMesh(tiledGround, options.updatable);
  297. return tiledGround;
  298. }
  299. 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 {
  300. var width = options.width || 10;
  301. var height = options.height || 10;
  302. var subdivisions = options.subdivisions || 1;
  303. var minHeight = options.minHeight;
  304. var maxHeight = options.maxHeight || 10;
  305. var updatable = options.updatable;
  306. var onReady = options.onReady;
  307. var ground = new GroundMesh(name, scene);
  308. ground._subdivisions = subdivisions;
  309. ground._width = width;
  310. ground._height = height;
  311. ground._maxX = ground._width / 2;
  312. ground._maxZ = ground._height / 2;
  313. ground._minX = -ground._maxX;
  314. ground._minZ = -ground._maxZ;
  315. ground._setReady(false);
  316. var onload = img => {
  317. // Getting height map data
  318. var canvas = document.createElement("canvas");
  319. var context = canvas.getContext("2d");
  320. var bufferWidth = img.width;
  321. var bufferHeight = img.height;
  322. canvas.width = bufferWidth;
  323. canvas.height = bufferHeight;
  324. context.drawImage(img, 0, 0);
  325. // Create VertexData from map data
  326. // Cast is due to wrong definition in lib.d.ts from ts 1.3 - https://github.com/Microsoft/TypeScript/issues/949
  327. var buffer = <Uint8Array>(<any>context.getImageData(0, 0, bufferWidth, bufferHeight).data);
  328. var vertexData = VertexData.CreateGroundFromHeightMap({
  329. width, height,
  330. subdivisions,
  331. minHeight, maxHeight,
  332. buffer, bufferWidth, bufferHeight
  333. });
  334. vertexData.applyToMesh(ground, updatable);
  335. ground._setReady(true);
  336. //execute ready callback, if set
  337. if (onReady) {
  338. onReady(ground);
  339. }
  340. };
  341. Tools.LoadImage(url, onload, () => { }, scene.database);
  342. return ground;
  343. }
  344. 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 {
  345. var path = options.path;
  346. var radius = options.radius || 1;
  347. var tessellation = options.tessellation || 64;
  348. var radiusFunction = options.radiusFunction;
  349. var cap = options.cap || Mesh.NO_CAP;
  350. var updatable = options.updatable;
  351. var sideOrientation = options.sideOrientation || Mesh.DEFAULTSIDE;
  352. var instance = options.instance;
  353. options.arc = (options.arc <= 0 || options.arc > 1) ? 1 : options.arc || 1;
  354. // tube geometry
  355. var tubePathArray = (path, path3D, circlePaths, radius, tessellation, radiusFunction, cap, arc) => {
  356. var tangents = path3D.getTangents();
  357. var normals = path3D.getNormals();
  358. var distances = path3D.getDistances();
  359. var pi2 = Math.PI * 2;
  360. var step = pi2 / tessellation * arc;
  361. var returnRadius: { (i: number, distance: number): number; } = () => radius;
  362. var radiusFunctionFinal: { (i: number, distance: number): number; } = radiusFunction || returnRadius;
  363. var circlePath: Vector3[];
  364. var rad: number;
  365. var normal: Vector3;
  366. var rotated: Vector3;
  367. var rotationMatrix: Matrix = Matrix.Zero();
  368. var index = (cap === Mesh._NO_CAP || cap === Mesh.CAP_END) ? 0 : 2;
  369. for (var i = 0; i < path.length; i++) {
  370. rad = radiusFunctionFinal(i, distances[i]); // current radius
  371. circlePath = Array<Vector3>(); // current circle array
  372. normal = normals[i]; // current normal
  373. for (var t = 0; t < tessellation; t++) {
  374. Matrix.RotationAxisToRef(tangents[i], step * t, rotationMatrix);
  375. rotated = Vector3.TransformCoordinates(normal, rotationMatrix).scaleInPlace(rad).add(path[i]);
  376. circlePath.push(rotated);
  377. }
  378. circlePaths[index] = circlePath;
  379. index++;
  380. }
  381. // cap
  382. var capPath = (nbPoints, pathIndex) => {
  383. var pointCap = Array<Vector3>();
  384. for (var i = 0; i < nbPoints; i++) {
  385. pointCap.push(path[pathIndex]);
  386. }
  387. return pointCap;
  388. };
  389. switch (cap) {
  390. case Mesh.NO_CAP:
  391. break;
  392. case Mesh.CAP_START:
  393. circlePaths[0] = capPath(tessellation, 0);
  394. circlePaths[1] = circlePaths[2].slice(0);
  395. break;
  396. case Mesh.CAP_END:
  397. circlePaths[index] = circlePaths[index - 1].slice(0);
  398. circlePaths[index + 1] = capPath(tessellation, path.length - 1);
  399. break;
  400. case Mesh.CAP_ALL:
  401. circlePaths[0] = capPath(tessellation, 0);
  402. circlePaths[1] = circlePaths[2].slice(0);
  403. circlePaths[index] = circlePaths[index - 1].slice(0);
  404. circlePaths[index + 1] = capPath(tessellation, path.length - 1);
  405. break;
  406. default:
  407. break;
  408. }
  409. return circlePaths;
  410. };
  411. var path3D;
  412. var pathArray;
  413. if (instance) { // tube update
  414. var arc = options.arc || (<any>instance).arc;
  415. path3D = ((<any>instance).path3D).update(path);
  416. pathArray = tubePathArray(path, path3D, (<any>instance).pathArray, radius, (<any>instance).tessellation, radiusFunction, (<any>instance).cap, arc);
  417. instance = MeshBuilder.CreateRibbon(null, { pathArray: pathArray, instance: instance });
  418. (<any>instance).path3D = path3D;
  419. (<any>instance).pathArray = pathArray;
  420. (<any>instance).arc = arc;
  421. return instance;
  422. }
  423. // tube creation
  424. path3D = <any>new Path3D(path);
  425. var newPathArray = new Array<Array<Vector3>>();
  426. cap = (cap < 0 || cap > 3) ? 0 : cap;
  427. pathArray = tubePathArray(path, path3D, newPathArray, radius, tessellation, radiusFunction, cap, options.arc);
  428. var tube = MeshBuilder.CreateRibbon(name, { pathArray: pathArray, closePath: true, closeArray: false, updatable: updatable, sideOrientation: sideOrientation }, scene);
  429. (<any>tube).pathArray = pathArray;
  430. (<any>tube).path3D = path3D;
  431. (<any>tube).tessellation = tessellation;
  432. (<any>tube).cap = cap;
  433. (<any>tube).arc = options.arc;
  434. return tube;
  435. }
  436. 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 {
  437. var polyhedron = new Mesh(name, scene);
  438. var vertexData = VertexData.CreatePolyhedron(options);
  439. vertexData.applyToMesh(polyhedron, options.updatable);
  440. return polyhedron;
  441. }
  442. public static CreateDecal(name: string, sourceMesh: AbstractMesh, options: { position?: Vector3, normal?: Vector3, size?: Vector3, angle?: number }): Mesh {
  443. var indices = sourceMesh.getIndices();
  444. var positions = sourceMesh.getVerticesData(VertexBuffer.PositionKind);
  445. var normals = sourceMesh.getVerticesData(VertexBuffer.NormalKind);
  446. var position = options.position || Vector3.Zero();
  447. var normal = options.normal || Vector3.Up();
  448. var size = options.size || new Vector3(1, 1, 1);
  449. var angle = options.angle || 0;
  450. // Getting correct rotation
  451. if (!normal) {
  452. var target = new Vector3(0, 0, 1);
  453. var camera = sourceMesh.getScene().activeCamera;
  454. var cameraWorldTarget = Vector3.TransformCoordinates(target, camera.getWorldMatrix());
  455. normal = camera.globalPosition.subtract(cameraWorldTarget);
  456. }
  457. var yaw = -Math.atan2(normal.z, normal.x) - Math.PI / 2;
  458. var len = Math.sqrt(normal.x * normal.x + normal.z * normal.z);
  459. var pitch = Math.atan2(normal.y, len);
  460. // Matrix
  461. var decalWorldMatrix = Matrix.RotationYawPitchRoll(yaw, pitch, angle).multiply(Matrix.Translation(position.x, position.y, position.z));
  462. var inverseDecalWorldMatrix = Matrix.Invert(decalWorldMatrix);
  463. var meshWorldMatrix = sourceMesh.getWorldMatrix();
  464. var transformMatrix = meshWorldMatrix.multiply(inverseDecalWorldMatrix);
  465. var vertexData = new VertexData();
  466. vertexData.indices = [];
  467. vertexData.positions = [];
  468. vertexData.normals = [];
  469. vertexData.uvs = [];
  470. var currentVertexDataIndex = 0;
  471. var extractDecalVector3 = (indexId: number): PositionNormalVertex => {
  472. var vertexId = indices[indexId];
  473. var result = new PositionNormalVertex();
  474. result.position = new Vector3(positions[vertexId * 3], positions[vertexId * 3 + 1], positions[vertexId * 3 + 2]);
  475. // Send vector to decal local world
  476. result.position = Vector3.TransformCoordinates(result.position, transformMatrix);
  477. // Get normal
  478. result.normal = new Vector3(normals[vertexId * 3], normals[vertexId * 3 + 1], normals[vertexId * 3 + 2]);
  479. return result;
  480. }; // Inspired by https://github.com/mrdoob/three.js/blob/eee231960882f6f3b6113405f524956145148146/examples/js/geometries/DecalGeometry.js
  481. var clip = (vertices: PositionNormalVertex[], axis: Vector3): PositionNormalVertex[]=> {
  482. if (vertices.length === 0) {
  483. return vertices;
  484. }
  485. var clipSize = 0.5 * Math.abs(Vector3.Dot(size, axis));
  486. var clipVertices = (v0: PositionNormalVertex, v1: PositionNormalVertex): PositionNormalVertex => {
  487. var clipFactor = Vector3.GetClipFactor(v0.position, v1.position, axis, clipSize);
  488. return new PositionNormalVertex(
  489. Vector3.Lerp(v0.position, v1.position, clipFactor),
  490. Vector3.Lerp(v0.normal, v1.normal, clipFactor)
  491. );
  492. };
  493. var result = new Array<PositionNormalVertex>();
  494. for (var index = 0; index < vertices.length; index += 3) {
  495. var v1Out: boolean;
  496. var v2Out: boolean;
  497. var v3Out: boolean;
  498. var total = 0;
  499. var nV1: PositionNormalVertex, nV2: PositionNormalVertex, nV3: PositionNormalVertex, nV4: PositionNormalVertex;
  500. var d1 = Vector3.Dot(vertices[index].position, axis) - clipSize;
  501. var d2 = Vector3.Dot(vertices[index + 1].position, axis) - clipSize;
  502. var d3 = Vector3.Dot(vertices[index + 2].position, axis) - clipSize;
  503. v1Out = d1 > 0;
  504. v2Out = d2 > 0;
  505. v3Out = d3 > 0;
  506. total = (v1Out ? 1 : 0) + (v2Out ? 1 : 0) + (v3Out ? 1 : 0);
  507. switch (total) {
  508. case 0:
  509. result.push(vertices[index]);
  510. result.push(vertices[index + 1]);
  511. result.push(vertices[index + 2]);
  512. break;
  513. case 1:
  514. if (v1Out) {
  515. nV1 = vertices[index + 1];
  516. nV2 = vertices[index + 2];
  517. nV3 = clipVertices(vertices[index], nV1);
  518. nV4 = clipVertices(vertices[index], nV2);
  519. }
  520. if (v2Out) {
  521. nV1 = vertices[index];
  522. nV2 = vertices[index + 2];
  523. nV3 = clipVertices(vertices[index + 1], nV1);
  524. nV4 = clipVertices(vertices[index + 1], nV2);
  525. result.push(nV3);
  526. result.push(nV2.clone());
  527. result.push(nV1.clone());
  528. result.push(nV2.clone());
  529. result.push(nV3.clone());
  530. result.push(nV4);
  531. break;
  532. }
  533. if (v3Out) {
  534. nV1 = vertices[index];
  535. nV2 = vertices[index + 1];
  536. nV3 = clipVertices(vertices[index + 2], nV1);
  537. nV4 = clipVertices(vertices[index + 2], nV2);
  538. }
  539. result.push(nV1.clone());
  540. result.push(nV2.clone());
  541. result.push(nV3);
  542. result.push(nV4);
  543. result.push(nV3.clone());
  544. result.push(nV2.clone());
  545. break;
  546. case 2:
  547. if (!v1Out) {
  548. nV1 = vertices[index].clone();
  549. nV2 = clipVertices(nV1, vertices[index + 1]);
  550. nV3 = clipVertices(nV1, vertices[index + 2]);
  551. result.push(nV1);
  552. result.push(nV2);
  553. result.push(nV3);
  554. }
  555. if (!v2Out) {
  556. nV1 = vertices[index + 1].clone();
  557. nV2 = clipVertices(nV1, vertices[index + 2]);
  558. nV3 = clipVertices(nV1, vertices[index]);
  559. result.push(nV1);
  560. result.push(nV2);
  561. result.push(nV3);
  562. }
  563. if (!v3Out) {
  564. nV1 = vertices[index + 2].clone();
  565. nV2 = clipVertices(nV1, vertices[index]);
  566. nV3 = clipVertices(nV1, vertices[index + 1]);
  567. result.push(nV1);
  568. result.push(nV2);
  569. result.push(nV3);
  570. }
  571. break;
  572. case 3:
  573. break;
  574. }
  575. }
  576. return result;
  577. };
  578. for (var index = 0; index < indices.length; index += 3) {
  579. var faceVertices = new Array<PositionNormalVertex>();
  580. faceVertices.push(extractDecalVector3(index));
  581. faceVertices.push(extractDecalVector3(index + 1));
  582. faceVertices.push(extractDecalVector3(index + 2));
  583. // Clip
  584. faceVertices = clip(faceVertices, new Vector3(1, 0, 0));
  585. faceVertices = clip(faceVertices, new Vector3(-1, 0, 0));
  586. faceVertices = clip(faceVertices, new Vector3(0, 1, 0));
  587. faceVertices = clip(faceVertices, new Vector3(0, -1, 0));
  588. faceVertices = clip(faceVertices, new Vector3(0, 0, 1));
  589. faceVertices = clip(faceVertices, new Vector3(0, 0, -1));
  590. if (faceVertices.length === 0) {
  591. continue;
  592. }
  593. // Add UVs and get back to world
  594. for (var vIndex = 0; vIndex < faceVertices.length; vIndex++) {
  595. var vertex = faceVertices[vIndex];
  596. //TODO check for Int32Array
  597. (<number[]>vertexData.indices).push(currentVertexDataIndex);
  598. vertex.position.toArray(vertexData.positions, currentVertexDataIndex * 3);
  599. vertex.normal.toArray(vertexData.normals, currentVertexDataIndex * 3);
  600. (<number[]>vertexData.uvs).push(0.5 + vertex.position.x / size.x);
  601. (<number[]>vertexData.uvs).push(0.5 + vertex.position.y / size.y);
  602. currentVertexDataIndex++;
  603. }
  604. }
  605. // Return mesh
  606. var decal = new Mesh(name, sourceMesh.getScene());
  607. vertexData.applyToMesh(decal);
  608. decal.position = position.clone();
  609. decal.rotation = new Vector3(pitch, yaw, angle);
  610. return decal;
  611. }
  612. // Privates
  613. 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 {
  614. // extrusion geometry
  615. var extrusionPathArray = (shape, curve, path3D, shapePaths, scale, rotation, scaleFunction, rotateFunction, cap, custom) => {
  616. var tangents = path3D.getTangents();
  617. var normals = path3D.getNormals();
  618. var binormals = path3D.getBinormals();
  619. var distances = path3D.getDistances();
  620. var angle = 0;
  621. var returnScale: { (i: number, distance: number): number; } = () => { return scale; };
  622. var returnRotation: { (i: number, distance: number): number; } = () => { return rotation; };
  623. var rotate: { (i: number, distance: number): number; } = custom ? rotateFunction : returnRotation;
  624. var scl: { (i: number, distance: number): number; } = custom ? scaleFunction : returnScale;
  625. var index = (cap === Mesh.NO_CAP || cap === Mesh.CAP_END) ? 0 : 2;
  626. var rotationMatrix: Matrix = Matrix.Zero();
  627. for (var i = 0; i < curve.length; i++) {
  628. var shapePath = new Array<Vector3>();
  629. var angleStep = rotate(i, distances[i]);
  630. var scaleRatio = scl(i, distances[i]);
  631. for (var p = 0; p < shape.length; p++) {
  632. Matrix.RotationAxisToRef(tangents[i], angle, rotationMatrix);
  633. var planed = ((tangents[i].scale(shape[p].z)).add(normals[i].scale(shape[p].x)).add(binormals[i].scale(shape[p].y)));
  634. var rotated = Vector3.TransformCoordinates(planed, rotationMatrix).scaleInPlace(scaleRatio).add(curve[i]);
  635. shapePath.push(rotated);
  636. }
  637. shapePaths[index] = shapePath;
  638. angle += angleStep;
  639. index++;
  640. }
  641. // cap
  642. var capPath = shapePath => {
  643. var pointCap = Array<Vector3>();
  644. var barycenter = Vector3.Zero();
  645. var i: number;
  646. for (i = 0; i < shapePath.length; i++) {
  647. barycenter.addInPlace(shapePath[i]);
  648. }
  649. barycenter.scaleInPlace(1 / shapePath.length);
  650. for (i = 0; i < shapePath.length; i++) {
  651. pointCap.push(barycenter);
  652. }
  653. return pointCap;
  654. };
  655. switch (cap) {
  656. case Mesh.NO_CAP:
  657. break;
  658. case Mesh.CAP_START:
  659. shapePaths[0] = capPath(shapePaths[2]);
  660. shapePaths[1] = shapePaths[2].slice(0);
  661. break;
  662. case Mesh.CAP_END:
  663. shapePaths[index] = shapePaths[index - 1];
  664. shapePaths[index + 1] = capPath(shapePaths[index - 1]);
  665. break;
  666. case Mesh.CAP_ALL:
  667. shapePaths[0] = capPath(shapePaths[2]);
  668. shapePaths[1] = shapePaths[2].slice(0);
  669. shapePaths[index] = shapePaths[index - 1];
  670. shapePaths[index + 1] = capPath(shapePaths[index - 1]);
  671. break;
  672. default:
  673. break;
  674. }
  675. return shapePaths;
  676. };
  677. var path3D;
  678. var pathArray;
  679. if (instance) { // instance update
  680. path3D = ((<any>instance).path3D).update(curve);
  681. pathArray = extrusionPathArray(shape, curve, (<any>instance).path3D, (<any>instance).pathArray, scale, rotation, scaleFunction, rotateFunction, (<any>instance).cap, custom);
  682. instance = Mesh.CreateRibbon(null, pathArray, null, null, null, null, null, null, instance);
  683. return instance;
  684. }
  685. // extruded shape creation
  686. path3D = <any>new Path3D(curve);
  687. var newShapePaths = new Array<Array<Vector3>>();
  688. cap = (cap < 0 || cap > 3) ? 0 : cap;
  689. pathArray = extrusionPathArray(shape, curve, path3D, newShapePaths, scale, rotation, scaleFunction, rotateFunction, cap, custom);
  690. var extrudedGeneric = Mesh.CreateRibbon(name, pathArray, rbCA, rbCP, 0, scene, updtbl, side);
  691. (<any>extrudedGeneric).pathArray = pathArray;
  692. (<any>extrudedGeneric).path3D = path3D;
  693. (<any>extrudedGeneric).cap = cap;
  694. return extrudedGeneric;
  695. }
  696. }
  697. }