@babylonjs/core 6.45.0 → 6.46.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (235) hide show
  1. package/Animations/animation.js +1 -1
  2. package/Animations/animation.js.map +1 -1
  3. package/BakedVertexAnimation/bakedVertexAnimationManager.js +2 -1
  4. package/BakedVertexAnimation/bakedVertexAnimationManager.js.map +1 -1
  5. package/Bones/skeleton.js +2 -2
  6. package/Bones/skeleton.js.map +1 -1
  7. package/Cameras/camera.d.ts +3 -3
  8. package/Cameras/camera.js +2 -1
  9. package/Cameras/camera.js.map +1 -1
  10. package/Cameras/cameraInputsManager.js +1 -1
  11. package/Cameras/cameraInputsManager.js.map +1 -1
  12. package/Cameras/targetCamera.js +4 -0
  13. package/Cameras/targetCamera.js.map +1 -1
  14. package/Compute/computeShader.d.ts +4 -2
  15. package/Compute/computeShader.js +7 -3
  16. package/Compute/computeShader.js.map +1 -1
  17. package/Debug/directionalLightFrustumViewer.js +6 -6
  18. package/Debug/directionalLightFrustumViewer.js.map +1 -1
  19. package/Engines/Extensions/engine.computeShader.d.ts +2 -1
  20. package/Engines/Extensions/engine.computeShader.js +1 -0
  21. package/Engines/Extensions/engine.computeShader.js.map +1 -1
  22. package/Engines/Extensions/engine.rawTexture.js +3 -3
  23. package/Engines/Extensions/engine.rawTexture.js.map +1 -1
  24. package/Engines/Native/nativePipelineContext.js +1 -1
  25. package/Engines/Native/nativePipelineContext.js.map +1 -1
  26. package/Engines/WebGL/webGLPipelineContext.js +1 -1
  27. package/Engines/WebGL/webGLPipelineContext.js.map +1 -1
  28. package/Engines/WebGPU/webgpuComputeContext.js +7 -3
  29. package/Engines/WebGPU/webgpuComputeContext.js.map +1 -1
  30. package/Engines/engine.d.ts +1 -1
  31. package/Engines/thinEngine.js +2 -2
  32. package/Engines/thinEngine.js.map +1 -1
  33. package/Engines/webgpuEngine.js +2 -15
  34. package/Engines/webgpuEngine.js.map +1 -1
  35. package/Layers/glowLayer.js +2 -1
  36. package/Layers/glowLayer.js.map +1 -1
  37. package/Layers/highlightLayer.js +2 -1
  38. package/Layers/highlightLayer.js.map +1 -1
  39. package/Lights/light.js +2 -1
  40. package/Lights/light.js.map +1 -1
  41. package/Loading/Plugins/babylonFileLoader.js +9 -0
  42. package/Loading/Plugins/babylonFileLoader.js.map +1 -1
  43. package/Loading/sceneLoader.d.ts +6 -1
  44. package/Loading/sceneLoader.js +6 -5
  45. package/Loading/sceneLoader.js.map +1 -1
  46. package/Materials/Background/backgroundMaterial.js +2 -1
  47. package/Materials/Background/backgroundMaterial.js.map +1 -1
  48. package/Materials/GaussianSplatting/gaussianSplattingMaterial.js +1 -1
  49. package/Materials/GaussianSplatting/gaussianSplattingMaterial.js.map +1 -1
  50. package/Materials/Node/nodeMaterial.d.ts +2 -1
  51. package/Materials/Node/nodeMaterial.js +5 -1
  52. package/Materials/Node/nodeMaterial.js.map +1 -1
  53. package/Materials/PBR/pbrBaseMaterial.d.ts +1 -1
  54. package/Materials/PBR/pbrBaseMaterial.js.map +1 -1
  55. package/Materials/PBR/pbrMaterial.js +2 -1
  56. package/Materials/PBR/pbrMaterial.js.map +1 -1
  57. package/Materials/PBR/pbrMetallicRoughnessMaterial.js +2 -1
  58. package/Materials/PBR/pbrMetallicRoughnessMaterial.js.map +1 -1
  59. package/Materials/PBR/pbrSpecularGlossinessMaterial.js +2 -1
  60. package/Materials/PBR/pbrSpecularGlossinessMaterial.js.map +1 -1
  61. package/Materials/Textures/baseTexture.js +2 -1
  62. package/Materials/Textures/baseTexture.js.map +1 -1
  63. package/Materials/Textures/cubeTexture.js +2 -1
  64. package/Materials/Textures/cubeTexture.js.map +1 -1
  65. package/Materials/Textures/rawCubeTexture.js +1 -1
  66. package/Materials/Textures/rawCubeTexture.js.map +1 -1
  67. package/Materials/Textures/texture.js +2 -1
  68. package/Materials/Textures/texture.js.map +1 -1
  69. package/Materials/colorCurves.d.ts +1 -1
  70. package/Materials/colorCurves.functions.d.ts +5 -0
  71. package/Materials/colorCurves.functions.js +8 -0
  72. package/Materials/colorCurves.functions.js.map +1 -0
  73. package/Materials/colorCurves.js +8 -8
  74. package/Materials/colorCurves.js.map +1 -1
  75. package/Materials/fresnelParameters.js +1 -1
  76. package/Materials/fresnelParameters.js.map +1 -1
  77. package/Materials/imageProcessingConfiguration.d.ts +3 -48
  78. package/Materials/imageProcessingConfiguration.defines.d.ts +46 -0
  79. package/Materials/imageProcessingConfiguration.defines.js +27 -0
  80. package/Materials/imageProcessingConfiguration.defines.js.map +1 -0
  81. package/Materials/imageProcessingConfiguration.functions.d.ts +13 -0
  82. package/Materials/imageProcessingConfiguration.functions.js +41 -0
  83. package/Materials/imageProcessingConfiguration.functions.js.map +1 -0
  84. package/Materials/imageProcessingConfiguration.js +18 -69
  85. package/Materials/imageProcessingConfiguration.js.map +1 -1
  86. package/Materials/material.js +2 -1
  87. package/Materials/material.js.map +1 -1
  88. package/Materials/materialHelper.d.ts +33 -33
  89. package/Materials/materialHelper.js +244 -286
  90. package/Materials/materialHelper.js.map +1 -1
  91. package/Materials/materialPluginBase.js +2 -1
  92. package/Materials/materialPluginBase.js.map +1 -1
  93. package/Materials/materialStencilState.js +2 -1
  94. package/Materials/materialStencilState.js.map +1 -1
  95. package/Materials/shaderMaterial.js +1 -1
  96. package/Materials/shaderMaterial.js.map +1 -1
  97. package/Materials/standardMaterial.d.ts +1 -1
  98. package/Materials/standardMaterial.js +2 -1
  99. package/Materials/standardMaterial.js.map +1 -1
  100. package/Materials/uniformBuffer.js +2 -2
  101. package/Materials/uniformBuffer.js.map +1 -1
  102. package/Maths/math.color.d.ts +392 -66
  103. package/Maths/math.color.js +541 -65
  104. package/Maths/math.color.js.map +1 -1
  105. package/Maths/math.like.d.ts +17 -28
  106. package/Maths/math.like.js.map +1 -1
  107. package/Maths/math.plane.d.ts +2 -1
  108. package/Maths/math.plane.js.map +1 -1
  109. package/Maths/math.polar.d.ts +1 -1
  110. package/Maths/math.polar.js.map +1 -1
  111. package/Maths/math.scalar.d.ts +6 -6
  112. package/Maths/math.scalar.functions.d.ts +51 -0
  113. package/Maths/math.scalar.functions.js +80 -0
  114. package/Maths/math.scalar.functions.js.map +1 -0
  115. package/Maths/math.scalar.js +48 -73
  116. package/Maths/math.scalar.js.map +1 -1
  117. package/Maths/math.vector.d.ts +571 -72
  118. package/Maths/math.vector.js +917 -119
  119. package/Maths/math.vector.js.map +1 -1
  120. package/Maths/math.viewport.d.ts +2 -1
  121. package/Maths/math.viewport.js.map +1 -1
  122. package/Maths/tensor.d.ts +411 -0
  123. package/Maths/tensor.js +3 -0
  124. package/Maths/tensor.js.map +1 -0
  125. package/Meshes/Node/Blocks/Set/setColorsBlock.js +20 -4
  126. package/Meshes/Node/Blocks/Set/setColorsBlock.js.map +1 -1
  127. package/Meshes/Node/nodeGeometry.js +2 -1
  128. package/Meshes/Node/nodeGeometry.js.map +1 -1
  129. package/Meshes/mesh.js +2 -2
  130. package/Meshes/mesh.js.map +1 -1
  131. package/Meshes/mesh.vertexData.d.ts +4 -0
  132. package/Meshes/mesh.vertexData.js +10 -0
  133. package/Meshes/mesh.vertexData.js.map +1 -1
  134. package/Meshes/transformNode.js +2 -1
  135. package/Meshes/transformNode.js.map +1 -1
  136. package/Misc/arrayTools.d.ts +2 -19
  137. package/Misc/arrayTools.js.map +1 -1
  138. package/Misc/decorators.d.ts +0 -80
  139. package/Misc/decorators.functions.d.ts +7 -0
  140. package/Misc/decorators.functions.js +52 -0
  141. package/Misc/decorators.functions.js.map +1 -0
  142. package/Misc/decorators.js +2 -318
  143. package/Misc/decorators.js.map +1 -1
  144. package/Misc/decorators.serialization.d.ts +81 -0
  145. package/Misc/decorators.serialization.js +269 -0
  146. package/Misc/decorators.serialization.js.map +1 -0
  147. package/Misc/index.d.ts +1 -0
  148. package/Misc/index.js +1 -0
  149. package/Misc/index.js.map +1 -1
  150. package/Misc/sceneRecorder.js +1 -1
  151. package/Misc/sceneRecorder.js.map +1 -1
  152. package/Misc/sceneSerializer.js +8 -1
  153. package/Misc/sceneSerializer.js.map +1 -1
  154. package/Misc/tools.functions.d.ts +14 -0
  155. package/Misc/tools.functions.js +23 -0
  156. package/Misc/tools.functions.js.map +1 -0
  157. package/Misc/tools.js +5 -6
  158. package/Misc/tools.js.map +1 -1
  159. package/Morph/morphTarget.js +2 -1
  160. package/Morph/morphTarget.js.map +1 -1
  161. package/Particles/EmitterTypes/boxParticleEmitter.js +8 -8
  162. package/Particles/EmitterTypes/boxParticleEmitter.js.map +1 -1
  163. package/Particles/baseParticleSystem.d.ts +8 -11
  164. package/Particles/baseParticleSystem.js +9 -40
  165. package/Particles/baseParticleSystem.js.map +1 -1
  166. package/Particles/gpuParticleSystem.d.ts +71 -1
  167. package/Particles/gpuParticleSystem.js +102 -1
  168. package/Particles/gpuParticleSystem.js.map +1 -1
  169. package/Particles/particle.d.ts +3 -3
  170. package/Particles/particle.js +3 -3
  171. package/Particles/particle.js.map +1 -1
  172. package/Particles/particleSystem.d.ts +81 -455
  173. package/Particles/particleSystem.functions.d.ts +61 -0
  174. package/Particles/particleSystem.functions.js +79 -0
  175. package/Particles/particleSystem.functions.js.map +1 -0
  176. package/Particles/particleSystem.js +390 -1984
  177. package/Particles/particleSystem.js.map +1 -1
  178. package/Particles/thinParticleSystem.d.ts +485 -0
  179. package/Particles/thinParticleSystem.js +1768 -0
  180. package/Particles/thinParticleSystem.js.map +1 -0
  181. package/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.js +2 -1
  182. package/PostProcesses/RenderPipeline/Pipelines/defaultRenderingPipeline.js.map +1 -1
  183. package/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.js +2 -1
  184. package/PostProcesses/RenderPipeline/Pipelines/ssao2RenderingPipeline.js.map +1 -1
  185. package/PostProcesses/RenderPipeline/Pipelines/ssrRenderingPipeline.js +2 -1
  186. package/PostProcesses/RenderPipeline/Pipelines/ssrRenderingPipeline.js.map +1 -1
  187. package/PostProcesses/RenderPipeline/Pipelines/standardRenderingPipeline.js +2 -1
  188. package/PostProcesses/RenderPipeline/Pipelines/standardRenderingPipeline.js.map +1 -1
  189. package/PostProcesses/RenderPipeline/Pipelines/taaRenderingPipeline.js +2 -1
  190. package/PostProcesses/RenderPipeline/Pipelines/taaRenderingPipeline.js.map +1 -1
  191. package/PostProcesses/blackAndWhitePostProcess.js +2 -1
  192. package/PostProcesses/blackAndWhitePostProcess.js.map +1 -1
  193. package/PostProcesses/blurPostProcess.js +2 -1
  194. package/PostProcesses/blurPostProcess.js.map +1 -1
  195. package/PostProcesses/chromaticAberrationPostProcess.js +2 -1
  196. package/PostProcesses/chromaticAberrationPostProcess.js.map +1 -1
  197. package/PostProcesses/colorCorrectionPostProcess.js +2 -1
  198. package/PostProcesses/colorCorrectionPostProcess.js.map +1 -1
  199. package/PostProcesses/convolutionPostProcess.js +2 -1
  200. package/PostProcesses/convolutionPostProcess.js.map +1 -1
  201. package/PostProcesses/displayPassPostProcess.js +1 -1
  202. package/PostProcesses/displayPassPostProcess.js.map +1 -1
  203. package/PostProcesses/filterPostProcess.js +2 -1
  204. package/PostProcesses/filterPostProcess.js.map +1 -1
  205. package/PostProcesses/fxaaPostProcess.js +1 -1
  206. package/PostProcesses/fxaaPostProcess.js.map +1 -1
  207. package/PostProcesses/grainPostProcess.js +2 -1
  208. package/PostProcesses/grainPostProcess.js.map +1 -1
  209. package/PostProcesses/imageProcessingPostProcess.js.map +1 -1
  210. package/PostProcesses/motionBlurPostProcess.js +2 -1
  211. package/PostProcesses/motionBlurPostProcess.js.map +1 -1
  212. package/PostProcesses/passPostProcess.js +1 -1
  213. package/PostProcesses/passPostProcess.js.map +1 -1
  214. package/PostProcesses/postProcess.js +2 -1
  215. package/PostProcesses/postProcess.js.map +1 -1
  216. package/PostProcesses/refractionPostProcess.js +2 -1
  217. package/PostProcesses/refractionPostProcess.js.map +1 -1
  218. package/PostProcesses/screenSpaceCurvaturePostProcess.js +2 -1
  219. package/PostProcesses/screenSpaceCurvaturePostProcess.js.map +1 -1
  220. package/PostProcesses/screenSpaceReflectionPostProcess.js +2 -1
  221. package/PostProcesses/screenSpaceReflectionPostProcess.js.map +1 -1
  222. package/PostProcesses/sharpenPostProcess.js +2 -1
  223. package/PostProcesses/sharpenPostProcess.js.map +1 -1
  224. package/Probes/reflectionProbe.js +2 -1
  225. package/Probes/reflectionProbe.js.map +1 -1
  226. package/Sprites/spriteManager.d.ts +4 -0
  227. package/Sprites/spriteManager.js.map +1 -1
  228. package/XR/features/WebXRControllerTeleportation.d.ts +9 -0
  229. package/XR/features/WebXRControllerTeleportation.js +75 -31
  230. package/XR/features/WebXRControllerTeleportation.js.map +1 -1
  231. package/node.js +2 -1
  232. package/node.js.map +1 -1
  233. package/package.json +1 -1
  234. package/types.d.ts +105 -0
  235. package/types.js.map +1 -1
@@ -0,0 +1,1768 @@
1
+ import { FactorGradient, ColorGradient, Color3Gradient, GradientHelper } from "../Misc/gradients.js";
2
+ import { Observable } from "../Misc/observable.js";
3
+ import { Vector3, Matrix, Vector4, TmpVectors } from "../Maths/math.vector.js";
4
+ import { VertexBuffer, Buffer } from "../Buffers/buffer.js";
5
+ import { RawTexture } from "../Materials/Textures/rawTexture.js";
6
+ import { EngineStore } from "../Engines/engineStore.js";
7
+ import { BaseParticleSystem } from "./baseParticleSystem.js";
8
+ import { Particle } from "./particle.js";
9
+
10
+ import { DrawWrapper } from "../Materials/drawWrapper.js";
11
+ import "../Shaders/particles.fragment.js";
12
+ import "../Shaders/particles.vertex.js";
13
+ import { Color4, Color3, TmpColors } from "../Maths/math.color.js";
14
+ import "../Engines/Extensions/engine.alpha.js";
15
+ import { addClipPlaneUniforms, prepareStringDefinesForClipPlanes, bindClipPlane } from "../Materials/clipPlaneMaterialHelper.js";
16
+ import { BindFogParameters, BindLogDepth } from "../Materials/materialHelper.functions.js";
17
+ import { BoxParticleEmitter } from "./EmitterTypes/boxParticleEmitter.js";
18
+ import { Clamp, Lerp, RandomRange } from "../Maths/math.scalar.functions.js";
19
+ import { PrepareSamplersForImageProcessing, PrepareUniformsForImageProcessing } from "../Materials/imageProcessingConfiguration.functions.js";
20
+ /**
21
+ * This represents a thin particle system in Babylon.
22
+ * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
23
+ * Particles can take different shapes while emitted like box, sphere, cone or you can write your custom function.
24
+ * This thin version contains a limited subset of the total features in order to provide users with a way to get particles but with a smaller footprint
25
+ * @example https://doc.babylonjs.com/features/featuresDeepDive/particles/particle_system/particle_system_intro
26
+ */
27
+ export class ThinParticleSystem extends BaseParticleSystem {
28
+ /**
29
+ * Sets a callback that will be triggered when the system is disposed
30
+ */
31
+ set onDispose(callback) {
32
+ if (this._onDisposeObserver) {
33
+ this.onDisposeObservable.remove(this._onDisposeObserver);
34
+ }
35
+ this._onDisposeObserver = this.onDisposeObservable.add(callback);
36
+ }
37
+ /** Gets or sets a boolean indicating that ramp gradients must be used
38
+ * @see https://doc.babylonjs.com/features/featuresDeepDive/particles/particle_system/particle_system_intro#ramp-gradients
39
+ */
40
+ get useRampGradients() {
41
+ return this._useRampGradients;
42
+ }
43
+ set useRampGradients(value) {
44
+ if (this._useRampGradients === value) {
45
+ return;
46
+ }
47
+ this._useRampGradients = value;
48
+ this._resetEffect();
49
+ }
50
+ /**
51
+ * Gets the current list of active particles
52
+ */
53
+ get particles() {
54
+ return this._particles;
55
+ }
56
+ /**
57
+ * Gets the number of particles active at the same time.
58
+ * @returns The number of active particles.
59
+ */
60
+ getActiveCount() {
61
+ return this._particles.length;
62
+ }
63
+ /**
64
+ * Returns the string "ParticleSystem"
65
+ * @returns a string containing the class name
66
+ */
67
+ getClassName() {
68
+ return "ParticleSystem";
69
+ }
70
+ /**
71
+ * Gets a boolean indicating that the system is stopping
72
+ * @returns true if the system is currently stopping
73
+ */
74
+ isStopping() {
75
+ return this._stopped && this.isAlive();
76
+ }
77
+ /**
78
+ * Gets the custom effect used to render the particles
79
+ * @param blendMode Blend mode for which the effect should be retrieved
80
+ * @returns The effect
81
+ */
82
+ getCustomEffect(blendMode = 0) {
83
+ return this._customWrappers[blendMode]?.effect ?? this._customWrappers[0].effect;
84
+ }
85
+ _getCustomDrawWrapper(blendMode = 0) {
86
+ return this._customWrappers[blendMode] ?? this._customWrappers[0];
87
+ }
88
+ /**
89
+ * Sets the custom effect used to render the particles
90
+ * @param effect The effect to set
91
+ * @param blendMode Blend mode for which the effect should be set
92
+ */
93
+ setCustomEffect(effect, blendMode = 0) {
94
+ this._customWrappers[blendMode] = new DrawWrapper(this._engine);
95
+ this._customWrappers[blendMode].effect = effect;
96
+ if (this._customWrappers[blendMode].drawContext) {
97
+ this._customWrappers[blendMode].drawContext.useInstancing = this._useInstancing;
98
+ }
99
+ }
100
+ /**
101
+ * Observable that will be called just before the particles are drawn
102
+ */
103
+ get onBeforeDrawParticlesObservable() {
104
+ if (!this._onBeforeDrawParticlesObservable) {
105
+ this._onBeforeDrawParticlesObservable = new Observable();
106
+ }
107
+ return this._onBeforeDrawParticlesObservable;
108
+ }
109
+ /**
110
+ * Gets the name of the particle vertex shader
111
+ */
112
+ get vertexShaderName() {
113
+ return "particles";
114
+ }
115
+ /**
116
+ * Gets the vertex buffers used by the particle system
117
+ */
118
+ get vertexBuffers() {
119
+ return this._vertexBuffers;
120
+ }
121
+ /**
122
+ * Gets the index buffer used by the particle system (or null if no index buffer is used (if _useInstancing=true))
123
+ */
124
+ get indexBuffer() {
125
+ return this._indexBuffer;
126
+ }
127
+ /**
128
+ * Instantiates a particle system.
129
+ * Particles are often small sprites used to simulate hard-to-reproduce phenomena like fire, smoke, water, or abstract visual effects like magic glitter and faery dust.
130
+ * @param name The name of the particle system
131
+ * @param capacity The max number of particles alive at the same time
132
+ * @param sceneOrEngine The scene the particle system belongs to or the engine to use if no scene
133
+ * @param customEffect a custom effect used to change the way particles are rendered by default
134
+ * @param isAnimationSheetEnabled Must be true if using a spritesheet to animate the particles texture
135
+ * @param epsilon Offset used to render the particles
136
+ */
137
+ constructor(name, capacity, sceneOrEngine, customEffect = null, isAnimationSheetEnabled = false, epsilon = 0.01) {
138
+ super(name);
139
+ this._emitterInverseWorldMatrix = Matrix.Identity();
140
+ /**
141
+ * @internal
142
+ */
143
+ this._inheritedVelocityOffset = new Vector3();
144
+ /**
145
+ * An event triggered when the system is disposed
146
+ */
147
+ this.onDisposeObservable = new Observable();
148
+ /**
149
+ * An event triggered when the system is stopped
150
+ */
151
+ this.onStoppedObservable = new Observable();
152
+ this._particles = new Array();
153
+ this._stockParticles = new Array();
154
+ this._newPartsExcess = 0;
155
+ this._vertexBuffers = {};
156
+ this._scaledColorStep = new Color4(0, 0, 0, 0);
157
+ this._colorDiff = new Color4(0, 0, 0, 0);
158
+ this._scaledDirection = Vector3.Zero();
159
+ this._scaledGravity = Vector3.Zero();
160
+ this._currentRenderId = -1;
161
+ this._useInstancing = false;
162
+ this._started = false;
163
+ this._stopped = false;
164
+ this._actualFrame = 0;
165
+ /** @internal */
166
+ this._currentEmitRate1 = 0;
167
+ /** @internal */
168
+ this._currentEmitRate2 = 0;
169
+ /** @internal */
170
+ this._currentStartSize1 = 0;
171
+ /** @internal */
172
+ this._currentStartSize2 = 0;
173
+ /** Indicates that the update of particles is done in the animate function */
174
+ this.updateInAnimate = true;
175
+ this._rawTextureWidth = 256;
176
+ this._useRampGradients = false;
177
+ /**
178
+ * Specifies if the particles are updated in emitter local space or world space
179
+ */
180
+ this.isLocal = false;
181
+ /** Indicates that the particle system is CPU based */
182
+ this.isGPU = false;
183
+ /** @internal */
184
+ this._onBeforeDrawParticlesObservable = null;
185
+ /** @internal */
186
+ this._emitFromParticle = (particle) => {
187
+ // Do nothing
188
+ };
189
+ // start of sub system methods
190
+ /**
191
+ * "Recycles" one of the particle by copying it back to the "stock" of particles and removing it from the active list.
192
+ * Its lifetime will start back at 0.
193
+ * @param particle
194
+ */
195
+ this.recycleParticle = (particle) => {
196
+ // move particle from activeParticle list to stock particles
197
+ const lastParticle = this._particles.pop();
198
+ if (lastParticle !== particle) {
199
+ lastParticle.copyTo(particle);
200
+ }
201
+ this._stockParticles.push(lastParticle);
202
+ };
203
+ this._createParticle = () => {
204
+ let particle;
205
+ if (this._stockParticles.length !== 0) {
206
+ particle = this._stockParticles.pop();
207
+ particle._reset();
208
+ }
209
+ else {
210
+ particle = new Particle(this);
211
+ }
212
+ this._prepareParticle(particle);
213
+ return particle;
214
+ };
215
+ this._capacity = capacity;
216
+ this._epsilon = epsilon;
217
+ this._isAnimationSheetEnabled = isAnimationSheetEnabled;
218
+ if (!sceneOrEngine || sceneOrEngine.getClassName() === "Scene") {
219
+ this._scene = sceneOrEngine || EngineStore.LastCreatedScene;
220
+ this._engine = this._scene.getEngine();
221
+ this.uniqueId = this._scene.getUniqueId();
222
+ this._scene.particleSystems.push(this);
223
+ }
224
+ else {
225
+ this._engine = sceneOrEngine;
226
+ this.defaultProjectionMatrix = Matrix.PerspectiveFovLH(0.8, 1, 0.1, 100, this._engine.isNDCHalfZRange);
227
+ }
228
+ if (this._engine.getCaps().vertexArrayObject) {
229
+ this._vertexArrayObject = null;
230
+ }
231
+ // Setup the default processing configuration to the scene.
232
+ this._attachImageProcessingConfiguration(null);
233
+ // eslint-disable-next-line @typescript-eslint/naming-convention
234
+ this._customWrappers = { 0: new DrawWrapper(this._engine) };
235
+ this._customWrappers[0].effect = customEffect;
236
+ this._drawWrappers = [];
237
+ this._useInstancing = this._engine.getCaps().instancedArrays;
238
+ this._createIndexBuffer();
239
+ this._createVertexBuffers();
240
+ // Default emitter type
241
+ this.particleEmitterType = new BoxParticleEmitter();
242
+ let noiseTextureData = null;
243
+ // Update
244
+ this.updateFunction = (particles) => {
245
+ let noiseTextureSize = null;
246
+ if (this.noiseTexture) {
247
+ // We need to get texture data back to CPU
248
+ noiseTextureSize = this.noiseTexture.getSize();
249
+ this.noiseTexture.getContent()?.then((data) => {
250
+ noiseTextureData = data;
251
+ });
252
+ }
253
+ const sameParticleArray = particles === this._particles;
254
+ for (let index = 0; index < particles.length; index++) {
255
+ const particle = particles[index];
256
+ let scaledUpdateSpeed = this._scaledUpdateSpeed;
257
+ const previousAge = particle.age;
258
+ particle.age += scaledUpdateSpeed;
259
+ // Evaluate step to death
260
+ if (particle.age > particle.lifeTime) {
261
+ const diff = particle.age - previousAge;
262
+ const oldDiff = particle.lifeTime - previousAge;
263
+ scaledUpdateSpeed = (oldDiff * scaledUpdateSpeed) / diff;
264
+ particle.age = particle.lifeTime;
265
+ }
266
+ const ratio = particle.age / particle.lifeTime;
267
+ // Color
268
+ if (this._colorGradients && this._colorGradients.length > 0) {
269
+ GradientHelper.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
270
+ if (currentGradient !== particle._currentColorGradient) {
271
+ particle._currentColor1.copyFrom(particle._currentColor2);
272
+ nextGradient.getColorToRef(particle._currentColor2);
273
+ particle._currentColorGradient = currentGradient;
274
+ }
275
+ Color4.LerpToRef(particle._currentColor1, particle._currentColor2, scale, particle.color);
276
+ });
277
+ }
278
+ else {
279
+ particle.colorStep.scaleToRef(scaledUpdateSpeed, this._scaledColorStep);
280
+ particle.color.addInPlace(this._scaledColorStep);
281
+ if (particle.color.a < 0) {
282
+ particle.color.a = 0;
283
+ }
284
+ }
285
+ // Angular speed
286
+ if (this._angularSpeedGradients && this._angularSpeedGradients.length > 0) {
287
+ GradientHelper.GetCurrentGradient(ratio, this._angularSpeedGradients, (currentGradient, nextGradient, scale) => {
288
+ if (currentGradient !== particle._currentAngularSpeedGradient) {
289
+ particle._currentAngularSpeed1 = particle._currentAngularSpeed2;
290
+ particle._currentAngularSpeed2 = nextGradient.getFactor();
291
+ particle._currentAngularSpeedGradient = currentGradient;
292
+ }
293
+ particle.angularSpeed = Lerp(particle._currentAngularSpeed1, particle._currentAngularSpeed2, scale);
294
+ });
295
+ }
296
+ particle.angle += particle.angularSpeed * scaledUpdateSpeed;
297
+ // Direction
298
+ let directionScale = scaledUpdateSpeed;
299
+ /// Velocity
300
+ if (this._velocityGradients && this._velocityGradients.length > 0) {
301
+ GradientHelper.GetCurrentGradient(ratio, this._velocityGradients, (currentGradient, nextGradient, scale) => {
302
+ if (currentGradient !== particle._currentVelocityGradient) {
303
+ particle._currentVelocity1 = particle._currentVelocity2;
304
+ particle._currentVelocity2 = nextGradient.getFactor();
305
+ particle._currentVelocityGradient = currentGradient;
306
+ }
307
+ directionScale *= Lerp(particle._currentVelocity1, particle._currentVelocity2, scale);
308
+ });
309
+ }
310
+ particle.direction.scaleToRef(directionScale, this._scaledDirection);
311
+ /// Limit velocity
312
+ if (this._limitVelocityGradients && this._limitVelocityGradients.length > 0) {
313
+ GradientHelper.GetCurrentGradient(ratio, this._limitVelocityGradients, (currentGradient, nextGradient, scale) => {
314
+ if (currentGradient !== particle._currentLimitVelocityGradient) {
315
+ particle._currentLimitVelocity1 = particle._currentLimitVelocity2;
316
+ particle._currentLimitVelocity2 = nextGradient.getFactor();
317
+ particle._currentLimitVelocityGradient = currentGradient;
318
+ }
319
+ const limitVelocity = Lerp(particle._currentLimitVelocity1, particle._currentLimitVelocity2, scale);
320
+ const currentVelocity = particle.direction.length();
321
+ if (currentVelocity > limitVelocity) {
322
+ particle.direction.scaleInPlace(this.limitVelocityDamping);
323
+ }
324
+ });
325
+ }
326
+ /// Drag
327
+ if (this._dragGradients && this._dragGradients.length > 0) {
328
+ GradientHelper.GetCurrentGradient(ratio, this._dragGradients, (currentGradient, nextGradient, scale) => {
329
+ if (currentGradient !== particle._currentDragGradient) {
330
+ particle._currentDrag1 = particle._currentDrag2;
331
+ particle._currentDrag2 = nextGradient.getFactor();
332
+ particle._currentDragGradient = currentGradient;
333
+ }
334
+ const drag = Lerp(particle._currentDrag1, particle._currentDrag2, scale);
335
+ this._scaledDirection.scaleInPlace(1.0 - drag);
336
+ });
337
+ }
338
+ if (this.isLocal && particle._localPosition) {
339
+ particle._localPosition.addInPlace(this._scaledDirection);
340
+ Vector3.TransformCoordinatesToRef(particle._localPosition, this._emitterWorldMatrix, particle.position);
341
+ }
342
+ else {
343
+ particle.position.addInPlace(this._scaledDirection);
344
+ }
345
+ // Noise
346
+ if (noiseTextureData && noiseTextureSize && particle._randomNoiseCoordinates1) {
347
+ const fetchedColorR = this._fetchR(particle._randomNoiseCoordinates1.x, particle._randomNoiseCoordinates1.y, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
348
+ const fetchedColorG = this._fetchR(particle._randomNoiseCoordinates1.z, particle._randomNoiseCoordinates2.x, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
349
+ const fetchedColorB = this._fetchR(particle._randomNoiseCoordinates2.y, particle._randomNoiseCoordinates2.z, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
350
+ const force = TmpVectors.Vector3[0];
351
+ const scaledForce = TmpVectors.Vector3[1];
352
+ force.copyFromFloats((2 * fetchedColorR - 1) * this.noiseStrength.x, (2 * fetchedColorG - 1) * this.noiseStrength.y, (2 * fetchedColorB - 1) * this.noiseStrength.z);
353
+ force.scaleToRef(scaledUpdateSpeed, scaledForce);
354
+ particle.direction.addInPlace(scaledForce);
355
+ }
356
+ // Gravity
357
+ this.gravity.scaleToRef(scaledUpdateSpeed, this._scaledGravity);
358
+ particle.direction.addInPlace(this._scaledGravity);
359
+ // Size
360
+ if (this._sizeGradients && this._sizeGradients.length > 0) {
361
+ GradientHelper.GetCurrentGradient(ratio, this._sizeGradients, (currentGradient, nextGradient, scale) => {
362
+ if (currentGradient !== particle._currentSizeGradient) {
363
+ particle._currentSize1 = particle._currentSize2;
364
+ particle._currentSize2 = nextGradient.getFactor();
365
+ particle._currentSizeGradient = currentGradient;
366
+ }
367
+ particle.size = Lerp(particle._currentSize1, particle._currentSize2, scale);
368
+ });
369
+ }
370
+ // Remap data
371
+ if (this._useRampGradients) {
372
+ if (this._colorRemapGradients && this._colorRemapGradients.length > 0) {
373
+ GradientHelper.GetCurrentGradient(ratio, this._colorRemapGradients, (currentGradient, nextGradient, scale) => {
374
+ const min = Lerp(currentGradient.factor1, nextGradient.factor1, scale);
375
+ const max = Lerp(currentGradient.factor2, nextGradient.factor2, scale);
376
+ particle.remapData.x = min;
377
+ particle.remapData.y = max - min;
378
+ });
379
+ }
380
+ if (this._alphaRemapGradients && this._alphaRemapGradients.length > 0) {
381
+ GradientHelper.GetCurrentGradient(ratio, this._alphaRemapGradients, (currentGradient, nextGradient, scale) => {
382
+ const min = Lerp(currentGradient.factor1, nextGradient.factor1, scale);
383
+ const max = Lerp(currentGradient.factor2, nextGradient.factor2, scale);
384
+ particle.remapData.z = min;
385
+ particle.remapData.w = max - min;
386
+ });
387
+ }
388
+ }
389
+ if (this._isAnimationSheetEnabled) {
390
+ particle.updateCellIndex();
391
+ }
392
+ // Update the position of the attached sub-emitters to match their attached particle
393
+ particle._inheritParticleInfoToSubEmitters();
394
+ if (particle.age >= particle.lifeTime) {
395
+ // Recycle by swapping with last particle
396
+ this._emitFromParticle(particle);
397
+ if (particle._attachedSubEmitters) {
398
+ particle._attachedSubEmitters.forEach((subEmitter) => {
399
+ subEmitter.particleSystem.disposeOnStop = true;
400
+ subEmitter.particleSystem.stop();
401
+ });
402
+ particle._attachedSubEmitters = null;
403
+ }
404
+ this.recycleParticle(particle);
405
+ if (sameParticleArray) {
406
+ index--;
407
+ }
408
+ continue;
409
+ }
410
+ }
411
+ };
412
+ }
413
+ serialize(serializeTexture) {
414
+ throw new Error("Method not implemented.");
415
+ }
416
+ /**
417
+ * Clones the particle system.
418
+ * @param name The name of the cloned object
419
+ * @param newEmitter The new emitter to use
420
+ * @param cloneTexture Also clone the textures if true
421
+ */
422
+ clone(name, newEmitter, cloneTexture = false) {
423
+ throw new Error("Method not implemented.");
424
+ }
425
+ _addFactorGradient(factorGradients, gradient, factor, factor2) {
426
+ const newGradient = new FactorGradient(gradient, factor, factor2);
427
+ factorGradients.push(newGradient);
428
+ factorGradients.sort((a, b) => {
429
+ if (a.gradient < b.gradient) {
430
+ return -1;
431
+ }
432
+ else if (a.gradient > b.gradient) {
433
+ return 1;
434
+ }
435
+ return 0;
436
+ });
437
+ }
438
+ _removeFactorGradient(factorGradients, gradient) {
439
+ if (!factorGradients) {
440
+ return;
441
+ }
442
+ let index = 0;
443
+ for (const factorGradient of factorGradients) {
444
+ if (factorGradient.gradient === gradient) {
445
+ factorGradients.splice(index, 1);
446
+ break;
447
+ }
448
+ index++;
449
+ }
450
+ }
451
+ /**
452
+ * Adds a new life time gradient
453
+ * @param gradient defines the gradient to use (between 0 and 1)
454
+ * @param factor defines the life time factor to affect to the specified gradient
455
+ * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
456
+ * @returns the current particle system
457
+ */
458
+ addLifeTimeGradient(gradient, factor, factor2) {
459
+ if (!this._lifeTimeGradients) {
460
+ this._lifeTimeGradients = [];
461
+ }
462
+ this._addFactorGradient(this._lifeTimeGradients, gradient, factor, factor2);
463
+ return this;
464
+ }
465
+ /**
466
+ * Remove a specific life time gradient
467
+ * @param gradient defines the gradient to remove
468
+ * @returns the current particle system
469
+ */
470
+ removeLifeTimeGradient(gradient) {
471
+ this._removeFactorGradient(this._lifeTimeGradients, gradient);
472
+ return this;
473
+ }
474
+ /**
475
+ * Adds a new size gradient
476
+ * @param gradient defines the gradient to use (between 0 and 1)
477
+ * @param factor defines the size factor to affect to the specified gradient
478
+ * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
479
+ * @returns the current particle system
480
+ */
481
+ addSizeGradient(gradient, factor, factor2) {
482
+ if (!this._sizeGradients) {
483
+ this._sizeGradients = [];
484
+ }
485
+ this._addFactorGradient(this._sizeGradients, gradient, factor, factor2);
486
+ return this;
487
+ }
488
+ /**
489
+ * Remove a specific size gradient
490
+ * @param gradient defines the gradient to remove
491
+ * @returns the current particle system
492
+ */
493
+ removeSizeGradient(gradient) {
494
+ this._removeFactorGradient(this._sizeGradients, gradient);
495
+ return this;
496
+ }
497
+ /**
498
+ * Adds a new color remap gradient
499
+ * @param gradient defines the gradient to use (between 0 and 1)
500
+ * @param min defines the color remap minimal range
501
+ * @param max defines the color remap maximal range
502
+ * @returns the current particle system
503
+ */
504
+ addColorRemapGradient(gradient, min, max) {
505
+ if (!this._colorRemapGradients) {
506
+ this._colorRemapGradients = [];
507
+ }
508
+ this._addFactorGradient(this._colorRemapGradients, gradient, min, max);
509
+ return this;
510
+ }
511
+ /**
512
+ * Remove a specific color remap gradient
513
+ * @param gradient defines the gradient to remove
514
+ * @returns the current particle system
515
+ */
516
+ removeColorRemapGradient(gradient) {
517
+ this._removeFactorGradient(this._colorRemapGradients, gradient);
518
+ return this;
519
+ }
520
+ /**
521
+ * Adds a new alpha remap gradient
522
+ * @param gradient defines the gradient to use (between 0 and 1)
523
+ * @param min defines the alpha remap minimal range
524
+ * @param max defines the alpha remap maximal range
525
+ * @returns the current particle system
526
+ */
527
+ addAlphaRemapGradient(gradient, min, max) {
528
+ if (!this._alphaRemapGradients) {
529
+ this._alphaRemapGradients = [];
530
+ }
531
+ this._addFactorGradient(this._alphaRemapGradients, gradient, min, max);
532
+ return this;
533
+ }
534
+ /**
535
+ * Remove a specific alpha remap gradient
536
+ * @param gradient defines the gradient to remove
537
+ * @returns the current particle system
538
+ */
539
+ removeAlphaRemapGradient(gradient) {
540
+ this._removeFactorGradient(this._alphaRemapGradients, gradient);
541
+ return this;
542
+ }
543
+ /**
544
+ * Adds a new angular speed gradient
545
+ * @param gradient defines the gradient to use (between 0 and 1)
546
+ * @param factor defines the angular speed to affect to the specified gradient
547
+ * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
548
+ * @returns the current particle system
549
+ */
550
+ addAngularSpeedGradient(gradient, factor, factor2) {
551
+ if (!this._angularSpeedGradients) {
552
+ this._angularSpeedGradients = [];
553
+ }
554
+ this._addFactorGradient(this._angularSpeedGradients, gradient, factor, factor2);
555
+ return this;
556
+ }
557
+ /**
558
+ * Remove a specific angular speed gradient
559
+ * @param gradient defines the gradient to remove
560
+ * @returns the current particle system
561
+ */
562
+ removeAngularSpeedGradient(gradient) {
563
+ this._removeFactorGradient(this._angularSpeedGradients, gradient);
564
+ return this;
565
+ }
566
+ /**
567
+ * Adds a new velocity gradient
568
+ * @param gradient defines the gradient to use (between 0 and 1)
569
+ * @param factor defines the velocity to affect to the specified gradient
570
+ * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
571
+ * @returns the current particle system
572
+ */
573
+ addVelocityGradient(gradient, factor, factor2) {
574
+ if (!this._velocityGradients) {
575
+ this._velocityGradients = [];
576
+ }
577
+ this._addFactorGradient(this._velocityGradients, gradient, factor, factor2);
578
+ return this;
579
+ }
580
+ /**
581
+ * Remove a specific velocity gradient
582
+ * @param gradient defines the gradient to remove
583
+ * @returns the current particle system
584
+ */
585
+ removeVelocityGradient(gradient) {
586
+ this._removeFactorGradient(this._velocityGradients, gradient);
587
+ return this;
588
+ }
589
+ /**
590
+ * Adds a new limit velocity gradient
591
+ * @param gradient defines the gradient to use (between 0 and 1)
592
+ * @param factor defines the limit velocity value to affect to the specified gradient
593
+ * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
594
+ * @returns the current particle system
595
+ */
596
+ addLimitVelocityGradient(gradient, factor, factor2) {
597
+ if (!this._limitVelocityGradients) {
598
+ this._limitVelocityGradients = [];
599
+ }
600
+ this._addFactorGradient(this._limitVelocityGradients, gradient, factor, factor2);
601
+ return this;
602
+ }
603
+ /**
604
+ * Remove a specific limit velocity gradient
605
+ * @param gradient defines the gradient to remove
606
+ * @returns the current particle system
607
+ */
608
+ removeLimitVelocityGradient(gradient) {
609
+ this._removeFactorGradient(this._limitVelocityGradients, gradient);
610
+ return this;
611
+ }
612
+ /**
613
+ * Adds a new drag gradient
614
+ * @param gradient defines the gradient to use (between 0 and 1)
615
+ * @param factor defines the drag value to affect to the specified gradient
616
+ * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
617
+ * @returns the current particle system
618
+ */
619
+ addDragGradient(gradient, factor, factor2) {
620
+ if (!this._dragGradients) {
621
+ this._dragGradients = [];
622
+ }
623
+ this._addFactorGradient(this._dragGradients, gradient, factor, factor2);
624
+ return this;
625
+ }
626
+ /**
627
+ * Remove a specific drag gradient
628
+ * @param gradient defines the gradient to remove
629
+ * @returns the current particle system
630
+ */
631
+ removeDragGradient(gradient) {
632
+ this._removeFactorGradient(this._dragGradients, gradient);
633
+ return this;
634
+ }
635
+ /**
636
+ * Adds a new emit rate gradient (please note that this will only work if you set the targetStopDuration property)
637
+ * @param gradient defines the gradient to use (between 0 and 1)
638
+ * @param factor defines the emit rate value to affect to the specified gradient
639
+ * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
640
+ * @returns the current particle system
641
+ */
642
+ addEmitRateGradient(gradient, factor, factor2) {
643
+ if (!this._emitRateGradients) {
644
+ this._emitRateGradients = [];
645
+ }
646
+ this._addFactorGradient(this._emitRateGradients, gradient, factor, factor2);
647
+ return this;
648
+ }
649
+ /**
650
+ * Remove a specific emit rate gradient
651
+ * @param gradient defines the gradient to remove
652
+ * @returns the current particle system
653
+ */
654
+ removeEmitRateGradient(gradient) {
655
+ this._removeFactorGradient(this._emitRateGradients, gradient);
656
+ return this;
657
+ }
658
+ /**
659
+ * Adds a new start size gradient (please note that this will only work if you set the targetStopDuration property)
660
+ * @param gradient defines the gradient to use (between 0 and 1)
661
+ * @param factor defines the start size value to affect to the specified gradient
662
+ * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
663
+ * @returns the current particle system
664
+ */
665
+ addStartSizeGradient(gradient, factor, factor2) {
666
+ if (!this._startSizeGradients) {
667
+ this._startSizeGradients = [];
668
+ }
669
+ this._addFactorGradient(this._startSizeGradients, gradient, factor, factor2);
670
+ return this;
671
+ }
672
+ /**
673
+ * Remove a specific start size gradient
674
+ * @param gradient defines the gradient to remove
675
+ * @returns the current particle system
676
+ */
677
+ removeStartSizeGradient(gradient) {
678
+ this._removeFactorGradient(this._startSizeGradients, gradient);
679
+ return this;
680
+ }
681
+ _createRampGradientTexture() {
682
+ if (!this._rampGradients || !this._rampGradients.length || this._rampGradientsTexture || !this._scene) {
683
+ return;
684
+ }
685
+ const data = new Uint8Array(this._rawTextureWidth * 4);
686
+ const tmpColor = TmpColors.Color3[0];
687
+ for (let x = 0; x < this._rawTextureWidth; x++) {
688
+ const ratio = x / this._rawTextureWidth;
689
+ GradientHelper.GetCurrentGradient(ratio, this._rampGradients, (currentGradient, nextGradient, scale) => {
690
+ Color3.LerpToRef(currentGradient.color, nextGradient.color, scale, tmpColor);
691
+ data[x * 4] = tmpColor.r * 255;
692
+ data[x * 4 + 1] = tmpColor.g * 255;
693
+ data[x * 4 + 2] = tmpColor.b * 255;
694
+ data[x * 4 + 3] = 255;
695
+ });
696
+ }
697
+ this._rampGradientsTexture = RawTexture.CreateRGBATexture(data, this._rawTextureWidth, 1, this._scene, false, false, 1);
698
+ }
699
+ /**
700
+ * Gets the current list of ramp gradients.
701
+ * You must use addRampGradient and removeRampGradient to update this list
702
+ * @returns the list of ramp gradients
703
+ */
704
+ getRampGradients() {
705
+ return this._rampGradients;
706
+ }
707
+ /** Force the system to rebuild all gradients that need to be resync */
708
+ forceRefreshGradients() {
709
+ this._syncRampGradientTexture();
710
+ }
711
+ _syncRampGradientTexture() {
712
+ if (!this._rampGradients) {
713
+ return;
714
+ }
715
+ this._rampGradients.sort((a, b) => {
716
+ if (a.gradient < b.gradient) {
717
+ return -1;
718
+ }
719
+ else if (a.gradient > b.gradient) {
720
+ return 1;
721
+ }
722
+ return 0;
723
+ });
724
+ if (this._rampGradientsTexture) {
725
+ this._rampGradientsTexture.dispose();
726
+ this._rampGradientsTexture = null;
727
+ }
728
+ this._createRampGradientTexture();
729
+ }
730
+ /**
731
+ * Adds a new ramp gradient used to remap particle colors
732
+ * @param gradient defines the gradient to use (between 0 and 1)
733
+ * @param color defines the color to affect to the specified gradient
734
+ * @returns the current particle system
735
+ */
736
+ addRampGradient(gradient, color) {
737
+ if (!this._rampGradients) {
738
+ this._rampGradients = [];
739
+ }
740
+ const rampGradient = new Color3Gradient(gradient, color);
741
+ this._rampGradients.push(rampGradient);
742
+ this._syncRampGradientTexture();
743
+ return this;
744
+ }
745
+ /**
746
+ * Remove a specific ramp gradient
747
+ * @param gradient defines the gradient to remove
748
+ * @returns the current particle system
749
+ */
750
+ removeRampGradient(gradient) {
751
+ this._removeGradientAndTexture(gradient, this._rampGradients, this._rampGradientsTexture);
752
+ this._rampGradientsTexture = null;
753
+ if (this._rampGradients && this._rampGradients.length > 0) {
754
+ this._createRampGradientTexture();
755
+ }
756
+ return this;
757
+ }
758
+ /**
759
+ * Adds a new color gradient
760
+ * @param gradient defines the gradient to use (between 0 and 1)
761
+ * @param color1 defines the color to affect to the specified gradient
762
+ * @param color2 defines an additional color used to define a range ([color, color2]) with main color to pick the final color from
763
+ * @returns this particle system
764
+ */
765
+ addColorGradient(gradient, color1, color2) {
766
+ if (!this._colorGradients) {
767
+ this._colorGradients = [];
768
+ }
769
+ const colorGradient = new ColorGradient(gradient, color1, color2);
770
+ this._colorGradients.push(colorGradient);
771
+ this._colorGradients.sort((a, b) => {
772
+ if (a.gradient < b.gradient) {
773
+ return -1;
774
+ }
775
+ else if (a.gradient > b.gradient) {
776
+ return 1;
777
+ }
778
+ return 0;
779
+ });
780
+ return this;
781
+ }
782
+ /**
783
+ * Remove a specific color gradient
784
+ * @param gradient defines the gradient to remove
785
+ * @returns this particle system
786
+ */
787
+ removeColorGradient(gradient) {
788
+ if (!this._colorGradients) {
789
+ return this;
790
+ }
791
+ let index = 0;
792
+ for (const colorGradient of this._colorGradients) {
793
+ if (colorGradient.gradient === gradient) {
794
+ this._colorGradients.splice(index, 1);
795
+ break;
796
+ }
797
+ index++;
798
+ }
799
+ return this;
800
+ }
801
+ /**
802
+ * Resets the draw wrappers cache
803
+ */
804
+ resetDrawCache() {
805
+ for (const drawWrappers of this._drawWrappers) {
806
+ if (drawWrappers) {
807
+ for (const drawWrapper of drawWrappers) {
808
+ drawWrapper?.dispose();
809
+ }
810
+ }
811
+ }
812
+ this._drawWrappers = [];
813
+ }
814
+ _fetchR(u, v, width, height, pixels) {
815
+ u = Math.abs(u) * 0.5 + 0.5;
816
+ v = Math.abs(v) * 0.5 + 0.5;
817
+ const wrappedU = (u * width) % width | 0;
818
+ const wrappedV = (v * height) % height | 0;
819
+ const position = (wrappedU + wrappedV * width) * 4;
820
+ return pixels[position] / 255;
821
+ }
822
+ _reset() {
823
+ this._resetEffect();
824
+ }
825
+ _resetEffect() {
826
+ if (this._vertexBuffer) {
827
+ this._vertexBuffer.dispose();
828
+ this._vertexBuffer = null;
829
+ }
830
+ if (this._spriteBuffer) {
831
+ this._spriteBuffer.dispose();
832
+ this._spriteBuffer = null;
833
+ }
834
+ if (this._vertexArrayObject) {
835
+ this._engine.releaseVertexArrayObject(this._vertexArrayObject);
836
+ this._vertexArrayObject = null;
837
+ }
838
+ this._createVertexBuffers();
839
+ }
840
+ _createVertexBuffers() {
841
+ this._vertexBufferSize = this._useInstancing ? 10 : 12;
842
+ if (this._isAnimationSheetEnabled) {
843
+ this._vertexBufferSize += 1;
844
+ }
845
+ if (!this._isBillboardBased ||
846
+ this.billboardMode === 8 ||
847
+ this.billboardMode === 9) {
848
+ this._vertexBufferSize += 3;
849
+ }
850
+ if (this._useRampGradients) {
851
+ this._vertexBufferSize += 4;
852
+ }
853
+ const engine = this._engine;
854
+ const vertexSize = this._vertexBufferSize * (this._useInstancing ? 1 : 4);
855
+ this._vertexData = new Float32Array(this._capacity * vertexSize);
856
+ this._vertexBuffer = new Buffer(engine, this._vertexData, true, vertexSize);
857
+ let dataOffset = 0;
858
+ const positions = this._vertexBuffer.createVertexBuffer(VertexBuffer.PositionKind, dataOffset, 3, this._vertexBufferSize, this._useInstancing);
859
+ this._vertexBuffers[VertexBuffer.PositionKind] = positions;
860
+ dataOffset += 3;
861
+ const colors = this._vertexBuffer.createVertexBuffer(VertexBuffer.ColorKind, dataOffset, 4, this._vertexBufferSize, this._useInstancing);
862
+ this._vertexBuffers[VertexBuffer.ColorKind] = colors;
863
+ dataOffset += 4;
864
+ const options = this._vertexBuffer.createVertexBuffer("angle", dataOffset, 1, this._vertexBufferSize, this._useInstancing);
865
+ this._vertexBuffers["angle"] = options;
866
+ dataOffset += 1;
867
+ const size = this._vertexBuffer.createVertexBuffer("size", dataOffset, 2, this._vertexBufferSize, this._useInstancing);
868
+ this._vertexBuffers["size"] = size;
869
+ dataOffset += 2;
870
+ if (this._isAnimationSheetEnabled) {
871
+ const cellIndexBuffer = this._vertexBuffer.createVertexBuffer("cellIndex", dataOffset, 1, this._vertexBufferSize, this._useInstancing);
872
+ this._vertexBuffers["cellIndex"] = cellIndexBuffer;
873
+ dataOffset += 1;
874
+ }
875
+ if (!this._isBillboardBased ||
876
+ this.billboardMode === 8 ||
877
+ this.billboardMode === 9) {
878
+ const directionBuffer = this._vertexBuffer.createVertexBuffer("direction", dataOffset, 3, this._vertexBufferSize, this._useInstancing);
879
+ this._vertexBuffers["direction"] = directionBuffer;
880
+ dataOffset += 3;
881
+ }
882
+ if (this._useRampGradients) {
883
+ const rampDataBuffer = this._vertexBuffer.createVertexBuffer("remapData", dataOffset, 4, this._vertexBufferSize, this._useInstancing);
884
+ this._vertexBuffers["remapData"] = rampDataBuffer;
885
+ dataOffset += 4;
886
+ }
887
+ let offsets;
888
+ if (this._useInstancing) {
889
+ const spriteData = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]);
890
+ this._spriteBuffer = new Buffer(engine, spriteData, false, 2);
891
+ offsets = this._spriteBuffer.createVertexBuffer("offset", 0, 2);
892
+ }
893
+ else {
894
+ offsets = this._vertexBuffer.createVertexBuffer("offset", dataOffset, 2, this._vertexBufferSize, this._useInstancing);
895
+ dataOffset += 2;
896
+ }
897
+ this._vertexBuffers["offset"] = offsets;
898
+ this.resetDrawCache();
899
+ }
900
+ _createIndexBuffer() {
901
+ if (this._useInstancing) {
902
+ this._linesIndexBufferUseInstancing = this._engine.createIndexBuffer(new Uint32Array([0, 1, 1, 3, 3, 2, 2, 0, 0, 3]));
903
+ return;
904
+ }
905
+ const indices = [];
906
+ const indicesWireframe = [];
907
+ let index = 0;
908
+ for (let count = 0; count < this._capacity; count++) {
909
+ indices.push(index);
910
+ indices.push(index + 1);
911
+ indices.push(index + 2);
912
+ indices.push(index);
913
+ indices.push(index + 2);
914
+ indices.push(index + 3);
915
+ indicesWireframe.push(index, index + 1, index + 1, index + 2, index + 2, index + 3, index + 3, index, index, index + 3);
916
+ index += 4;
917
+ }
918
+ this._indexBuffer = this._engine.createIndexBuffer(indices);
919
+ this._linesIndexBuffer = this._engine.createIndexBuffer(indicesWireframe);
920
+ }
921
+ /**
922
+ * Gets the maximum number of particles active at the same time.
923
+ * @returns The max number of active particles.
924
+ */
925
+ getCapacity() {
926
+ return this._capacity;
927
+ }
928
+ /**
929
+ * Gets whether there are still active particles in the system.
930
+ * @returns True if it is alive, otherwise false.
931
+ */
932
+ isAlive() {
933
+ return this._alive;
934
+ }
935
+ /**
936
+ * Gets if the system has been started. (Note: this will still be true after stop is called)
937
+ * @returns True if it has been started, otherwise false.
938
+ */
939
+ isStarted() {
940
+ return this._started;
941
+ }
942
+ /** @internal */
943
+ _preStart() {
944
+ // Do nothing
945
+ }
946
+ /**
947
+ * Starts the particle system and begins to emit
948
+ * @param delay defines the delay in milliseconds before starting the system (this.startDelay by default)
949
+ */
950
+ start(delay = this.startDelay) {
951
+ if (!this.targetStopDuration && this._hasTargetStopDurationDependantGradient()) {
952
+ // eslint-disable-next-line no-throw-literal
953
+ throw "Particle system started with a targetStopDuration dependant gradient (eg. startSizeGradients) but no targetStopDuration set";
954
+ }
955
+ if (delay) {
956
+ setTimeout(() => {
957
+ this.start(0);
958
+ }, delay);
959
+ return;
960
+ }
961
+ this._started = true;
962
+ this._stopped = false;
963
+ this._actualFrame = 0;
964
+ this._preStart();
965
+ // Reset emit gradient so it acts the same on every start
966
+ if (this._emitRateGradients) {
967
+ if (this._emitRateGradients.length > 0) {
968
+ this._currentEmitRateGradient = this._emitRateGradients[0];
969
+ this._currentEmitRate1 = this._currentEmitRateGradient.getFactor();
970
+ this._currentEmitRate2 = this._currentEmitRate1;
971
+ }
972
+ if (this._emitRateGradients.length > 1) {
973
+ this._currentEmitRate2 = this._emitRateGradients[1].getFactor();
974
+ }
975
+ }
976
+ // Reset start size gradient so it acts the same on every start
977
+ if (this._startSizeGradients) {
978
+ if (this._startSizeGradients.length > 0) {
979
+ this._currentStartSizeGradient = this._startSizeGradients[0];
980
+ this._currentStartSize1 = this._currentStartSizeGradient.getFactor();
981
+ this._currentStartSize2 = this._currentStartSize1;
982
+ }
983
+ if (this._startSizeGradients.length > 1) {
984
+ this._currentStartSize2 = this._startSizeGradients[1].getFactor();
985
+ }
986
+ }
987
+ if (this.preWarmCycles) {
988
+ if (this.emitter?.getClassName().indexOf("Mesh") !== -1) {
989
+ this.emitter.computeWorldMatrix(true);
990
+ }
991
+ const noiseTextureAsProcedural = this.noiseTexture;
992
+ if (noiseTextureAsProcedural && noiseTextureAsProcedural.onGeneratedObservable) {
993
+ noiseTextureAsProcedural.onGeneratedObservable.addOnce(() => {
994
+ setTimeout(() => {
995
+ for (let index = 0; index < this.preWarmCycles; index++) {
996
+ this.animate(true);
997
+ noiseTextureAsProcedural.render();
998
+ }
999
+ });
1000
+ });
1001
+ }
1002
+ else {
1003
+ for (let index = 0; index < this.preWarmCycles; index++) {
1004
+ this.animate(true);
1005
+ }
1006
+ }
1007
+ }
1008
+ // Animations
1009
+ if (this.beginAnimationOnStart && this.animations && this.animations.length > 0 && this._scene) {
1010
+ this._scene.beginAnimation(this, this.beginAnimationFrom, this.beginAnimationTo, this.beginAnimationLoop);
1011
+ }
1012
+ }
1013
+ /**
1014
+ * Stops the particle system.
1015
+ * @param stopSubEmitters if true it will stop the current system and all created sub-Systems if false it will stop the current root system only, this param is used by the root particle system only. the default value is true.
1016
+ */
1017
+ stop(stopSubEmitters = true) {
1018
+ if (this._stopped) {
1019
+ return;
1020
+ }
1021
+ this.onStoppedObservable.notifyObservers(this);
1022
+ this._stopped = true;
1023
+ this._postStop(stopSubEmitters);
1024
+ }
1025
+ /** @internal */
1026
+ _postStop(stopSubEmitters) {
1027
+ // Do nothing
1028
+ }
1029
+ // Animation sheet
1030
+ /**
1031
+ * Remove all active particles
1032
+ */
1033
+ reset() {
1034
+ this._stockParticles.length = 0;
1035
+ this._particles.length = 0;
1036
+ }
1037
+ /**
1038
+ * @internal (for internal use only)
1039
+ */
1040
+ _appendParticleVertex(index, particle, offsetX, offsetY) {
1041
+ let offset = index * this._vertexBufferSize;
1042
+ this._vertexData[offset++] = particle.position.x + this.worldOffset.x;
1043
+ this._vertexData[offset++] = particle.position.y + this.worldOffset.y;
1044
+ this._vertexData[offset++] = particle.position.z + this.worldOffset.z;
1045
+ this._vertexData[offset++] = particle.color.r;
1046
+ this._vertexData[offset++] = particle.color.g;
1047
+ this._vertexData[offset++] = particle.color.b;
1048
+ this._vertexData[offset++] = particle.color.a;
1049
+ this._vertexData[offset++] = particle.angle;
1050
+ this._vertexData[offset++] = particle.scale.x * particle.size;
1051
+ this._vertexData[offset++] = particle.scale.y * particle.size;
1052
+ if (this._isAnimationSheetEnabled) {
1053
+ this._vertexData[offset++] = particle.cellIndex;
1054
+ }
1055
+ if (!this._isBillboardBased) {
1056
+ if (particle._initialDirection) {
1057
+ let initialDirection = particle._initialDirection;
1058
+ if (this.isLocal) {
1059
+ Vector3.TransformNormalToRef(initialDirection, this._emitterWorldMatrix, TmpVectors.Vector3[0]);
1060
+ initialDirection = TmpVectors.Vector3[0];
1061
+ }
1062
+ if (initialDirection.x === 0 && initialDirection.z === 0) {
1063
+ initialDirection.x = 0.001;
1064
+ }
1065
+ this._vertexData[offset++] = initialDirection.x;
1066
+ this._vertexData[offset++] = initialDirection.y;
1067
+ this._vertexData[offset++] = initialDirection.z;
1068
+ }
1069
+ else {
1070
+ let direction = particle.direction;
1071
+ if (this.isLocal) {
1072
+ Vector3.TransformNormalToRef(direction, this._emitterWorldMatrix, TmpVectors.Vector3[0]);
1073
+ direction = TmpVectors.Vector3[0];
1074
+ }
1075
+ if (direction.x === 0 && direction.z === 0) {
1076
+ direction.x = 0.001;
1077
+ }
1078
+ this._vertexData[offset++] = direction.x;
1079
+ this._vertexData[offset++] = direction.y;
1080
+ this._vertexData[offset++] = direction.z;
1081
+ }
1082
+ }
1083
+ else if (this.billboardMode === 8 || this.billboardMode === 9) {
1084
+ this._vertexData[offset++] = particle.direction.x;
1085
+ this._vertexData[offset++] = particle.direction.y;
1086
+ this._vertexData[offset++] = particle.direction.z;
1087
+ }
1088
+ if (this._useRampGradients && particle.remapData) {
1089
+ this._vertexData[offset++] = particle.remapData.x;
1090
+ this._vertexData[offset++] = particle.remapData.y;
1091
+ this._vertexData[offset++] = particle.remapData.z;
1092
+ this._vertexData[offset++] = particle.remapData.w;
1093
+ }
1094
+ if (!this._useInstancing) {
1095
+ if (this._isAnimationSheetEnabled) {
1096
+ if (offsetX === 0) {
1097
+ offsetX = this._epsilon;
1098
+ }
1099
+ else if (offsetX === 1) {
1100
+ offsetX = 1 - this._epsilon;
1101
+ }
1102
+ if (offsetY === 0) {
1103
+ offsetY = this._epsilon;
1104
+ }
1105
+ else if (offsetY === 1) {
1106
+ offsetY = 1 - this._epsilon;
1107
+ }
1108
+ }
1109
+ this._vertexData[offset++] = offsetX;
1110
+ this._vertexData[offset++] = offsetY;
1111
+ }
1112
+ }
1113
+ /** @internal */
1114
+ _prepareParticle(particle) {
1115
+ //Do nothing
1116
+ }
1117
+ _update(newParticles) {
1118
+ // Update current
1119
+ this._alive = this._particles.length > 0;
1120
+ if (this.emitter.position) {
1121
+ const emitterMesh = this.emitter;
1122
+ this._emitterWorldMatrix = emitterMesh.getWorldMatrix();
1123
+ }
1124
+ else {
1125
+ const emitterPosition = this.emitter;
1126
+ this._emitterWorldMatrix = Matrix.Translation(emitterPosition.x, emitterPosition.y, emitterPosition.z);
1127
+ }
1128
+ this._emitterWorldMatrix.invertToRef(this._emitterInverseWorldMatrix);
1129
+ this.updateFunction(this._particles);
1130
+ // Add new ones
1131
+ let particle;
1132
+ for (let index = 0; index < newParticles; index++) {
1133
+ if (this._particles.length === this._capacity) {
1134
+ break;
1135
+ }
1136
+ particle = this._createParticle();
1137
+ this._particles.push(particle);
1138
+ // Life time
1139
+ if (this.targetStopDuration && this._lifeTimeGradients && this._lifeTimeGradients.length > 0) {
1140
+ const ratio = Clamp(this._actualFrame / this.targetStopDuration);
1141
+ GradientHelper.GetCurrentGradient(ratio, this._lifeTimeGradients, (currentGradient, nextGradient) => {
1142
+ const factorGradient1 = currentGradient;
1143
+ const factorGradient2 = nextGradient;
1144
+ const lifeTime1 = factorGradient1.getFactor();
1145
+ const lifeTime2 = factorGradient2.getFactor();
1146
+ const gradient = (ratio - factorGradient1.gradient) / (factorGradient2.gradient - factorGradient1.gradient);
1147
+ particle.lifeTime = Lerp(lifeTime1, lifeTime2, gradient);
1148
+ });
1149
+ }
1150
+ else {
1151
+ particle.lifeTime = RandomRange(this.minLifeTime, this.maxLifeTime);
1152
+ }
1153
+ // Emitter
1154
+ const emitPower = RandomRange(this.minEmitPower, this.maxEmitPower);
1155
+ if (this.startPositionFunction) {
1156
+ this.startPositionFunction(this._emitterWorldMatrix, particle.position, particle, this.isLocal);
1157
+ }
1158
+ else {
1159
+ this.particleEmitterType.startPositionFunction(this._emitterWorldMatrix, particle.position, particle, this.isLocal);
1160
+ }
1161
+ if (this.isLocal) {
1162
+ if (!particle._localPosition) {
1163
+ particle._localPosition = particle.position.clone();
1164
+ }
1165
+ else {
1166
+ particle._localPosition.copyFrom(particle.position);
1167
+ }
1168
+ Vector3.TransformCoordinatesToRef(particle._localPosition, this._emitterWorldMatrix, particle.position);
1169
+ }
1170
+ if (this.startDirectionFunction) {
1171
+ this.startDirectionFunction(this._emitterWorldMatrix, particle.direction, particle, this.isLocal);
1172
+ }
1173
+ else {
1174
+ this.particleEmitterType.startDirectionFunction(this._emitterWorldMatrix, particle.direction, particle, this.isLocal, this._emitterInverseWorldMatrix);
1175
+ }
1176
+ if (emitPower === 0) {
1177
+ if (!particle._initialDirection) {
1178
+ particle._initialDirection = particle.direction.clone();
1179
+ }
1180
+ else {
1181
+ particle._initialDirection.copyFrom(particle.direction);
1182
+ }
1183
+ }
1184
+ else {
1185
+ particle._initialDirection = null;
1186
+ }
1187
+ particle.direction.scaleInPlace(emitPower);
1188
+ // Size
1189
+ if (!this._sizeGradients || this._sizeGradients.length === 0) {
1190
+ particle.size = RandomRange(this.minSize, this.maxSize);
1191
+ }
1192
+ else {
1193
+ particle._currentSizeGradient = this._sizeGradients[0];
1194
+ particle._currentSize1 = particle._currentSizeGradient.getFactor();
1195
+ particle.size = particle._currentSize1;
1196
+ if (this._sizeGradients.length > 1) {
1197
+ particle._currentSize2 = this._sizeGradients[1].getFactor();
1198
+ }
1199
+ else {
1200
+ particle._currentSize2 = particle._currentSize1;
1201
+ }
1202
+ }
1203
+ // Size and scale
1204
+ particle.scale.copyFromFloats(RandomRange(this.minScaleX, this.maxScaleX), RandomRange(this.minScaleY, this.maxScaleY));
1205
+ // Adjust scale by start size
1206
+ if (this._startSizeGradients && this._startSizeGradients[0] && this.targetStopDuration) {
1207
+ const ratio = this._actualFrame / this.targetStopDuration;
1208
+ GradientHelper.GetCurrentGradient(ratio, this._startSizeGradients, (currentGradient, nextGradient, scale) => {
1209
+ if (currentGradient !== this._currentStartSizeGradient) {
1210
+ this._currentStartSize1 = this._currentStartSize2;
1211
+ this._currentStartSize2 = nextGradient.getFactor();
1212
+ this._currentStartSizeGradient = currentGradient;
1213
+ }
1214
+ const value = Lerp(this._currentStartSize1, this._currentStartSize2, scale);
1215
+ particle.scale.scaleInPlace(value);
1216
+ });
1217
+ }
1218
+ // Angle
1219
+ if (!this._angularSpeedGradients || this._angularSpeedGradients.length === 0) {
1220
+ particle.angularSpeed = RandomRange(this.minAngularSpeed, this.maxAngularSpeed);
1221
+ }
1222
+ else {
1223
+ particle._currentAngularSpeedGradient = this._angularSpeedGradients[0];
1224
+ particle.angularSpeed = particle._currentAngularSpeedGradient.getFactor();
1225
+ particle._currentAngularSpeed1 = particle.angularSpeed;
1226
+ if (this._angularSpeedGradients.length > 1) {
1227
+ particle._currentAngularSpeed2 = this._angularSpeedGradients[1].getFactor();
1228
+ }
1229
+ else {
1230
+ particle._currentAngularSpeed2 = particle._currentAngularSpeed1;
1231
+ }
1232
+ }
1233
+ particle.angle = RandomRange(this.minInitialRotation, this.maxInitialRotation);
1234
+ // Velocity
1235
+ if (this._velocityGradients && this._velocityGradients.length > 0) {
1236
+ particle._currentVelocityGradient = this._velocityGradients[0];
1237
+ particle._currentVelocity1 = particle._currentVelocityGradient.getFactor();
1238
+ if (this._velocityGradients.length > 1) {
1239
+ particle._currentVelocity2 = this._velocityGradients[1].getFactor();
1240
+ }
1241
+ else {
1242
+ particle._currentVelocity2 = particle._currentVelocity1;
1243
+ }
1244
+ }
1245
+ // Limit velocity
1246
+ if (this._limitVelocityGradients && this._limitVelocityGradients.length > 0) {
1247
+ particle._currentLimitVelocityGradient = this._limitVelocityGradients[0];
1248
+ particle._currentLimitVelocity1 = particle._currentLimitVelocityGradient.getFactor();
1249
+ if (this._limitVelocityGradients.length > 1) {
1250
+ particle._currentLimitVelocity2 = this._limitVelocityGradients[1].getFactor();
1251
+ }
1252
+ else {
1253
+ particle._currentLimitVelocity2 = particle._currentLimitVelocity1;
1254
+ }
1255
+ }
1256
+ // Drag
1257
+ if (this._dragGradients && this._dragGradients.length > 0) {
1258
+ particle._currentDragGradient = this._dragGradients[0];
1259
+ particle._currentDrag1 = particle._currentDragGradient.getFactor();
1260
+ if (this._dragGradients.length > 1) {
1261
+ particle._currentDrag2 = this._dragGradients[1].getFactor();
1262
+ }
1263
+ else {
1264
+ particle._currentDrag2 = particle._currentDrag1;
1265
+ }
1266
+ }
1267
+ // Color
1268
+ if (!this._colorGradients || this._colorGradients.length === 0) {
1269
+ const step = RandomRange(0, 1.0);
1270
+ Color4.LerpToRef(this.color1, this.color2, step, particle.color);
1271
+ this.colorDead.subtractToRef(particle.color, this._colorDiff);
1272
+ this._colorDiff.scaleToRef(1.0 / particle.lifeTime, particle.colorStep);
1273
+ }
1274
+ else {
1275
+ particle._currentColorGradient = this._colorGradients[0];
1276
+ particle._currentColorGradient.getColorToRef(particle.color);
1277
+ particle._currentColor1.copyFrom(particle.color);
1278
+ if (this._colorGradients.length > 1) {
1279
+ this._colorGradients[1].getColorToRef(particle._currentColor2);
1280
+ }
1281
+ else {
1282
+ particle._currentColor2.copyFrom(particle.color);
1283
+ }
1284
+ }
1285
+ // Sheet
1286
+ if (this._isAnimationSheetEnabled) {
1287
+ particle._initialStartSpriteCellID = this.startSpriteCellID;
1288
+ particle._initialEndSpriteCellID = this.endSpriteCellID;
1289
+ particle._initialSpriteCellLoop = this.spriteCellLoop;
1290
+ }
1291
+ // Inherited Velocity
1292
+ particle.direction.addInPlace(this._inheritedVelocityOffset);
1293
+ // Ramp
1294
+ if (this._useRampGradients) {
1295
+ particle.remapData = new Vector4(0, 1, 0, 1);
1296
+ }
1297
+ // Noise texture coordinates
1298
+ if (this.noiseTexture) {
1299
+ if (particle._randomNoiseCoordinates1) {
1300
+ particle._randomNoiseCoordinates1.copyFromFloats(Math.random(), Math.random(), Math.random());
1301
+ particle._randomNoiseCoordinates2.copyFromFloats(Math.random(), Math.random(), Math.random());
1302
+ }
1303
+ else {
1304
+ particle._randomNoiseCoordinates1 = new Vector3(Math.random(), Math.random(), Math.random());
1305
+ particle._randomNoiseCoordinates2 = new Vector3(Math.random(), Math.random(), Math.random());
1306
+ }
1307
+ }
1308
+ // Update the position of the attached sub-emitters to match their attached particle
1309
+ particle._inheritParticleInfoToSubEmitters();
1310
+ }
1311
+ }
1312
+ /**
1313
+ * @internal
1314
+ */
1315
+ static _GetAttributeNamesOrOptions(isAnimationSheetEnabled = false, isBillboardBased = false, useRampGradients = false) {
1316
+ const attributeNamesOrOptions = [VertexBuffer.PositionKind, VertexBuffer.ColorKind, "angle", "offset", "size"];
1317
+ if (isAnimationSheetEnabled) {
1318
+ attributeNamesOrOptions.push("cellIndex");
1319
+ }
1320
+ if (!isBillboardBased) {
1321
+ attributeNamesOrOptions.push("direction");
1322
+ }
1323
+ if (useRampGradients) {
1324
+ attributeNamesOrOptions.push("remapData");
1325
+ }
1326
+ return attributeNamesOrOptions;
1327
+ }
1328
+ /**
1329
+ * @internal
1330
+ */
1331
+ static _GetEffectCreationOptions(isAnimationSheetEnabled = false, useLogarithmicDepth = false, applyFog = false) {
1332
+ const effectCreationOption = ["invView", "view", "projection", "textureMask", "translationPivot", "eyePosition"];
1333
+ addClipPlaneUniforms(effectCreationOption);
1334
+ if (isAnimationSheetEnabled) {
1335
+ effectCreationOption.push("particlesInfos");
1336
+ }
1337
+ if (useLogarithmicDepth) {
1338
+ effectCreationOption.push("logarithmicDepthConstant");
1339
+ }
1340
+ if (applyFog) {
1341
+ effectCreationOption.push("vFogInfos");
1342
+ effectCreationOption.push("vFogColor");
1343
+ }
1344
+ return effectCreationOption;
1345
+ }
1346
+ /**
1347
+ * Fill the defines array according to the current settings of the particle system
1348
+ * @param defines Array to be updated
1349
+ * @param blendMode blend mode to take into account when updating the array
1350
+ */
1351
+ fillDefines(defines, blendMode) {
1352
+ if (this._scene) {
1353
+ prepareStringDefinesForClipPlanes(this, this._scene, defines);
1354
+ if (this.applyFog && this._scene.fogEnabled && this._scene.fogMode !== 0) {
1355
+ defines.push("#define FOG");
1356
+ }
1357
+ }
1358
+ if (this._isAnimationSheetEnabled) {
1359
+ defines.push("#define ANIMATESHEET");
1360
+ }
1361
+ if (this.useLogarithmicDepth) {
1362
+ defines.push("#define LOGARITHMICDEPTH");
1363
+ }
1364
+ if (blendMode === BaseParticleSystem.BLENDMODE_MULTIPLY) {
1365
+ defines.push("#define BLENDMULTIPLYMODE");
1366
+ }
1367
+ if (this._useRampGradients) {
1368
+ defines.push("#define RAMPGRADIENT");
1369
+ }
1370
+ if (this._isBillboardBased) {
1371
+ defines.push("#define BILLBOARD");
1372
+ switch (this.billboardMode) {
1373
+ case 2:
1374
+ defines.push("#define BILLBOARDY");
1375
+ break;
1376
+ case 8:
1377
+ case 9:
1378
+ defines.push("#define BILLBOARDSTRETCHED");
1379
+ if (this.billboardMode === 9) {
1380
+ defines.push("#define BILLBOARDSTRETCHED_LOCAL");
1381
+ }
1382
+ break;
1383
+ case 7:
1384
+ defines.push("#define BILLBOARDMODE_ALL");
1385
+ break;
1386
+ default:
1387
+ break;
1388
+ }
1389
+ }
1390
+ if (this._imageProcessingConfiguration) {
1391
+ this._imageProcessingConfiguration.prepareDefines(this._imageProcessingConfigurationDefines);
1392
+ defines.push(this._imageProcessingConfigurationDefines.toString());
1393
+ }
1394
+ }
1395
+ /**
1396
+ * Fill the uniforms, attributes and samplers arrays according to the current settings of the particle system
1397
+ * @param uniforms Uniforms array to fill
1398
+ * @param attributes Attributes array to fill
1399
+ * @param samplers Samplers array to fill
1400
+ */
1401
+ fillUniformsAttributesAndSamplerNames(uniforms, attributes, samplers) {
1402
+ attributes.push(...ThinParticleSystem._GetAttributeNamesOrOptions(this._isAnimationSheetEnabled, this._isBillboardBased &&
1403
+ this.billboardMode !== 8 &&
1404
+ this.billboardMode !== 9, this._useRampGradients));
1405
+ uniforms.push(...ThinParticleSystem._GetEffectCreationOptions(this._isAnimationSheetEnabled, this.useLogarithmicDepth, this.applyFog));
1406
+ samplers.push("diffuseSampler", "rampSampler");
1407
+ if (this._imageProcessingConfiguration) {
1408
+ PrepareUniformsForImageProcessing(uniforms, this._imageProcessingConfigurationDefines);
1409
+ PrepareSamplersForImageProcessing(samplers, this._imageProcessingConfigurationDefines);
1410
+ }
1411
+ }
1412
+ /**
1413
+ * @internal
1414
+ */
1415
+ _getWrapper(blendMode) {
1416
+ const customWrapper = this._getCustomDrawWrapper(blendMode);
1417
+ if (customWrapper?.effect) {
1418
+ return customWrapper;
1419
+ }
1420
+ const defines = [];
1421
+ this.fillDefines(defines, blendMode);
1422
+ // Effect
1423
+ const currentRenderPassId = this._engine._features.supportRenderPasses ? this._engine.currentRenderPassId : 0;
1424
+ let drawWrappers = this._drawWrappers[currentRenderPassId];
1425
+ if (!drawWrappers) {
1426
+ drawWrappers = this._drawWrappers[currentRenderPassId] = [];
1427
+ }
1428
+ let drawWrapper = drawWrappers[blendMode];
1429
+ if (!drawWrapper) {
1430
+ drawWrapper = new DrawWrapper(this._engine);
1431
+ if (drawWrapper.drawContext) {
1432
+ drawWrapper.drawContext.useInstancing = this._useInstancing;
1433
+ }
1434
+ drawWrappers[blendMode] = drawWrapper;
1435
+ }
1436
+ const join = defines.join("\n");
1437
+ if (drawWrapper.defines !== join) {
1438
+ const attributesNamesOrOptions = [];
1439
+ const effectCreationOption = [];
1440
+ const samplers = [];
1441
+ this.fillUniformsAttributesAndSamplerNames(effectCreationOption, attributesNamesOrOptions, samplers);
1442
+ drawWrapper.setEffect(this._engine.createEffect("particles", attributesNamesOrOptions, effectCreationOption, samplers, join), join);
1443
+ }
1444
+ return drawWrapper;
1445
+ }
1446
+ /**
1447
+ * Animates the particle system for the current frame by emitting new particles and or animating the living ones.
1448
+ * @param preWarmOnly will prevent the system from updating the vertex buffer (default is false)
1449
+ */
1450
+ animate(preWarmOnly = false) {
1451
+ if (!this._started) {
1452
+ return;
1453
+ }
1454
+ if (!preWarmOnly && this._scene) {
1455
+ // Check
1456
+ if (!this.isReady()) {
1457
+ return;
1458
+ }
1459
+ if (this._currentRenderId === this._scene.getFrameId()) {
1460
+ return;
1461
+ }
1462
+ this._currentRenderId = this._scene.getFrameId();
1463
+ }
1464
+ this._scaledUpdateSpeed = this.updateSpeed * (preWarmOnly ? this.preWarmStepOffset : this._scene?.getAnimationRatio() || 1);
1465
+ // Determine the number of particles we need to create
1466
+ let newParticles;
1467
+ if (this.manualEmitCount > -1) {
1468
+ newParticles = this.manualEmitCount;
1469
+ this._newPartsExcess = 0;
1470
+ this.manualEmitCount = 0;
1471
+ }
1472
+ else {
1473
+ let rate = this.emitRate;
1474
+ if (this._emitRateGradients && this._emitRateGradients.length > 0 && this.targetStopDuration) {
1475
+ const ratio = this._actualFrame / this.targetStopDuration;
1476
+ GradientHelper.GetCurrentGradient(ratio, this._emitRateGradients, (currentGradient, nextGradient, scale) => {
1477
+ if (currentGradient !== this._currentEmitRateGradient) {
1478
+ this._currentEmitRate1 = this._currentEmitRate2;
1479
+ this._currentEmitRate2 = nextGradient.getFactor();
1480
+ this._currentEmitRateGradient = currentGradient;
1481
+ }
1482
+ rate = Lerp(this._currentEmitRate1, this._currentEmitRate2, scale);
1483
+ });
1484
+ }
1485
+ newParticles = (rate * this._scaledUpdateSpeed) >> 0;
1486
+ this._newPartsExcess += rate * this._scaledUpdateSpeed - newParticles;
1487
+ }
1488
+ if (this._newPartsExcess > 1.0) {
1489
+ newParticles += this._newPartsExcess >> 0;
1490
+ this._newPartsExcess -= this._newPartsExcess >> 0;
1491
+ }
1492
+ this._alive = false;
1493
+ if (!this._stopped) {
1494
+ this._actualFrame += this._scaledUpdateSpeed;
1495
+ if (this.targetStopDuration && this._actualFrame >= this.targetStopDuration) {
1496
+ this.stop();
1497
+ }
1498
+ }
1499
+ else {
1500
+ newParticles = 0;
1501
+ }
1502
+ this._update(newParticles);
1503
+ // Stopped?
1504
+ if (this._stopped) {
1505
+ if (!this._alive) {
1506
+ this._started = false;
1507
+ if (this.onAnimationEnd) {
1508
+ this.onAnimationEnd();
1509
+ }
1510
+ if (this.disposeOnStop && this._scene) {
1511
+ this._scene._toBeDisposed.push(this);
1512
+ }
1513
+ }
1514
+ }
1515
+ if (!preWarmOnly) {
1516
+ // Update VBO
1517
+ let offset = 0;
1518
+ for (let index = 0; index < this._particles.length; index++) {
1519
+ const particle = this._particles[index];
1520
+ this._appendParticleVertices(offset, particle);
1521
+ offset += this._useInstancing ? 1 : 4;
1522
+ }
1523
+ if (this._vertexBuffer) {
1524
+ this._vertexBuffer.updateDirectly(this._vertexData, 0, this._particles.length);
1525
+ }
1526
+ }
1527
+ if (this.manualEmitCount === 0 && this.disposeOnStop) {
1528
+ this.stop();
1529
+ }
1530
+ }
1531
+ _appendParticleVertices(offset, particle) {
1532
+ this._appendParticleVertex(offset++, particle, 0, 0);
1533
+ if (!this._useInstancing) {
1534
+ this._appendParticleVertex(offset++, particle, 1, 0);
1535
+ this._appendParticleVertex(offset++, particle, 1, 1);
1536
+ this._appendParticleVertex(offset++, particle, 0, 1);
1537
+ }
1538
+ }
1539
+ /**
1540
+ * Rebuilds the particle system.
1541
+ */
1542
+ rebuild() {
1543
+ if (this._engine.getCaps().vertexArrayObject) {
1544
+ this._vertexArrayObject = null;
1545
+ }
1546
+ this._createIndexBuffer();
1547
+ this._spriteBuffer?._rebuild();
1548
+ this._createVertexBuffers();
1549
+ this.resetDrawCache();
1550
+ }
1551
+ /**
1552
+ * Is this system ready to be used/rendered
1553
+ * @returns true if the system is ready
1554
+ */
1555
+ isReady() {
1556
+ if (!this.emitter || (this._imageProcessingConfiguration && !this._imageProcessingConfiguration.isReady()) || !this.particleTexture || !this.particleTexture.isReady()) {
1557
+ return false;
1558
+ }
1559
+ if (this.blendMode !== BaseParticleSystem.BLENDMODE_MULTIPLYADD) {
1560
+ if (!this._getWrapper(this.blendMode).effect.isReady()) {
1561
+ return false;
1562
+ }
1563
+ }
1564
+ else {
1565
+ if (!this._getWrapper(BaseParticleSystem.BLENDMODE_MULTIPLY).effect.isReady()) {
1566
+ return false;
1567
+ }
1568
+ if (!this._getWrapper(BaseParticleSystem.BLENDMODE_ADD).effect.isReady()) {
1569
+ return false;
1570
+ }
1571
+ }
1572
+ return true;
1573
+ }
1574
+ _render(blendMode) {
1575
+ const drawWrapper = this._getWrapper(blendMode);
1576
+ const effect = drawWrapper.effect;
1577
+ const engine = this._engine;
1578
+ // Render
1579
+ engine.enableEffect(drawWrapper);
1580
+ const viewMatrix = this.defaultViewMatrix ?? this._scene.getViewMatrix();
1581
+ effect.setTexture("diffuseSampler", this.particleTexture);
1582
+ effect.setMatrix("view", viewMatrix);
1583
+ effect.setMatrix("projection", this.defaultProjectionMatrix ?? this._scene.getProjectionMatrix());
1584
+ if (this._isAnimationSheetEnabled && this.particleTexture) {
1585
+ const baseSize = this.particleTexture.getBaseSize();
1586
+ effect.setFloat3("particlesInfos", this.spriteCellWidth / baseSize.width, this.spriteCellHeight / baseSize.height, this.spriteCellWidth / baseSize.width);
1587
+ }
1588
+ effect.setVector2("translationPivot", this.translationPivot);
1589
+ effect.setFloat4("textureMask", this.textureMask.r, this.textureMask.g, this.textureMask.b, this.textureMask.a);
1590
+ if (this._isBillboardBased && this._scene) {
1591
+ const camera = this._scene.activeCamera;
1592
+ effect.setVector3("eyePosition", camera.globalPosition);
1593
+ }
1594
+ if (this._rampGradientsTexture) {
1595
+ if (!this._rampGradients || !this._rampGradients.length) {
1596
+ this._rampGradientsTexture.dispose();
1597
+ this._rampGradientsTexture = null;
1598
+ }
1599
+ effect.setTexture("rampSampler", this._rampGradientsTexture);
1600
+ }
1601
+ const defines = effect.defines;
1602
+ if (this._scene) {
1603
+ bindClipPlane(effect, this, this._scene);
1604
+ if (this.applyFog) {
1605
+ BindFogParameters(this._scene, undefined, effect);
1606
+ }
1607
+ }
1608
+ if (defines.indexOf("#define BILLBOARDMODE_ALL") >= 0) {
1609
+ viewMatrix.invertToRef(TmpVectors.Matrix[0]);
1610
+ effect.setMatrix("invView", TmpVectors.Matrix[0]);
1611
+ }
1612
+ if (this._vertexArrayObject !== undefined) {
1613
+ if (this._scene?.forceWireframe) {
1614
+ engine.bindBuffers(this._vertexBuffers, this._linesIndexBufferUseInstancing, effect);
1615
+ }
1616
+ else {
1617
+ if (!this._vertexArrayObject) {
1618
+ this._vertexArrayObject = this._engine.recordVertexArrayObject(this._vertexBuffers, null, effect);
1619
+ }
1620
+ this._engine.bindVertexArrayObject(this._vertexArrayObject, this._scene?.forceWireframe ? this._linesIndexBufferUseInstancing : this._indexBuffer);
1621
+ }
1622
+ }
1623
+ else {
1624
+ if (!this._indexBuffer) {
1625
+ // Use instancing mode
1626
+ engine.bindBuffers(this._vertexBuffers, this._scene?.forceWireframe ? this._linesIndexBufferUseInstancing : null, effect);
1627
+ }
1628
+ else {
1629
+ engine.bindBuffers(this._vertexBuffers, this._scene?.forceWireframe ? this._linesIndexBuffer : this._indexBuffer, effect);
1630
+ }
1631
+ }
1632
+ // Log. depth
1633
+ if (this.useLogarithmicDepth && this._scene) {
1634
+ BindLogDepth(defines, effect, this._scene);
1635
+ }
1636
+ // image processing
1637
+ if (this._imageProcessingConfiguration && !this._imageProcessingConfiguration.applyByPostProcess) {
1638
+ this._imageProcessingConfiguration.bind(effect);
1639
+ }
1640
+ // Draw order
1641
+ switch (blendMode) {
1642
+ case BaseParticleSystem.BLENDMODE_ADD:
1643
+ engine.setAlphaMode(1);
1644
+ break;
1645
+ case BaseParticleSystem.BLENDMODE_ONEONE:
1646
+ engine.setAlphaMode(6);
1647
+ break;
1648
+ case BaseParticleSystem.BLENDMODE_STANDARD:
1649
+ engine.setAlphaMode(2);
1650
+ break;
1651
+ case BaseParticleSystem.BLENDMODE_MULTIPLY:
1652
+ engine.setAlphaMode(4);
1653
+ break;
1654
+ }
1655
+ if (this._onBeforeDrawParticlesObservable) {
1656
+ this._onBeforeDrawParticlesObservable.notifyObservers(effect);
1657
+ }
1658
+ if (this._useInstancing) {
1659
+ if (this._scene?.forceWireframe) {
1660
+ engine.drawElementsType(6, 0, 10, this._particles.length);
1661
+ }
1662
+ else {
1663
+ engine.drawArraysType(7, 0, 4, this._particles.length);
1664
+ }
1665
+ }
1666
+ else {
1667
+ if (this._scene?.forceWireframe) {
1668
+ engine.drawElementsType(1, 0, this._particles.length * 10);
1669
+ }
1670
+ else {
1671
+ engine.drawElementsType(0, 0, this._particles.length * 6);
1672
+ }
1673
+ }
1674
+ return this._particles.length;
1675
+ }
1676
+ /**
1677
+ * Renders the particle system in its current state.
1678
+ * @returns the current number of particles
1679
+ */
1680
+ render() {
1681
+ // Check
1682
+ if (!this.isReady() || !this._particles.length) {
1683
+ return 0;
1684
+ }
1685
+ const engine = this._engine;
1686
+ if (engine.setState) {
1687
+ engine.setState(false);
1688
+ if (this.forceDepthWrite) {
1689
+ engine.setDepthWrite(true);
1690
+ }
1691
+ }
1692
+ let outparticles = 0;
1693
+ if (this.blendMode === BaseParticleSystem.BLENDMODE_MULTIPLYADD) {
1694
+ outparticles = this._render(BaseParticleSystem.BLENDMODE_MULTIPLY) + this._render(BaseParticleSystem.BLENDMODE_ADD);
1695
+ }
1696
+ else {
1697
+ outparticles = this._render(this.blendMode);
1698
+ }
1699
+ this._engine.unbindInstanceAttributes();
1700
+ this._engine.setAlphaMode(0);
1701
+ return outparticles;
1702
+ }
1703
+ /** @internal */
1704
+ _onDispose() {
1705
+ // Do Nothing
1706
+ }
1707
+ /**
1708
+ * Disposes the particle system and free the associated resources
1709
+ * @param disposeTexture defines if the particle texture must be disposed as well (true by default)
1710
+ */
1711
+ dispose(disposeTexture = true) {
1712
+ this.resetDrawCache();
1713
+ if (this._vertexBuffer) {
1714
+ this._vertexBuffer.dispose();
1715
+ this._vertexBuffer = null;
1716
+ }
1717
+ if (this._spriteBuffer) {
1718
+ this._spriteBuffer.dispose();
1719
+ this._spriteBuffer = null;
1720
+ }
1721
+ if (this._indexBuffer) {
1722
+ this._engine._releaseBuffer(this._indexBuffer);
1723
+ this._indexBuffer = null;
1724
+ }
1725
+ if (this._linesIndexBuffer) {
1726
+ this._engine._releaseBuffer(this._linesIndexBuffer);
1727
+ this._linesIndexBuffer = null;
1728
+ }
1729
+ if (this._linesIndexBufferUseInstancing) {
1730
+ this._engine._releaseBuffer(this._linesIndexBufferUseInstancing);
1731
+ this._linesIndexBufferUseInstancing = null;
1732
+ }
1733
+ if (this._vertexArrayObject) {
1734
+ this._engine.releaseVertexArrayObject(this._vertexArrayObject);
1735
+ this._vertexArrayObject = null;
1736
+ }
1737
+ if (disposeTexture && this.particleTexture) {
1738
+ this.particleTexture.dispose();
1739
+ this.particleTexture = null;
1740
+ }
1741
+ if (disposeTexture && this.noiseTexture) {
1742
+ this.noiseTexture.dispose();
1743
+ this.noiseTexture = null;
1744
+ }
1745
+ if (this._rampGradientsTexture) {
1746
+ this._rampGradientsTexture.dispose();
1747
+ this._rampGradientsTexture = null;
1748
+ }
1749
+ this._onDispose();
1750
+ if (this._onBeforeDrawParticlesObservable) {
1751
+ this._onBeforeDrawParticlesObservable.clear();
1752
+ }
1753
+ // Remove from scene
1754
+ if (this._scene) {
1755
+ const index = this._scene.particleSystems.indexOf(this);
1756
+ if (index > -1) {
1757
+ this._scene.particleSystems.splice(index, 1);
1758
+ }
1759
+ this._scene._activeParticleSystems.dispose();
1760
+ }
1761
+ // Callback
1762
+ this.onDisposeObservable.notifyObservers(this);
1763
+ this.onDisposeObservable.clear();
1764
+ this.onStoppedObservable.clear();
1765
+ this.reset();
1766
+ }
1767
+ }
1768
+ //# sourceMappingURL=thinParticleSystem.js.map