particle.ts 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. import { Nullable } from "../types";
  2. import { Vector2, Vector3, TmpVectors, Vector4 } from "../Maths/math.vector";
  3. import { Color4 } from '../Maths/math.color';
  4. import { Scalar } from "../Maths/math.scalar";
  5. import { AbstractMesh } from "../Meshes/abstractMesh";
  6. import { ParticleSystem } from "./particleSystem";
  7. import { SubEmitter } from "./subEmitter";
  8. import { ColorGradient, FactorGradient } from "../Misc/gradients";
  9. /**
  10. * A particle represents one of the element emitted by a particle system.
  11. * This is mainly define by its coordinates, direction, velocity and age.
  12. */
  13. export class Particle {
  14. private static _Count = 0;
  15. /**
  16. * Unique ID of the particle
  17. */
  18. public id: number;
  19. /**
  20. * The world position of the particle in the scene.
  21. */
  22. public position = Vector3.Zero();
  23. /**
  24. * The world direction of the particle in the scene.
  25. */
  26. public direction = Vector3.Zero();
  27. /**
  28. * The color of the particle.
  29. */
  30. public color = new Color4(0, 0, 0, 0);
  31. /**
  32. * The color change of the particle per step.
  33. */
  34. public colorStep = new Color4(0, 0, 0, 0);
  35. /**
  36. * Defines how long will the life of the particle be.
  37. */
  38. public lifeTime = 1.0;
  39. /**
  40. * The current age of the particle.
  41. */
  42. public age = 0;
  43. /**
  44. * The current size of the particle.
  45. */
  46. public size = 0;
  47. /**
  48. * The current scale of the particle.
  49. */
  50. public scale = new Vector2(1, 1);
  51. /**
  52. * The current angle of the particle.
  53. */
  54. public angle = 0;
  55. /**
  56. * Defines how fast is the angle changing.
  57. */
  58. public angularSpeed = 0;
  59. /**
  60. * Defines the cell index used by the particle to be rendered from a sprite.
  61. */
  62. public cellIndex: number = 0;
  63. /**
  64. * The information required to support color remapping
  65. */
  66. public remapData: Vector4;
  67. /** @hidden */
  68. public _randomCellOffset?: number;
  69. /** @hidden */
  70. public _initialDirection: Nullable<Vector3>;
  71. /** @hidden */
  72. public _attachedSubEmitters: Nullable<Array<SubEmitter>> = null;
  73. /** @hidden */
  74. public _initialStartSpriteCellID: number;
  75. /** @hidden */
  76. public _initialEndSpriteCellID: number;
  77. /** @hidden */
  78. public _currentColorGradient: Nullable<ColorGradient>;
  79. /** @hidden */
  80. public _currentColor1 = new Color4(0, 0, 0, 0);
  81. /** @hidden */
  82. public _currentColor2 = new Color4(0, 0, 0, 0);
  83. /** @hidden */
  84. public _currentSizeGradient: Nullable<FactorGradient>;
  85. /** @hidden */
  86. public _currentSize1 = 0;
  87. /** @hidden */
  88. public _currentSize2 = 0;
  89. /** @hidden */
  90. public _currentAngularSpeedGradient: Nullable<FactorGradient>;
  91. /** @hidden */
  92. public _currentAngularSpeed1 = 0;
  93. /** @hidden */
  94. public _currentAngularSpeed2 = 0;
  95. /** @hidden */
  96. public _currentVelocityGradient: Nullable<FactorGradient>;
  97. /** @hidden */
  98. public _currentVelocity1 = 0;
  99. /** @hidden */
  100. public _currentVelocity2 = 0;
  101. /** @hidden */
  102. public _currentLimitVelocityGradient: Nullable<FactorGradient>;
  103. /** @hidden */
  104. public _currentLimitVelocity1 = 0;
  105. /** @hidden */
  106. public _currentLimitVelocity2 = 0;
  107. /** @hidden */
  108. public _currentDragGradient: Nullable<FactorGradient>;
  109. /** @hidden */
  110. public _currentDrag1 = 0;
  111. /** @hidden */
  112. public _currentDrag2 = 0;
  113. /** @hidden */
  114. public _randomNoiseCoordinates1: Vector3;
  115. /** @hidden */
  116. public _randomNoiseCoordinates2: Vector3;
  117. /**
  118. * Creates a new instance Particle
  119. * @param particleSystem the particle system the particle belongs to
  120. */
  121. constructor(
  122. /**
  123. * The particle system the particle belongs to.
  124. */
  125. public particleSystem: ParticleSystem) {
  126. this.id = Particle._Count++;
  127. if (!this.particleSystem.isAnimationSheetEnabled) {
  128. return;
  129. }
  130. this.updateCellInfoFromSystem();
  131. }
  132. private updateCellInfoFromSystem(): void {
  133. this.cellIndex = this.particleSystem.startSpriteCellID;
  134. }
  135. /**
  136. * Defines how the sprite cell index is updated for the particle
  137. */
  138. public updateCellIndex(): void {
  139. let offsetAge = this.age;
  140. let changeSpeed = this.particleSystem.spriteCellChangeSpeed;
  141. if (this.particleSystem.spriteRandomStartCell) {
  142. if (this._randomCellOffset === undefined) {
  143. this._randomCellOffset = Math.random() * this.lifeTime;
  144. }
  145. if (changeSpeed === 0) { // Special case when speed = 0 meaning we want to stay on initial cell
  146. changeSpeed = 1;
  147. offsetAge = this._randomCellOffset;
  148. } else {
  149. offsetAge += this._randomCellOffset;
  150. }
  151. }
  152. let dist = (this._initialEndSpriteCellID - this._initialStartSpriteCellID);
  153. let ratio = Scalar.Clamp(((offsetAge * changeSpeed) % this.lifeTime) / this.lifeTime);
  154. this.cellIndex = this._initialStartSpriteCellID + (ratio * dist) | 0;
  155. }
  156. /** @hidden */
  157. public _inheritParticleInfoToSubEmitter(subEmitter: SubEmitter) {
  158. if ((<AbstractMesh>subEmitter.particleSystem.emitter).position) {
  159. var emitterMesh = (<AbstractMesh>subEmitter.particleSystem.emitter);
  160. emitterMesh.position.copyFrom(this.position);
  161. if (subEmitter.inheritDirection) {
  162. emitterMesh.setDirection(this.direction.normalize(), 0, Math.PI / 2);
  163. }
  164. } else {
  165. var emitterPosition = (<Vector3>subEmitter.particleSystem.emitter);
  166. emitterPosition.copyFrom(this.position);
  167. }
  168. // Set inheritedVelocityOffset to be used when new particles are created
  169. this.direction.scaleToRef(subEmitter.inheritedVelocityAmount / 2, TmpVectors.Vector3[0]);
  170. subEmitter.particleSystem._inheritedVelocityOffset.copyFrom(TmpVectors.Vector3[0]);
  171. }
  172. /** @hidden */
  173. public _inheritParticleInfoToSubEmitters() {
  174. if (this._attachedSubEmitters && this._attachedSubEmitters.length > 0) {
  175. this._attachedSubEmitters.forEach((subEmitter) => {
  176. this._inheritParticleInfoToSubEmitter(subEmitter);
  177. });
  178. }
  179. }
  180. /** @hidden */
  181. public _reset() {
  182. this.age = 0;
  183. this.id = Particle._Count++;
  184. this._currentColorGradient = null;
  185. this._currentSizeGradient = null;
  186. this._currentAngularSpeedGradient = null;
  187. this._currentVelocityGradient = null;
  188. this._currentLimitVelocityGradient = null;
  189. this._currentDragGradient = null;
  190. this.cellIndex = this.particleSystem.startSpriteCellID;
  191. this._randomCellOffset = undefined;
  192. }
  193. /**
  194. * Copy the properties of particle to another one.
  195. * @param other the particle to copy the information to.
  196. */
  197. public copyTo(other: Particle) {
  198. other.position.copyFrom(this.position);
  199. if (this._initialDirection) {
  200. if (other._initialDirection) {
  201. other._initialDirection.copyFrom(this._initialDirection);
  202. } else {
  203. other._initialDirection = this._initialDirection.clone();
  204. }
  205. } else {
  206. other._initialDirection = null;
  207. }
  208. other.direction.copyFrom(this.direction);
  209. other.color.copyFrom(this.color);
  210. other.colorStep.copyFrom(this.colorStep);
  211. other.lifeTime = this.lifeTime;
  212. other.age = this.age;
  213. other._randomCellOffset = this._randomCellOffset;
  214. other.size = this.size;
  215. other.scale.copyFrom(this.scale);
  216. other.angle = this.angle;
  217. other.angularSpeed = this.angularSpeed;
  218. other.particleSystem = this.particleSystem;
  219. other.cellIndex = this.cellIndex;
  220. other.id = this.id;
  221. other._attachedSubEmitters = this._attachedSubEmitters;
  222. if (this._currentColorGradient) {
  223. other._currentColorGradient = this._currentColorGradient;
  224. other._currentColor1.copyFrom(this._currentColor1);
  225. other._currentColor2.copyFrom(this._currentColor2);
  226. }
  227. if (this._currentSizeGradient) {
  228. other._currentSizeGradient = this._currentSizeGradient;
  229. other._currentSize1 = this._currentSize1;
  230. other._currentSize2 = this._currentSize2;
  231. }
  232. if (this._currentAngularSpeedGradient) {
  233. other._currentAngularSpeedGradient = this._currentAngularSpeedGradient;
  234. other._currentAngularSpeed1 = this._currentAngularSpeed1;
  235. other._currentAngularSpeed2 = this._currentAngularSpeed2;
  236. }
  237. if (this._currentVelocityGradient) {
  238. other._currentVelocityGradient = this._currentVelocityGradient;
  239. other._currentVelocity1 = this._currentVelocity1;
  240. other._currentVelocity2 = this._currentVelocity2;
  241. }
  242. if (this._currentLimitVelocityGradient) {
  243. other._currentLimitVelocityGradient = this._currentLimitVelocityGradient;
  244. other._currentLimitVelocity1 = this._currentLimitVelocity1;
  245. other._currentLimitVelocity2 = this._currentLimitVelocity2;
  246. }
  247. if (this._currentDragGradient) {
  248. other._currentDragGradient = this._currentDragGradient;
  249. other._currentDrag1 = this._currentDrag1;
  250. other._currentDrag2 = this._currentDrag2;
  251. }
  252. if (this.particleSystem.isAnimationSheetEnabled) {
  253. other._initialStartSpriteCellID = this._initialStartSpriteCellID;
  254. other._initialEndSpriteCellID = this._initialEndSpriteCellID;
  255. }
  256. if (this.particleSystem.useRampGradients) {
  257. other.remapData.copyFrom(this.remapData);
  258. }
  259. if (this._randomNoiseCoordinates1) {
  260. if (other._randomNoiseCoordinates1) {
  261. other._randomNoiseCoordinates1.copyFrom(this._randomNoiseCoordinates1);
  262. other._randomNoiseCoordinates2.copyFrom(this._randomNoiseCoordinates2);
  263. } else {
  264. other._randomNoiseCoordinates1 = this._randomNoiseCoordinates1.clone();
  265. other._randomNoiseCoordinates2 = this._randomNoiseCoordinates2.clone();
  266. }
  267. }
  268. }
  269. }