babylon.meshBuilder.js 37 KB

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