meshParticleEmitter.ts 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import { DeepCopier } from "../../Misc/deepCopier";
  2. import { Vector3, Matrix, TmpVectors } from "../../Maths/math.vector";
  3. import { Scalar } from "../../Maths/math.scalar";
  4. import { Effect } from "../../Materials/effect";
  5. import { Particle } from "../../Particles/particle";
  6. import { IParticleEmitterType } from "./IParticleEmitterType";
  7. import { IndicesArray, Nullable, FloatArray } from '../../types';
  8. import { VertexBuffer } from '../../Meshes/buffer';
  9. import { Scene } from '../../scene';
  10. import { AbstractMesh } from '../../Meshes/abstractMesh';
  11. /**
  12. * Particle emitter emitting particles from the inside of a box.
  13. * It emits the particles randomly between 2 given directions.
  14. */
  15. export class MeshParticleEmitter implements IParticleEmitterType {
  16. private _indices: Nullable<IndicesArray> = null;
  17. private _positions: Nullable<FloatArray> = null;
  18. private _normals: Nullable<FloatArray> = null;
  19. private _storedNormal = Vector3.Zero();
  20. private _mesh: Nullable<AbstractMesh> = null;
  21. /**
  22. * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
  23. */
  24. public direction1 = new Vector3(0, 1.0, 0);
  25. /**
  26. * Random direction of each particle after it has been emitted, between direction1 and direction2 vectors.
  27. */
  28. public direction2 = new Vector3(0, 1.0, 0);
  29. /**
  30. * Gets or sets a boolean indicating that particle directions must be built from mesh face normals
  31. */
  32. public useMeshNormalsForDirection = true;
  33. /** Defines the mesh to use as source */
  34. public get mesh(): Nullable<AbstractMesh> {
  35. return this._mesh;
  36. }
  37. public set mesh(value: Nullable<AbstractMesh>) {
  38. if (this._mesh === value) {
  39. return;
  40. }
  41. this._mesh = value;
  42. if (value) {
  43. this._indices = value.getIndices();
  44. this._positions = value.getVerticesData(VertexBuffer.PositionKind);
  45. this._normals = value.getVerticesData(VertexBuffer.NormalKind);
  46. } else {
  47. this._indices = null;
  48. this._positions = null;
  49. this._normals = null;
  50. }
  51. }
  52. /**
  53. * Creates a new instance MeshParticleEmitter
  54. * @param mesh defines the mesh to use as source
  55. */
  56. constructor(mesh: Nullable<AbstractMesh> = null) {
  57. this.mesh = mesh;
  58. }
  59. /**
  60. * Called by the particle System when the direction is computed for the created particle.
  61. * @param worldMatrix is the world matrix of the particle system
  62. * @param directionToUpdate is the direction vector to update with the result
  63. * @param particle is the particle we are computed the direction for
  64. * @param isLocal defines if the direction should be set in local space
  65. */
  66. public startDirectionFunction(worldMatrix: Matrix, directionToUpdate: Vector3, particle: Particle, isLocal: boolean): void {
  67. if (this.useMeshNormalsForDirection && this._normals) {
  68. Vector3.TransformNormalToRef(this._storedNormal, worldMatrix, directionToUpdate);
  69. return;
  70. }
  71. var randX = Scalar.RandomRange(this.direction1.x, this.direction2.x);
  72. var randY = Scalar.RandomRange(this.direction1.y, this.direction2.y);
  73. var randZ = Scalar.RandomRange(this.direction1.z, this.direction2.z);
  74. if (isLocal) {
  75. directionToUpdate.copyFromFloats(randX, randY, randZ);
  76. return;
  77. }
  78. Vector3.TransformNormalFromFloatsToRef(randX, randY, randZ, worldMatrix, directionToUpdate);
  79. }
  80. /**
  81. * Called by the particle System when the position is computed for the created particle.
  82. * @param worldMatrix is the world matrix of the particle system
  83. * @param positionToUpdate is the position vector to update with the result
  84. * @param particle is the particle we are computed the position for
  85. * @param isLocal defines if the position should be set in local space
  86. */
  87. public startPositionFunction(worldMatrix: Matrix, positionToUpdate: Vector3, particle: Particle, isLocal: boolean): void {
  88. if (!this._indices || !this._positions) {
  89. return;
  90. }
  91. let randomFaceIndex = 3 * Math.random() * (this._indices.length / 3) | 0;
  92. let bu = Math.random();
  93. let bv = Math.random() * (1.0 - bu);
  94. let bw = 1.0 - bu - bv;
  95. let faceIndexA = this._indices[randomFaceIndex];
  96. let faceIndexB = this._indices[randomFaceIndex + 1];
  97. let faceIndexC = this._indices[randomFaceIndex + 2];
  98. let vertexA = TmpVectors.Vector3[0];
  99. let vertexB = TmpVectors.Vector3[1];
  100. let vertexC = TmpVectors.Vector3[2];
  101. let randomVertex = TmpVectors.Vector3[3];
  102. Vector3.FromArrayToRef(this._positions, faceIndexA * 3, vertexA);
  103. Vector3.FromArrayToRef(this._positions, faceIndexB * 3, vertexB);
  104. Vector3.FromArrayToRef(this._positions, faceIndexC * 3, vertexC);
  105. randomVertex.x = bu * vertexA.x + bv * vertexB.x + bw * vertexC.x;
  106. randomVertex.y = bu * vertexA.y + bv * vertexB.y + bw * vertexC.y;
  107. randomVertex.z = bu * vertexA.z + bv * vertexB.z + bw * vertexC.z;
  108. if (isLocal) {
  109. positionToUpdate.copyFromFloats(randomVertex.x, randomVertex.y, randomVertex.z);
  110. } else {
  111. Vector3.TransformCoordinatesFromFloatsToRef(randomVertex.x, randomVertex.y, randomVertex.z, worldMatrix, positionToUpdate);
  112. }
  113. if (this.useMeshNormalsForDirection && this._normals) {
  114. Vector3.FromArrayToRef(this._normals, faceIndexA * 3, vertexA);
  115. Vector3.FromArrayToRef(this._normals, faceIndexB * 3, vertexB);
  116. Vector3.FromArrayToRef(this._normals, faceIndexC * 3, vertexC);
  117. this._storedNormal.x = bu * vertexA.x + bv * vertexB.x + bw * vertexC.x;
  118. this._storedNormal.y = bu * vertexA.y + bv * vertexB.y + bw * vertexC.y;
  119. this._storedNormal.z = bu * vertexA.z + bv * vertexB.z + bw * vertexC.z;
  120. }
  121. }
  122. /**
  123. * Clones the current emitter and returns a copy of it
  124. * @returns the new emitter
  125. */
  126. public clone(): MeshParticleEmitter {
  127. let newOne = new MeshParticleEmitter(this.mesh);
  128. DeepCopier.DeepCopy(this, newOne);
  129. return newOne;
  130. }
  131. /**
  132. * Called by the GPUParticleSystem to setup the update shader
  133. * @param effect defines the update shader
  134. */
  135. public applyToShader(effect: Effect): void {
  136. effect.setVector3("direction1", this.direction1);
  137. effect.setVector3("direction2", this.direction2);
  138. }
  139. /**
  140. * Returns a string to use to update the GPU particles update shader
  141. * @returns a string containing the defines string
  142. */
  143. public getEffectDefines(): string {
  144. return "";
  145. }
  146. /**
  147. * Returns the string "BoxParticleEmitter"
  148. * @returns a string containing the class name
  149. */
  150. public getClassName(): string {
  151. return "MeshParticleEmitter";
  152. }
  153. /**
  154. * Serializes the particle system to a JSON object.
  155. * @returns the JSON object
  156. */
  157. public serialize(): any {
  158. var serializationObject: any = {};
  159. serializationObject.type = this.getClassName();
  160. serializationObject.direction1 = this.direction1.asArray();
  161. serializationObject.direction2 = this.direction2.asArray();
  162. serializationObject.meshId = this.mesh?.id;
  163. serializationObject.useMeshNormalsForDirection = this.useMeshNormalsForDirection;
  164. return serializationObject;
  165. }
  166. /**
  167. * Parse properties from a JSON object
  168. * @param serializationObject defines the JSON object
  169. * @param scene defines the hosting scene
  170. */
  171. public parse(serializationObject: any, scene: Nullable<Scene>): void {
  172. Vector3.FromArrayToRef(serializationObject.direction1, 0, this.direction1);
  173. Vector3.FromArrayToRef(serializationObject.direction2, 0, this.direction2);
  174. if (serializationObject.meshId && scene) {
  175. this.mesh = scene.getLastMeshByID(serializationObject.meshId);
  176. }
  177. this.useMeshNormalsForDirection = serializationObject.useMeshNormalsForDirection;
  178. }
  179. }