babylon.solidParticleSystem.js 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829
  1. var BABYLON;
  2. (function (BABYLON) {
  3. /**
  4. * Full documentation here : http://doc.babylonjs.com/tutorials/Solid_Particle_System
  5. */
  6. var SolidParticleSystem = (function () {
  7. /**
  8. * Creates a SPS (Solid Particle System) object.
  9. * @param name the SPS name, this will be the underlying mesh name
  10. * @param scene the scene in which the SPS is added
  11. * @param options "updatable" (default true) : if the SPS must be updatable or immutable, "isPickable" (default false) : if the solid particles must be pickable
  12. */
  13. function SolidParticleSystem(name, scene, options) {
  14. // public members
  15. /**
  16. * The SPS array of Solid Particle objects. Just access each particle as with any classic array.
  17. * Example : var p = SPS.particles[i];
  18. */
  19. this.particles = new Array();
  20. /**
  21. * The SPS total number of particles. Read only. Use SPS.counter instead if you need to set your own value.
  22. */
  23. this.nbParticles = 0;
  24. /**
  25. * If the particles must ever face the camera (default false). Useful for planar particles.
  26. */
  27. this.billboard = false;
  28. /**
  29. * This a counter ofr your own usage. It's not set by any SPS functions.
  30. */
  31. this.counter = 0;
  32. /**
  33. * This empty object is intended to store some SPS specific or temporary values in order to lower the Garbage Collector activity.
  34. * Please read : http://doc.babylonjs.com/tutorials/Solid_Particle_System#garbage-collector-concerns
  35. */
  36. this.vars = {};
  37. this._positions = new Array();
  38. this._indices = new Array();
  39. this._normals = new Array();
  40. this._colors = new Array();
  41. this._uvs = new Array();
  42. this._index = 0; // indices index
  43. this._updatable = true;
  44. this._pickable = false;
  45. this._isVisibilityBoxLocked = false;
  46. this._alwaysVisible = false;
  47. this._shapeCounter = 0;
  48. this._copy = new BABYLON.SolidParticle(null, null, null, null, null);
  49. this._color = new BABYLON.Color4(0, 0, 0, 0);
  50. this._computeParticleColor = true;
  51. this._computeParticleTexture = true;
  52. this._computeParticleRotation = true;
  53. this._computeParticleVertex = false;
  54. this._computeBoundingBox = false;
  55. this._cam_axisZ = BABYLON.Vector3.Zero();
  56. this._cam_axisY = BABYLON.Vector3.Zero();
  57. this._cam_axisX = BABYLON.Vector3.Zero();
  58. this._axisX = BABYLON.Axis.X;
  59. this._axisY = BABYLON.Axis.Y;
  60. this._axisZ = BABYLON.Axis.Z;
  61. this._fakeCamPos = BABYLON.Vector3.Zero();
  62. this._rotMatrix = new BABYLON.Matrix();
  63. this._invertMatrix = new BABYLON.Matrix();
  64. this._rotated = BABYLON.Vector3.Zero();
  65. this._quaternion = new BABYLON.Quaternion();
  66. this._vertex = BABYLON.Vector3.Zero();
  67. this._normal = BABYLON.Vector3.Zero();
  68. this._yaw = 0.0;
  69. this._pitch = 0.0;
  70. this._roll = 0.0;
  71. this._halfroll = 0.0;
  72. this._halfpitch = 0.0;
  73. this._halfyaw = 0.0;
  74. this._sinRoll = 0.0;
  75. this._cosRoll = 0.0;
  76. this._sinPitch = 0.0;
  77. this._cosPitch = 0.0;
  78. this._sinYaw = 0.0;
  79. this._cosYaw = 0.0;
  80. this._w = 0.0;
  81. this._minimum = BABYLON.Tmp.Vector3[0];
  82. this._maximum = BABYLON.Tmp.Vector3[1];
  83. this.name = name;
  84. this._scene = scene;
  85. this._camera = scene.activeCamera;
  86. this._pickable = options ? options.isPickable : false;
  87. if (options && options.updatable) {
  88. this._updatable = options.updatable;
  89. }
  90. else {
  91. this._updatable = true;
  92. }
  93. if (this._pickable) {
  94. this.pickedParticles = [];
  95. }
  96. }
  97. /**
  98. * Builds the SPS underlying mesh. Returns a standard Mesh.
  99. * If no model shape was added to the SPS, the return mesh is only a single triangular plane.
  100. */
  101. SolidParticleSystem.prototype.buildMesh = function () {
  102. if (this.nbParticles === 0) {
  103. var triangle = BABYLON.MeshBuilder.CreateDisc("", { radius: 1, tessellation: 3 }, this._scene);
  104. this.addShape(triangle, 1);
  105. triangle.dispose();
  106. }
  107. this._positions32 = new Float32Array(this._positions);
  108. this._uvs32 = new Float32Array(this._uvs);
  109. this._colors32 = new Float32Array(this._colors);
  110. BABYLON.VertexData.ComputeNormals(this._positions32, this._indices, this._normals);
  111. this._normals32 = new Float32Array(this._normals);
  112. this._fixedNormal32 = new Float32Array(this._normals);
  113. var vertexData = new BABYLON.VertexData();
  114. vertexData.set(this._positions32, BABYLON.VertexBuffer.PositionKind);
  115. vertexData.indices = this._indices;
  116. vertexData.set(this._normals32, BABYLON.VertexBuffer.NormalKind);
  117. if (this._uvs32) {
  118. vertexData.set(this._uvs32, BABYLON.VertexBuffer.UVKind);
  119. ;
  120. }
  121. if (this._colors32) {
  122. vertexData.set(this._colors32, BABYLON.VertexBuffer.ColorKind);
  123. }
  124. var mesh = new BABYLON.Mesh(this.name, this._scene);
  125. vertexData.applyToMesh(mesh, this._updatable);
  126. this.mesh = mesh;
  127. this.mesh.isPickable = this._pickable;
  128. // free memory
  129. this._positions = null;
  130. this._normals = null;
  131. this._uvs = null;
  132. this._colors = null;
  133. if (!this._updatable) {
  134. this.particles.length = 0;
  135. }
  136. return mesh;
  137. };
  138. /**
  139. * Digests the mesh and generates as many solid particles in the system as wanted.
  140. * These particles will have the same geometry than the mesh parts and will be positioned at the same localisation than the mesh original places.
  141. * Thus the particles generated from digest() have their property "positiion" yet set.
  142. * @param mesh the mesh to be digested
  143. * @param facetNb the number of mesh facets per particle (optional, default 1), this parameter is overriden by the parameter "number" if any
  144. * @param number the wanted number of particles : each particle is built with mesh_total_facets / number facets (optional)
  145. */
  146. SolidParticleSystem.prototype.digest = function (mesh, options) {
  147. var size = (options && options.facetNb) || 1;
  148. var number = (options && options.number);
  149. var meshPos = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
  150. var meshInd = mesh.getIndices();
  151. var meshUV = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
  152. var meshCol = mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
  153. var f = 0; // facet counter
  154. var totalFacets = meshInd.length / 3; // a facet is a triangle, so 3 indices
  155. // compute size from number
  156. if (number) {
  157. number = (number > totalFacets) ? totalFacets : number;
  158. size = Math.round(totalFacets / number);
  159. }
  160. else {
  161. size = (size > totalFacets) ? totalFacets : size;
  162. }
  163. var facetPos = []; // submesh positions
  164. var facetInd = []; // submesh indices
  165. var facetUV = []; // submesh UV
  166. var facetCol = []; // submesh colors
  167. var barycenter = BABYLON.Tmp.Vector3[0];
  168. while (f < totalFacets) {
  169. if (f > totalFacets - size) {
  170. size = totalFacets - f;
  171. }
  172. // reset temp arrays
  173. facetPos.length = 0;
  174. facetInd.length = 0;
  175. facetUV.length = 0;
  176. facetCol.length = 0;
  177. // iterate over "size" facets
  178. var fi = 0;
  179. for (var j = f * 3; j < (f + size) * 3; j++) {
  180. facetInd.push(fi);
  181. var i = meshInd[j];
  182. facetPos.push(meshPos[i * 3], meshPos[i * 3 + 1], meshPos[i * 3 + 2]);
  183. if (meshUV) {
  184. facetUV.push(meshUV[i * 2], meshUV[i * 2 + 1]);
  185. }
  186. if (meshCol) {
  187. facetCol.push(meshCol[i * 4], meshCol[i * 4 + 1], meshCol[i * 4 + 2], meshCol[i * 4 + 3]);
  188. }
  189. fi++;
  190. }
  191. // create a model shape for each single particle
  192. var idx = this.nbParticles;
  193. var shape = this._posToShape(facetPos);
  194. var shapeUV = this._uvsToShapeUV(facetUV);
  195. // compute the barycenter of the shape
  196. var v;
  197. for (v = 0; v < shape.length; v++) {
  198. barycenter.addInPlace(shape[v]);
  199. }
  200. barycenter.scaleInPlace(1 / shape.length);
  201. // shift the shape from its barycenter to the origin
  202. for (v = 0; v < shape.length; v++) {
  203. shape[v].subtractInPlace(barycenter);
  204. }
  205. var modelShape = new BABYLON.ModelShape(this._shapeCounter, shape, shapeUV, null, null);
  206. // add the particle in the SPS
  207. this._meshBuilder(this._index, shape, this._positions, facetInd, this._indices, facetUV, this._uvs, facetCol, this._colors, idx, 0, null);
  208. this._addParticle(idx, this._positions.length, modelShape, this._shapeCounter, 0);
  209. // initialize the particle position
  210. this.particles[this.nbParticles].position.addInPlace(barycenter);
  211. this._index += shape.length;
  212. idx++;
  213. this.nbParticles++;
  214. this._shapeCounter++;
  215. f += size;
  216. }
  217. };
  218. //reset copy
  219. SolidParticleSystem.prototype._resetCopy = function () {
  220. this._copy.position.x = 0;
  221. this._copy.position.y = 0;
  222. this._copy.position.z = 0;
  223. this._copy.rotation.x = 0;
  224. this._copy.rotation.y = 0;
  225. this._copy.rotation.z = 0;
  226. this._copy.quaternion = null;
  227. this._copy.scale.x = 1;
  228. this._copy.scale.y = 1;
  229. this._copy.scale.z = 1;
  230. this._copy.uvs.x = 0;
  231. this._copy.uvs.y = 0;
  232. this._copy.uvs.z = 1;
  233. this._copy.uvs.w = 1;
  234. this._copy.color = null;
  235. };
  236. // _meshBuilder : inserts the shape model in the global SPS mesh
  237. SolidParticleSystem.prototype._meshBuilder = function (p, shape, positions, meshInd, indices, meshUV, uvs, meshCol, colors, idx, idxInShape, options) {
  238. var i;
  239. var u = 0;
  240. var c = 0;
  241. this._resetCopy();
  242. if (options && options.positionFunction) {
  243. options.positionFunction(this._copy, idx, idxInShape);
  244. }
  245. if (this._copy.quaternion) {
  246. this._quaternion.x = this._copy.quaternion.x;
  247. this._quaternion.y = this._copy.quaternion.y;
  248. this._quaternion.z = this._copy.quaternion.z;
  249. this._quaternion.w = this._copy.quaternion.w;
  250. }
  251. else {
  252. this._yaw = this._copy.rotation.y;
  253. this._pitch = this._copy.rotation.x;
  254. this._roll = this._copy.rotation.z;
  255. this._quaternionRotationYPR();
  256. }
  257. this._quaternionToRotationMatrix();
  258. for (i = 0; i < shape.length; i++) {
  259. this._vertex.x = shape[i].x;
  260. this._vertex.y = shape[i].y;
  261. this._vertex.z = shape[i].z;
  262. if (options && options.vertexFunction) {
  263. options.vertexFunction(this._copy, this._vertex, i);
  264. }
  265. this._vertex.x *= this._copy.scale.x;
  266. this._vertex.y *= this._copy.scale.y;
  267. this._vertex.z *= this._copy.scale.z;
  268. BABYLON.Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
  269. positions.push(this._copy.position.x + this._rotated.x, this._copy.position.y + this._rotated.y, this._copy.position.z + this._rotated.z);
  270. if (meshUV) {
  271. uvs.push((this._copy.uvs.z - this._copy.uvs.x) * meshUV[u] + this._copy.uvs.x, (this._copy.uvs.w - this._copy.uvs.y) * meshUV[u + 1] + this._copy.uvs.y);
  272. u += 2;
  273. }
  274. if (this._copy.color) {
  275. this._color = this._copy.color;
  276. }
  277. else if (meshCol && meshCol[c]) {
  278. this._color.r = meshCol[c];
  279. this._color.g = meshCol[c + 1];
  280. this._color.b = meshCol[c + 2];
  281. this._color.a = meshCol[c + 3];
  282. }
  283. else {
  284. this._color.r = 1;
  285. this._color.g = 1;
  286. this._color.b = 1;
  287. this._color.a = 1;
  288. }
  289. colors.push(this._color.r, this._color.g, this._color.b, this._color.a);
  290. c += 4;
  291. }
  292. for (i = 0; i < meshInd.length; i++) {
  293. indices.push(p + meshInd[i]);
  294. }
  295. if (this._pickable) {
  296. var nbfaces = meshInd.length / 3;
  297. for (i = 0; i < nbfaces; i++) {
  298. this.pickedParticles.push({ idx: idx, faceId: i });
  299. }
  300. }
  301. };
  302. // returns a shape array from positions array
  303. SolidParticleSystem.prototype._posToShape = function (positions) {
  304. var shape = [];
  305. for (var i = 0; i < positions.length; i += 3) {
  306. shape.push(new BABYLON.Vector3(positions[i], positions[i + 1], positions[i + 2]));
  307. }
  308. return shape;
  309. };
  310. // returns a shapeUV array from a Vector4 uvs
  311. SolidParticleSystem.prototype._uvsToShapeUV = function (uvs) {
  312. var shapeUV = [];
  313. if (uvs) {
  314. for (var i = 0; i < uvs.length; i++)
  315. shapeUV.push(uvs[i]);
  316. }
  317. return shapeUV;
  318. };
  319. // adds a new particle object in the particles array
  320. SolidParticleSystem.prototype._addParticle = function (idx, idxpos, model, shapeId, idxInShape) {
  321. this.particles.push(new BABYLON.SolidParticle(idx, idxpos, model, shapeId, idxInShape));
  322. };
  323. /**
  324. * Adds some particles to the SPS from the model shape.
  325. * Please read the doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#create-an-immutable-sps
  326. * @param mesh any Mesh object that will be used as a model for the solid particles.
  327. * @param nb the number of particles to be created from this model
  328. * @param options positionFunction is an optional javascript function to called for each particle on SPS creation. vertexFunction an optional javascript function to called for each vertex of each particle on SPS creation
  329. */
  330. SolidParticleSystem.prototype.addShape = function (mesh, nb, options) {
  331. var meshPos = mesh.getVerticesData(BABYLON.VertexBuffer.PositionKind);
  332. var meshInd = mesh.getIndices();
  333. var meshUV = mesh.getVerticesData(BABYLON.VertexBuffer.UVKind);
  334. var meshCol = mesh.getVerticesData(BABYLON.VertexBuffer.ColorKind);
  335. var shape = this._posToShape(meshPos);
  336. var shapeUV = this._uvsToShapeUV(meshUV);
  337. var posfunc = options ? options.positionFunction : null;
  338. var vtxfunc = options ? options.vertexFunction : null;
  339. var modelShape = new BABYLON.ModelShape(this._shapeCounter, shape, shapeUV, posfunc, vtxfunc);
  340. // particles
  341. var idx = this.nbParticles;
  342. for (var i = 0; i < nb; i++) {
  343. this._meshBuilder(this._index, shape, this._positions, meshInd, this._indices, meshUV, this._uvs, meshCol, this._colors, idx, i, options);
  344. if (this._updatable) {
  345. this._addParticle(idx, this._positions.length, modelShape, this._shapeCounter, i);
  346. }
  347. this._index += shape.length;
  348. idx++;
  349. }
  350. this.nbParticles += nb;
  351. this._shapeCounter++;
  352. return this._shapeCounter - 1;
  353. };
  354. // rebuilds a particle back to its just built status : if needed, recomputes the custom positions and vertices
  355. SolidParticleSystem.prototype._rebuildParticle = function (particle) {
  356. this._resetCopy();
  357. if (particle._model._positionFunction) {
  358. particle._model._positionFunction(this._copy, particle.idx, particle.idxInShape);
  359. }
  360. if (this._copy.quaternion) {
  361. this._quaternion.x = this._copy.quaternion.x;
  362. this._quaternion.y = this._copy.quaternion.y;
  363. this._quaternion.z = this._copy.quaternion.z;
  364. this._quaternion.w = this._copy.quaternion.w;
  365. }
  366. else {
  367. this._yaw = this._copy.rotation.y;
  368. this._pitch = this._copy.rotation.x;
  369. this._roll = this._copy.rotation.z;
  370. this._quaternionRotationYPR();
  371. }
  372. this._quaternionToRotationMatrix();
  373. this._shape = particle._model._shape;
  374. for (var pt = 0; pt < this._shape.length; pt++) {
  375. this._vertex.x = this._shape[pt].x;
  376. this._vertex.y = this._shape[pt].y;
  377. this._vertex.z = this._shape[pt].z;
  378. if (particle._model._vertexFunction) {
  379. particle._model._vertexFunction(this._copy, this._vertex, pt); // recall to stored vertexFunction
  380. }
  381. this._vertex.x *= this._copy.scale.x;
  382. this._vertex.y *= this._copy.scale.y;
  383. this._vertex.z *= this._copy.scale.z;
  384. BABYLON.Vector3.TransformCoordinatesToRef(this._vertex, this._rotMatrix, this._rotated);
  385. this._positions32[particle._pos + pt * 3] = this._copy.position.x + this._rotated.x;
  386. this._positions32[particle._pos + pt * 3 + 1] = this._copy.position.y + this._rotated.y;
  387. this._positions32[particle._pos + pt * 3 + 2] = this._copy.position.z + this._rotated.z;
  388. }
  389. particle.position.x = 0;
  390. particle.position.y = 0;
  391. particle.position.z = 0;
  392. particle.rotation.x = 0;
  393. particle.rotation.y = 0;
  394. particle.rotation.z = 0;
  395. particle.quaternion = null;
  396. particle.scale.x = 1;
  397. particle.scale.y = 1;
  398. particle.scale.z = 1;
  399. };
  400. /**
  401. * Rebuilds the whole mesh and updates the VBO : custom positions and vertices are recomputed if needed.
  402. */
  403. SolidParticleSystem.prototype.rebuildMesh = function () {
  404. for (var p = 0; p < this.particles.length; p++) {
  405. this._rebuildParticle(this.particles[p]);
  406. }
  407. this.mesh.updateVerticesData(BABYLON.VertexBuffer.PositionKind, this._positions32, false, false);
  408. };
  409. /**
  410. * Sets all the particles : this method actually really updates the mesh according to the particle positions, rotations, colors, textures, etc.
  411. * This method calls updateParticle() for each particles of the SPS.
  412. * For an animated SPS, it is usually called within the render loop.
  413. * @param start (default 0) the particle index in the particle array where to start to compute the particle property values
  414. * @param end (default nbParticle - 1) the particle index in the particle array where to stop to compute the particle property values
  415. * @param update (default true) if the mesh must be finally updated on this call after all the particle computations.
  416. */
  417. SolidParticleSystem.prototype.setParticles = function (start, end, update) {
  418. if (start === void 0) { start = 0; }
  419. if (end === void 0) { end = this.nbParticles - 1; }
  420. if (update === void 0) { update = true; }
  421. if (!this._updatable) {
  422. return;
  423. }
  424. // custom beforeUpdate
  425. this.beforeUpdateParticles(start, end, update);
  426. this._cam_axisX.x = 1;
  427. this._cam_axisX.y = 0;
  428. this._cam_axisX.z = 0;
  429. this._cam_axisY.x = 0;
  430. this._cam_axisY.y = 1;
  431. this._cam_axisY.z = 0;
  432. this._cam_axisZ.x = 0;
  433. this._cam_axisZ.y = 0;
  434. this._cam_axisZ.z = 1;
  435. // if the particles will always face the camera
  436. if (this.billboard) {
  437. // compute a fake camera position : un-rotate the camera position by the current mesh rotation
  438. this._yaw = this.mesh.rotation.y;
  439. this._pitch = this.mesh.rotation.x;
  440. this._roll = this.mesh.rotation.z;
  441. this._quaternionRotationYPR();
  442. this._quaternionToRotationMatrix();
  443. this._rotMatrix.invertToRef(this._invertMatrix);
  444. BABYLON.Vector3.TransformCoordinatesToRef(this._camera.globalPosition, this._invertMatrix, this._fakeCamPos);
  445. // set two orthogonal vectors (_cam_axisX and and _cam_axisY) to the cam-mesh axis (_cam_axisZ)
  446. (this._fakeCamPos).subtractToRef(this.mesh.position, this._cam_axisZ);
  447. BABYLON.Vector3.CrossToRef(this._cam_axisZ, this._axisX, this._cam_axisY);
  448. BABYLON.Vector3.CrossToRef(this._cam_axisZ, this._cam_axisY, this._cam_axisX);
  449. this._cam_axisY.normalize();
  450. this._cam_axisX.normalize();
  451. this._cam_axisZ.normalize();
  452. }
  453. BABYLON.Matrix.IdentityToRef(this._rotMatrix);
  454. var idx = 0;
  455. var index = 0;
  456. var colidx = 0;
  457. var colorIndex = 0;
  458. var uvidx = 0;
  459. var uvIndex = 0;
  460. if (this._computeBoundingBox) {
  461. BABYLON.Vector3.FromFloatsToRef(Number.MAX_VALUE, Number.MAX_VALUE, Number.MAX_VALUE, this._minimum);
  462. BABYLON.Vector3.FromFloatsToRef(-Number.MAX_VALUE, -Number.MAX_VALUE, -Number.MAX_VALUE, this._maximum);
  463. }
  464. // particle loop
  465. end = (end > this.nbParticles - 1) ? this.nbParticles - 1 : end;
  466. for (var p = start; p <= end; p++) {
  467. this._particle = this.particles[p];
  468. this._shape = this._particle._model._shape;
  469. this._shapeUV = this._particle._model._shapeUV;
  470. // call to custom user function to update the particle properties
  471. this.updateParticle(this._particle);
  472. // particle rotation matrix
  473. if (this.billboard) {
  474. this._particle.rotation.x = 0.0;
  475. this._particle.rotation.y = 0.0;
  476. }
  477. if (this._computeParticleRotation) {
  478. if (this._particle.quaternion) {
  479. this._quaternion.x = this._particle.quaternion.x;
  480. this._quaternion.y = this._particle.quaternion.y;
  481. this._quaternion.z = this._particle.quaternion.z;
  482. this._quaternion.w = this._particle.quaternion.w;
  483. }
  484. else {
  485. this._yaw = this._particle.rotation.y;
  486. this._pitch = this._particle.rotation.x;
  487. this._roll = this._particle.rotation.z;
  488. this._quaternionRotationYPR();
  489. }
  490. this._quaternionToRotationMatrix();
  491. }
  492. for (var pt = 0; pt < this._shape.length; pt++) {
  493. idx = index + pt * 3;
  494. colidx = colorIndex + pt * 4;
  495. uvidx = uvIndex + pt * 2;
  496. this._vertex.x = this._shape[pt].x;
  497. this._vertex.y = this._shape[pt].y;
  498. this._vertex.z = this._shape[pt].z;
  499. if (this._computeParticleVertex) {
  500. this.updateParticleVertex(this._particle, this._vertex, pt);
  501. }
  502. // positions
  503. this._vertex.x *= this._particle.scale.x;
  504. this._vertex.y *= this._particle.scale.y;
  505. this._vertex.z *= this._particle.scale.z;
  506. this._w = (this._vertex.x * this._rotMatrix.m[3]) + (this._vertex.y * this._rotMatrix.m[7]) + (this._vertex.z * this._rotMatrix.m[11]) + this._rotMatrix.m[15];
  507. this._rotated.x = ((this._vertex.x * this._rotMatrix.m[0]) + (this._vertex.y * this._rotMatrix.m[4]) + (this._vertex.z * this._rotMatrix.m[8]) + this._rotMatrix.m[12]) / this._w;
  508. this._rotated.y = ((this._vertex.x * this._rotMatrix.m[1]) + (this._vertex.y * this._rotMatrix.m[5]) + (this._vertex.z * this._rotMatrix.m[9]) + this._rotMatrix.m[13]) / this._w;
  509. this._rotated.z = ((this._vertex.x * this._rotMatrix.m[2]) + (this._vertex.y * this._rotMatrix.m[6]) + (this._vertex.z * this._rotMatrix.m[10]) + this._rotMatrix.m[14]) / this._w;
  510. this._positions32[idx] = this._particle.position.x + this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
  511. this._positions32[idx + 1] = this._particle.position.y + this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
  512. this._positions32[idx + 2] = this._particle.position.z + this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
  513. if (this._computeBoundingBox) {
  514. if (this._positions32[idx] < this._minimum.x) {
  515. this._minimum.x = this._positions32[idx];
  516. }
  517. if (this._positions32[idx] > this._maximum.x) {
  518. this._maximum.x = this._positions32[idx];
  519. }
  520. if (this._positions32[idx + 1] < this._minimum.y) {
  521. this._minimum.y = this._positions32[idx + 1];
  522. }
  523. if (this._positions32[idx + 1] > this._maximum.y) {
  524. this._maximum.y = this._positions32[idx + 1];
  525. }
  526. if (this._positions32[idx + 2] < this._minimum.z) {
  527. this._minimum.z = this._positions32[idx + 2];
  528. }
  529. if (this._positions32[idx + 2] > this._maximum.z) {
  530. this._maximum.z = this._positions32[idx + 2];
  531. }
  532. }
  533. // normals : if the particles can't be morphed then just rotate the normals
  534. if (!this._computeParticleVertex && !this.billboard) {
  535. this._normal.x = this._fixedNormal32[idx];
  536. this._normal.y = this._fixedNormal32[idx + 1];
  537. this._normal.z = this._fixedNormal32[idx + 2];
  538. this._w = (this._normal.x * this._rotMatrix.m[3]) + (this._normal.y * this._rotMatrix.m[7]) + (this._normal.z * this._rotMatrix.m[11]) + this._rotMatrix.m[15];
  539. this._rotated.x = ((this._normal.x * this._rotMatrix.m[0]) + (this._normal.y * this._rotMatrix.m[4]) + (this._normal.z * this._rotMatrix.m[8]) + this._rotMatrix.m[12]) / this._w;
  540. this._rotated.y = ((this._normal.x * this._rotMatrix.m[1]) + (this._normal.y * this._rotMatrix.m[5]) + (this._normal.z * this._rotMatrix.m[9]) + this._rotMatrix.m[13]) / this._w;
  541. this._rotated.z = ((this._normal.x * this._rotMatrix.m[2]) + (this._normal.y * this._rotMatrix.m[6]) + (this._normal.z * this._rotMatrix.m[10]) + this._rotMatrix.m[14]) / this._w;
  542. this._normals32[idx] = this._cam_axisX.x * this._rotated.x + this._cam_axisY.x * this._rotated.y + this._cam_axisZ.x * this._rotated.z;
  543. this._normals32[idx + 1] = this._cam_axisX.y * this._rotated.x + this._cam_axisY.y * this._rotated.y + this._cam_axisZ.y * this._rotated.z;
  544. this._normals32[idx + 2] = this._cam_axisX.z * this._rotated.x + this._cam_axisY.z * this._rotated.y + this._cam_axisZ.z * this._rotated.z;
  545. }
  546. if (this._computeParticleColor) {
  547. this._colors32[colidx] = this._particle.color.r;
  548. this._colors32[colidx + 1] = this._particle.color.g;
  549. this._colors32[colidx + 2] = this._particle.color.b;
  550. this._colors32[colidx + 3] = this._particle.color.a;
  551. }
  552. if (this._computeParticleTexture) {
  553. this._uvs32[uvidx] = this._shapeUV[pt * 2] * (this._particle.uvs.z - this._particle.uvs.x) + this._particle.uvs.x;
  554. this._uvs32[uvidx + 1] = this._shapeUV[pt * 2 + 1] * (this._particle.uvs.w - this._particle.uvs.y) + this._particle.uvs.y;
  555. }
  556. }
  557. index = idx + 3;
  558. colorIndex = colidx + 4;
  559. uvIndex = uvidx + 2;
  560. }
  561. if (update) {
  562. if (this._computeParticleColor) {
  563. this.mesh.updateVerticesData(BABYLON.VertexBuffer.ColorKind, this._colors32, false, false);
  564. }
  565. if (this._computeParticleTexture) {
  566. this.mesh.updateVerticesData(BABYLON.VertexBuffer.UVKind, this._uvs32, false, false);
  567. }
  568. this.mesh.updateVerticesData(BABYLON.VertexBuffer.PositionKind, this._positions32, false, false);
  569. if (!this.mesh.areNormalsFrozen) {
  570. if (this._computeParticleVertex || this.billboard) {
  571. // recompute the normals only if the particles can be morphed, update then the normal reference array
  572. BABYLON.VertexData.ComputeNormals(this._positions32, this._indices, this._normals32);
  573. for (var i = 0; i < this._normals32.length; i++) {
  574. this._fixedNormal32[i] = this._normals32[i];
  575. }
  576. }
  577. this.mesh.updateVerticesData(BABYLON.VertexBuffer.NormalKind, this._normals32, false, false);
  578. }
  579. }
  580. if (this._computeBoundingBox) {
  581. this.mesh._boundingInfo = new BABYLON.BoundingInfo(this._minimum, this._maximum);
  582. this.mesh._boundingInfo.update(this.mesh._worldMatrix);
  583. }
  584. this.afterUpdateParticles(start, end, update);
  585. };
  586. SolidParticleSystem.prototype._quaternionRotationYPR = function () {
  587. this._halfroll = this._roll * 0.5;
  588. this._halfpitch = this._pitch * 0.5;
  589. this._halfyaw = this._yaw * 0.5;
  590. this._sinRoll = Math.sin(this._halfroll);
  591. this._cosRoll = Math.cos(this._halfroll);
  592. this._sinPitch = Math.sin(this._halfpitch);
  593. this._cosPitch = Math.cos(this._halfpitch);
  594. this._sinYaw = Math.sin(this._halfyaw);
  595. this._cosYaw = Math.cos(this._halfyaw);
  596. this._quaternion.x = (this._cosYaw * this._sinPitch * this._cosRoll) + (this._sinYaw * this._cosPitch * this._sinRoll);
  597. this._quaternion.y = (this._sinYaw * this._cosPitch * this._cosRoll) - (this._cosYaw * this._sinPitch * this._sinRoll);
  598. this._quaternion.z = (this._cosYaw * this._cosPitch * this._sinRoll) - (this._sinYaw * this._sinPitch * this._cosRoll);
  599. this._quaternion.w = (this._cosYaw * this._cosPitch * this._cosRoll) + (this._sinYaw * this._sinPitch * this._sinRoll);
  600. };
  601. SolidParticleSystem.prototype._quaternionToRotationMatrix = function () {
  602. this._rotMatrix.m[0] = 1.0 - (2.0 * (this._quaternion.y * this._quaternion.y + this._quaternion.z * this._quaternion.z));
  603. this._rotMatrix.m[1] = 2.0 * (this._quaternion.x * this._quaternion.y + this._quaternion.z * this._quaternion.w);
  604. this._rotMatrix.m[2] = 2.0 * (this._quaternion.z * this._quaternion.x - this._quaternion.y * this._quaternion.w);
  605. this._rotMatrix.m[3] = 0;
  606. this._rotMatrix.m[4] = 2.0 * (this._quaternion.x * this._quaternion.y - this._quaternion.z * this._quaternion.w);
  607. this._rotMatrix.m[5] = 1.0 - (2.0 * (this._quaternion.z * this._quaternion.z + this._quaternion.x * this._quaternion.x));
  608. this._rotMatrix.m[6] = 2.0 * (this._quaternion.y * this._quaternion.z + this._quaternion.x * this._quaternion.w);
  609. this._rotMatrix.m[7] = 0;
  610. this._rotMatrix.m[8] = 2.0 * (this._quaternion.z * this._quaternion.x + this._quaternion.y * this._quaternion.w);
  611. this._rotMatrix.m[9] = 2.0 * (this._quaternion.y * this._quaternion.z - this._quaternion.x * this._quaternion.w);
  612. this._rotMatrix.m[10] = 1.0 - (2.0 * (this._quaternion.y * this._quaternion.y + this._quaternion.x * this._quaternion.x));
  613. this._rotMatrix.m[11] = 0;
  614. this._rotMatrix.m[12] = 0;
  615. this._rotMatrix.m[13] = 0;
  616. this._rotMatrix.m[14] = 0;
  617. this._rotMatrix.m[15] = 1.0;
  618. };
  619. /**
  620. * Disposes the SPS
  621. */
  622. SolidParticleSystem.prototype.dispose = function () {
  623. this.mesh.dispose();
  624. this.vars = null;
  625. // drop references to internal big arrays for the GC
  626. this._positions = null;
  627. this._indices = null;
  628. this._normals = null;
  629. this._uvs = null;
  630. this._colors = null;
  631. this._positions32 = null;
  632. this._normals32 = null;
  633. this._fixedNormal32 = null;
  634. this._uvs32 = null;
  635. this._colors32 = null;
  636. this.pickedParticles = null;
  637. };
  638. /**
  639. * Visibilty helper : Recomputes the visible size according to the mesh bounding box
  640. * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#sps-visibility
  641. */
  642. SolidParticleSystem.prototype.refreshVisibleSize = function () {
  643. if (!this._isVisibilityBoxLocked) {
  644. this.mesh.refreshBoundingInfo();
  645. }
  646. };
  647. /** Visibility helper : Sets the size of a visibility box, this sets the underlying mesh bounding box.
  648. * @param size the size (float) of the visibility box
  649. * note : this doesn't lock the SPS mesh bounding box.
  650. * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#sps-visibility
  651. */
  652. SolidParticleSystem.prototype.setVisibilityBox = function (size) {
  653. var vis = size / 2;
  654. this.mesh._boundingInfo = new BABYLON.BoundingInfo(new BABYLON.Vector3(-vis, -vis, -vis), new BABYLON.Vector3(vis, vis, vis));
  655. };
  656. Object.defineProperty(SolidParticleSystem.prototype, "isAlwaysVisible", {
  657. // getter and setter
  658. /**
  659. * True if the SPS is set as always visible
  660. */
  661. get: function () {
  662. return this._alwaysVisible;
  663. },
  664. /**
  665. * Sets the SPS as always visible or not
  666. * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#sps-visibility
  667. */
  668. set: function (val) {
  669. this._alwaysVisible = val;
  670. this.mesh.alwaysSelectAsActiveMesh = val;
  671. },
  672. enumerable: true,
  673. configurable: true
  674. });
  675. Object.defineProperty(SolidParticleSystem.prototype, "isVisibilityBoxLocked", {
  676. /**
  677. * True if the SPS visibility box is locked. The underlying mesh bounding box is then not updatable any more.
  678. */
  679. get: function () {
  680. return this._isVisibilityBoxLocked;
  681. },
  682. /**
  683. * Sets the SPS visibility box as locked or not. This enables/disables the underlying mesh bounding box updates.
  684. * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#sps-visibility
  685. */
  686. set: function (val) {
  687. this._isVisibilityBoxLocked = val;
  688. this.mesh.getBoundingInfo().isLocked = val;
  689. },
  690. enumerable: true,
  691. configurable: true
  692. });
  693. Object.defineProperty(SolidParticleSystem.prototype, "computeParticleRotation", {
  694. // getters
  695. get: function () {
  696. return this._computeParticleRotation;
  697. },
  698. // Optimizer setters
  699. /**
  700. * Tells to setParticles() to compute the particle rotations or not.
  701. * Default value : true. The SPS is faster when it's set to false.
  702. * Note : the particle rotations aren't stored values, so setting computeParticleRotation to false will prevents the particle to rotate.
  703. */
  704. set: function (val) {
  705. this._computeParticleRotation = val;
  706. },
  707. enumerable: true,
  708. configurable: true
  709. });
  710. Object.defineProperty(SolidParticleSystem.prototype, "computeParticleColor", {
  711. get: function () {
  712. return this._computeParticleColor;
  713. },
  714. /**
  715. * Tells to setParticles() to compute the particle colors or not.
  716. * Default value : true. The SPS is faster when it's set to false.
  717. * Note : the particle colors are stored values, so setting computeParticleColor to false will keep yet the last colors set.
  718. */
  719. set: function (val) {
  720. this._computeParticleColor = val;
  721. },
  722. enumerable: true,
  723. configurable: true
  724. });
  725. Object.defineProperty(SolidParticleSystem.prototype, "computeParticleTexture", {
  726. get: function () {
  727. return this._computeParticleTexture;
  728. },
  729. /**
  730. * Tells to setParticles() to compute the particle textures or not.
  731. * Default value : true. The SPS is faster when it's set to false.
  732. * Note : the particle textures are stored values, so setting computeParticleTexture to false will keep yet the last colors set.
  733. */
  734. set: function (val) {
  735. this._computeParticleTexture = val;
  736. },
  737. enumerable: true,
  738. configurable: true
  739. });
  740. Object.defineProperty(SolidParticleSystem.prototype, "computeParticleVertex", {
  741. get: function () {
  742. return this._computeParticleVertex;
  743. },
  744. /**
  745. * Tells to setParticles() to call the vertex function for each vertex of each particle, or not.
  746. * Default value : false. The SPS is faster when it's set to false.
  747. * Note : the particle custom vertex positions aren't stored values.
  748. */
  749. set: function (val) {
  750. this._computeParticleVertex = val;
  751. },
  752. enumerable: true,
  753. configurable: true
  754. });
  755. Object.defineProperty(SolidParticleSystem.prototype, "computeBoundingBox", {
  756. get: function () {
  757. return this._computeBoundingBox;
  758. },
  759. /**
  760. * Tells to setParticles() to compute or not the mesh bounding box when computing the particle positions.
  761. */
  762. set: function (val) {
  763. this._computeBoundingBox = val;
  764. },
  765. enumerable: true,
  766. configurable: true
  767. });
  768. // =======================================================================
  769. // Particle behavior logic
  770. // these following methods may be overwritten by the user to fit his needs
  771. /**
  772. * This function does nothing. It may be overwritten to set all the particles first values.
  773. * The SPS doesn't call this function, you may have to call it by your own.
  774. * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#particle-management
  775. */
  776. SolidParticleSystem.prototype.initParticles = function () {
  777. };
  778. /**
  779. * This function does nothing. It may be overwritten to recycle a particle.
  780. * The SPS doesn't call this function, you may have to call it by your own.
  781. * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#particle-management
  782. */
  783. SolidParticleSystem.prototype.recycleParticle = function (particle) {
  784. return particle;
  785. };
  786. /**
  787. * Updates a particle : this function should be overwritten by the user.
  788. * It is called on each particle by setParticles(). This is the place to code each particle behavior.
  789. * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#particle-management
  790. * ex : just set a particle position or velocity and recycle conditions
  791. */
  792. SolidParticleSystem.prototype.updateParticle = function (particle) {
  793. return particle;
  794. };
  795. /**
  796. * Updates a vertex of a particle : it can be overwritten by the user.
  797. * This will be called on each vertex particle by setParticles() if computeParticleVertex is set to true only.
  798. * @param particle the current particle
  799. * @param vertex the current index of the current particle
  800. * @param pt the index of the current vertex in the particle shape
  801. * doc : http://doc.babylonjs.com/tutorials/Solid_Particle_System#update-each-particle-shape
  802. * ex : just set a vertex particle position
  803. */
  804. SolidParticleSystem.prototype.updateParticleVertex = function (particle, vertex, pt) {
  805. return vertex;
  806. };
  807. /**
  808. * This will be called before any other treatment by setParticles() and will be passed three parameters.
  809. * This does nothing and may be overwritten by the user.
  810. * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
  811. * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
  812. * @param update the boolean update value actually passed to setParticles()
  813. */
  814. SolidParticleSystem.prototype.beforeUpdateParticles = function (start, stop, update) {
  815. };
  816. /**
  817. * This will be called by setParticles() after all the other treatments and just before the actual mesh update.
  818. * This will be passed three parameters.
  819. * This does nothing and may be overwritten by the user.
  820. * @param start the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
  821. * @param stop the particle index in the particle array where to stop to iterate, same than the value passed to setParticle()
  822. * @param update the boolean update value actually passed to setParticles()
  823. */
  824. SolidParticleSystem.prototype.afterUpdateParticles = function (start, stop, update) {
  825. };
  826. return SolidParticleSystem;
  827. })();
  828. BABYLON.SolidParticleSystem = SolidParticleSystem;
  829. })(BABYLON || (BABYLON = {}));