particle.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317
  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. /** @hidden */
  118. public _localPosition?: Vector3;
  119. /**
  120. * Creates a new instance Particle
  121. * @param particleSystem the particle system the particle belongs to
  122. */
  123. constructor(
  124. /**
  125. * The particle system the particle belongs to.
  126. */
  127. public particleSystem: ParticleSystem) {
  128. this.id = Particle._Count++;
  129. if (!this.particleSystem.isAnimationSheetEnabled) {
  130. return;
  131. }
  132. this.updateCellInfoFromSystem();
  133. }
  134. private updateCellInfoFromSystem(): void {
  135. this.cellIndex = this.particleSystem.startSpriteCellID;
  136. }
  137. /**
  138. * Defines how the sprite cell index is updated for the particle
  139. */
  140. public updateCellIndex(): void {
  141. let offsetAge = this.age;
  142. let changeSpeed = this.particleSystem.spriteCellChangeSpeed;
  143. if (this.particleSystem.spriteRandomStartCell) {
  144. if (this._randomCellOffset === undefined) {
  145. this._randomCellOffset = Math.random() * this.lifeTime;
  146. }
  147. if (changeSpeed === 0) { // Special case when speed = 0 meaning we want to stay on initial cell
  148. changeSpeed = 1;
  149. offsetAge = this._randomCellOffset;
  150. } else {
  151. offsetAge += this._randomCellOffset;
  152. }
  153. }
  154. let dist = (this._initialEndSpriteCellID - this._initialStartSpriteCellID);
  155. let ratio = Scalar.Clamp(((offsetAge * changeSpeed) % this.lifeTime) / this.lifeTime);
  156. this.cellIndex = this._initialStartSpriteCellID + (ratio * dist) | 0;
  157. }
  158. /** @hidden */
  159. public _inheritParticleInfoToSubEmitter(subEmitter: SubEmitter) {
  160. if ((<AbstractMesh>subEmitter.particleSystem.emitter).position) {
  161. var emitterMesh = (<AbstractMesh>subEmitter.particleSystem.emitter);
  162. emitterMesh.position.copyFrom(this.position);
  163. if (subEmitter.inheritDirection) {
  164. emitterMesh.setDirection(this.direction.normalize(), 0, Math.PI / 2);
  165. }
  166. } else {
  167. var emitterPosition = (<Vector3>subEmitter.particleSystem.emitter);
  168. emitterPosition.copyFrom(this.position);
  169. }
  170. // Set inheritedVelocityOffset to be used when new particles are created
  171. this.direction.scaleToRef(subEmitter.inheritedVelocityAmount / 2, TmpVectors.Vector3[0]);
  172. subEmitter.particleSystem._inheritedVelocityOffset.copyFrom(TmpVectors.Vector3[0]);
  173. }
  174. /** @hidden */
  175. public _inheritParticleInfoToSubEmitters() {
  176. if (this._attachedSubEmitters && this._attachedSubEmitters.length > 0) {
  177. this._attachedSubEmitters.forEach((subEmitter) => {
  178. this._inheritParticleInfoToSubEmitter(subEmitter);
  179. });
  180. }
  181. }
  182. /** @hidden */
  183. public _reset() {
  184. this.age = 0;
  185. this.id = Particle._Count++;
  186. this._currentColorGradient = null;
  187. this._currentSizeGradient = null;
  188. this._currentAngularSpeedGradient = null;
  189. this._currentVelocityGradient = null;
  190. this._currentLimitVelocityGradient = null;
  191. this._currentDragGradient = null;
  192. this.cellIndex = this.particleSystem.startSpriteCellID;
  193. this._randomCellOffset = undefined;
  194. }
  195. /**
  196. * Copy the properties of particle to another one.
  197. * @param other the particle to copy the information to.
  198. */
  199. public copyTo(other: Particle) {
  200. other.position.copyFrom(this.position);
  201. if (this._initialDirection) {
  202. if (other._initialDirection) {
  203. other._initialDirection.copyFrom(this._initialDirection);
  204. } else {
  205. other._initialDirection = this._initialDirection.clone();
  206. }
  207. } else {
  208. other._initialDirection = null;
  209. }
  210. other.direction.copyFrom(this.direction);
  211. if (this._localPosition) {
  212. if (other._localPosition) {
  213. other._localPosition.copyFrom(this._localPosition);
  214. } else {
  215. other._localPosition = this._localPosition.clone();
  216. }
  217. }
  218. other.color.copyFrom(this.color);
  219. other.colorStep.copyFrom(this.colorStep);
  220. other.lifeTime = this.lifeTime;
  221. other.age = this.age;
  222. other._randomCellOffset = this._randomCellOffset;
  223. other.size = this.size;
  224. other.scale.copyFrom(this.scale);
  225. other.angle = this.angle;
  226. other.angularSpeed = this.angularSpeed;
  227. other.particleSystem = this.particleSystem;
  228. other.cellIndex = this.cellIndex;
  229. other.id = this.id;
  230. other._attachedSubEmitters = this._attachedSubEmitters;
  231. if (this._currentColorGradient) {
  232. other._currentColorGradient = this._currentColorGradient;
  233. other._currentColor1.copyFrom(this._currentColor1);
  234. other._currentColor2.copyFrom(this._currentColor2);
  235. }
  236. if (this._currentSizeGradient) {
  237. other._currentSizeGradient = this._currentSizeGradient;
  238. other._currentSize1 = this._currentSize1;
  239. other._currentSize2 = this._currentSize2;
  240. }
  241. if (this._currentAngularSpeedGradient) {
  242. other._currentAngularSpeedGradient = this._currentAngularSpeedGradient;
  243. other._currentAngularSpeed1 = this._currentAngularSpeed1;
  244. other._currentAngularSpeed2 = this._currentAngularSpeed2;
  245. }
  246. if (this._currentVelocityGradient) {
  247. other._currentVelocityGradient = this._currentVelocityGradient;
  248. other._currentVelocity1 = this._currentVelocity1;
  249. other._currentVelocity2 = this._currentVelocity2;
  250. }
  251. if (this._currentLimitVelocityGradient) {
  252. other._currentLimitVelocityGradient = this._currentLimitVelocityGradient;
  253. other._currentLimitVelocity1 = this._currentLimitVelocity1;
  254. other._currentLimitVelocity2 = this._currentLimitVelocity2;
  255. }
  256. if (this._currentDragGradient) {
  257. other._currentDragGradient = this._currentDragGradient;
  258. other._currentDrag1 = this._currentDrag1;
  259. other._currentDrag2 = this._currentDrag2;
  260. }
  261. if (this.particleSystem.isAnimationSheetEnabled) {
  262. other._initialStartSpriteCellID = this._initialStartSpriteCellID;
  263. other._initialEndSpriteCellID = this._initialEndSpriteCellID;
  264. }
  265. if (this.particleSystem.useRampGradients) {
  266. if (other.remapData) {
  267. other.remapData.copyFrom(this.remapData);
  268. } else {
  269. other.remapData = new Vector4(0, 0, 0, 0);
  270. }
  271. }
  272. if (this._randomNoiseCoordinates1) {
  273. if (other._randomNoiseCoordinates1) {
  274. other._randomNoiseCoordinates1.copyFrom(this._randomNoiseCoordinates1);
  275. other._randomNoiseCoordinates2.copyFrom(this._randomNoiseCoordinates2);
  276. } else {
  277. other._randomNoiseCoordinates1 = this._randomNoiseCoordinates1.clone();
  278. other._randomNoiseCoordinates2 = this._randomNoiseCoordinates2.clone();
  279. }
  280. }
  281. }
  282. }