@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
@@ -1,234 +1,34 @@
1
- import { FactorGradient, ColorGradient, Color3Gradient, GradientHelper } from "../Misc/gradients.js";
2
- import { Observable } from "../Misc/observable.js";
3
- import { Vector3, Matrix, TmpVectors, Vector4 } from "../Maths/math.vector.js";
4
- import { Scalar } from "../Maths/math.scalar.js";
5
- import { VertexBuffer, Buffer } from "../Buffers/buffer.js";
6
- import { ImageProcessingConfiguration } from "../Materials/imageProcessingConfiguration.js";
7
- import { RawTexture } from "../Materials/Textures/rawTexture.js";
8
- import { EngineStore } from "../Engines/engineStore.js";
9
- import { Scene } from "../scene.js";
10
- import { BoxParticleEmitter, HemisphericParticleEmitter, SphereParticleEmitter, SphereDirectedParticleEmitter, CylinderParticleEmitter, ConeParticleEmitter, PointParticleEmitter, MeshParticleEmitter, CylinderDirectedParticleEmitter, CustomParticleEmitter, } from "../Particles/EmitterTypes/index.js";
11
- import { BaseParticleSystem } from "./baseParticleSystem.js";
12
- import { Particle } from "./particle.js";
1
+ import { ThinParticleSystem } from "./thinParticleSystem.js";
13
2
  import { SubEmitter, SubEmitterType } from "./subEmitter.js";
14
-
15
- import { SerializationHelper } from "../Misc/decorators.js";
16
- import { GetClass } from "../Misc/typeStore.js";
17
- import { DrawWrapper } from "../Materials/drawWrapper.js";
18
- import "../Shaders/particles.fragment.js";
19
- import "../Shaders/particles.vertex.js";
20
- import { Color4, Color3, TmpColors } from "../Maths/math.color.js";
3
+ import { Color3, Color4 } from "../Maths/math.color.js";
4
+ import { Vector3 } from "../Maths/math.vector.js";
21
5
  import { ThinEngine } from "../Engines/thinEngine.js";
22
- import "../Engines/Extensions/engine.alpha.js";
23
- import { addClipPlaneUniforms, prepareStringDefinesForClipPlanes, bindClipPlane } from "../Materials/clipPlaneMaterialHelper.js";
24
- import { BindFogParameters, BindLogDepth } from "../Materials/materialHelper.functions.js";
6
+ import { GetClass } from "../Misc/typeStore.js";
7
+
8
+ import { SerializationHelper } from "../Misc/decorators.serialization.js";
9
+ import { MeshParticleEmitter } from "./EmitterTypes/meshParticleEmitter.js";
10
+ import { CustomParticleEmitter } from "./EmitterTypes/customParticleEmitter.js";
11
+ import { BoxParticleEmitter } from "./EmitterTypes/boxParticleEmitter.js";
12
+ import { PointParticleEmitter } from "./EmitterTypes/pointParticleEmitter.js";
13
+ import { HemisphericParticleEmitter } from "./EmitterTypes/hemisphericParticleEmitter.js";
14
+ import { SphereDirectedParticleEmitter, SphereParticleEmitter } from "./EmitterTypes/sphereParticleEmitter.js";
15
+ import { CylinderDirectedParticleEmitter, CylinderParticleEmitter } from "./EmitterTypes/cylinderParticleEmitter.js";
16
+ import { ConeParticleEmitter } from "./EmitterTypes/coneParticleEmitter.js";
17
+ import { CreateConeEmitter, CreateCylinderEmitter, CreateDirectedCylinderEmitter, CreateDirectedSphereEmitter, CreateHemisphericEmitter, CreatePointEmitter, CreateSphereEmitter, } from "./particleSystem.functions.js";
25
18
  /**
26
19
  * This represents a particle system in Babylon.
27
20
  * 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.
28
21
  * Particles can take different shapes while emitted like box, sphere, cone or you can write your custom function.
29
22
  * @example https://doc.babylonjs.com/features/featuresDeepDive/particles/particle_system/particle_system_intro
30
23
  */
31
- export class ParticleSystem extends BaseParticleSystem {
32
- /**
33
- * Sets a callback that will be triggered when the system is disposed
34
- */
35
- set onDispose(callback) {
36
- if (this._onDisposeObserver) {
37
- this.onDisposeObservable.remove(this._onDisposeObserver);
38
- }
39
- this._onDisposeObserver = this.onDisposeObservable.add(callback);
40
- }
41
- /** Gets or sets a boolean indicating that ramp gradients must be used
42
- * @see https://doc.babylonjs.com/features/featuresDeepDive/particles/particle_system/particle_system_intro#ramp-gradients
43
- */
44
- get useRampGradients() {
45
- return this._useRampGradients;
46
- }
47
- set useRampGradients(value) {
48
- if (this._useRampGradients === value) {
49
- return;
50
- }
51
- this._useRampGradients = value;
52
- this._resetEffect();
53
- }
54
- //end of Sub-emitter
55
- /**
56
- * Gets the current list of active particles
57
- */
58
- get particles() {
59
- return this._particles;
60
- }
61
- /**
62
- * Gets the number of particles active at the same time.
63
- * @returns The number of active particles.
64
- */
65
- getActiveCount() {
66
- return this._particles.length;
67
- }
68
- /**
69
- * Returns the string "ParticleSystem"
70
- * @returns a string containing the class name
71
- */
72
- getClassName() {
73
- return "ParticleSystem";
74
- }
75
- /**
76
- * Gets a boolean indicating that the system is stopping
77
- * @returns true if the system is currently stopping
78
- */
79
- isStopping() {
80
- return this._stopped && this.isAlive();
81
- }
82
- /**
83
- * Gets the custom effect used to render the particles
84
- * @param blendMode Blend mode for which the effect should be retrieved
85
- * @returns The effect
86
- */
87
- getCustomEffect(blendMode = 0) {
88
- return this._customWrappers[blendMode]?.effect ?? this._customWrappers[0].effect;
89
- }
90
- _getCustomDrawWrapper(blendMode = 0) {
91
- return this._customWrappers[blendMode] ?? this._customWrappers[0];
92
- }
93
- /**
94
- * Sets the custom effect used to render the particles
95
- * @param effect The effect to set
96
- * @param blendMode Blend mode for which the effect should be set
97
- */
98
- setCustomEffect(effect, blendMode = 0) {
99
- this._customWrappers[blendMode] = new DrawWrapper(this._engine);
100
- this._customWrappers[blendMode].effect = effect;
101
- if (this._customWrappers[blendMode].drawContext) {
102
- this._customWrappers[blendMode].drawContext.useInstancing = this._useInstancing;
103
- }
104
- }
105
- /**
106
- * Observable that will be called just before the particles are drawn
107
- */
108
- get onBeforeDrawParticlesObservable() {
109
- if (!this._onBeforeDrawParticlesObservable) {
110
- this._onBeforeDrawParticlesObservable = new Observable();
111
- }
112
- return this._onBeforeDrawParticlesObservable;
113
- }
114
- /**
115
- * Gets the name of the particle vertex shader
116
- */
117
- get vertexShaderName() {
118
- return "particles";
119
- }
120
- /**
121
- * Gets the vertex buffers used by the particle system
122
- */
123
- get vertexBuffers() {
124
- return this._vertexBuffers;
125
- }
126
- /**
127
- * Gets the index buffer used by the particle system (or null if no index buffer is used (if _useInstancing=true))
128
- */
129
- get indexBuffer() {
130
- return this._indexBuffer;
131
- }
132
- /**
133
- * Instantiates a particle system.
134
- * 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.
135
- * @param name The name of the particle system
136
- * @param capacity The max number of particles alive at the same time
137
- * @param sceneOrEngine The scene the particle system belongs to or the engine to use if no scene
138
- * @param customEffect a custom effect used to change the way particles are rendered by default
139
- * @param isAnimationSheetEnabled Must be true if using a spritesheet to animate the particles texture
140
- * @param epsilon Offset used to render the particles
141
- */
142
- constructor(name, capacity, sceneOrEngine, customEffect = null, isAnimationSheetEnabled = false, epsilon = 0.01) {
143
- super(name);
144
- this._emitterInverseWorldMatrix = Matrix.Identity();
145
- /**
146
- * @internal
147
- */
148
- this._inheritedVelocityOffset = new Vector3();
149
- /**
150
- * An event triggered when the system is disposed
151
- */
152
- this.onDisposeObservable = new Observable();
153
- /**
154
- * An event triggered when the system is stopped
155
- */
156
- this.onStoppedObservable = new Observable();
157
- this._particles = new Array();
158
- this._stockParticles = new Array();
159
- this._newPartsExcess = 0;
160
- this._vertexBuffers = {};
161
- this._scaledColorStep = new Color4(0, 0, 0, 0);
162
- this._colorDiff = new Color4(0, 0, 0, 0);
163
- this._scaledDirection = Vector3.Zero();
164
- this._scaledGravity = Vector3.Zero();
165
- this._currentRenderId = -1;
166
- this._useInstancing = false;
167
- this._started = false;
168
- this._stopped = false;
169
- this._actualFrame = 0;
170
- /** @internal */
171
- this._currentEmitRate1 = 0;
172
- /** @internal */
173
- this._currentEmitRate2 = 0;
174
- /** @internal */
175
- this._currentStartSize1 = 0;
176
- /** @internal */
177
- this._currentStartSize2 = 0;
178
- /** Indicates that the update of particles is done in the animate function */
179
- this.updateInAnimate = true;
180
- this._rawTextureWidth = 256;
181
- this._useRampGradients = false;
24
+ export class ParticleSystem extends ThinParticleSystem {
25
+ constructor() {
26
+ super(...arguments);
182
27
  /**
183
28
  * @internal
184
29
  * If the particle systems emitter should be disposed when the particle system is disposed
185
30
  */
186
31
  this._disposeEmitterOnDispose = false;
187
- /**
188
- * Specifies if the particles are updated in emitter local space or world space
189
- */
190
- this.isLocal = false;
191
- /** Indicates that the particle system is CPU based */
192
- this.isGPU = false;
193
- /** @internal */
194
- this._onBeforeDrawParticlesObservable = null;
195
- // start of sub system methods
196
- /**
197
- * "Recycles" one of the particle by copying it back to the "stock" of particles and removing it from the active list.
198
- * Its lifetime will start back at 0.
199
- * @param particle
200
- */
201
- this.recycleParticle = (particle) => {
202
- // move particle from activeParticle list to stock particles
203
- const lastParticle = this._particles.pop();
204
- if (lastParticle !== particle) {
205
- lastParticle.copyTo(particle);
206
- }
207
- this._stockParticles.push(lastParticle);
208
- };
209
- this._createParticle = () => {
210
- let particle;
211
- if (this._stockParticles.length !== 0) {
212
- particle = this._stockParticles.pop();
213
- particle._reset();
214
- }
215
- else {
216
- particle = new Particle(this);
217
- }
218
- // Attach emitters
219
- if (this._subEmitters && this._subEmitters.length > 0) {
220
- const subEmitters = this._subEmitters[Math.floor(Math.random() * this._subEmitters.length)];
221
- particle._attachedSubEmitters = [];
222
- subEmitters.forEach((subEmitter) => {
223
- if (subEmitter.type === SubEmitterType.ATTACHED) {
224
- const newEmitter = subEmitter.clone();
225
- particle._attachedSubEmitters.push(newEmitter);
226
- newEmitter.particleSystem.start();
227
- }
228
- });
229
- }
230
- return particle;
231
- };
232
32
  this._emitFromParticle = (particle) => {
233
33
  if (!this._subEmitters || this._subEmitters.length === 0) {
234
34
  return;
@@ -244,716 +44,106 @@ export class ParticleSystem extends BaseParticleSystem {
244
44
  }
245
45
  });
246
46
  };
247
- this._capacity = capacity;
248
- this._epsilon = epsilon;
249
- this._isAnimationSheetEnabled = isAnimationSheetEnabled;
250
- if (!sceneOrEngine || sceneOrEngine.getClassName() === "Scene") {
251
- this._scene = sceneOrEngine || EngineStore.LastCreatedScene;
252
- this._engine = this._scene.getEngine();
253
- this.uniqueId = this._scene.getUniqueId();
254
- this._scene.particleSystems.push(this);
255
- }
256
- else {
257
- this._engine = sceneOrEngine;
258
- this.defaultProjectionMatrix = Matrix.PerspectiveFovLH(0.8, 1, 0.1, 100, this._engine.isNDCHalfZRange);
259
- }
260
- if (this._engine.getCaps().vertexArrayObject) {
261
- this._vertexArrayObject = null;
262
- }
263
- // Setup the default processing configuration to the scene.
264
- this._attachImageProcessingConfiguration(null);
265
- // eslint-disable-next-line @typescript-eslint/naming-convention
266
- this._customWrappers = { 0: new DrawWrapper(this._engine) };
267
- this._customWrappers[0].effect = customEffect;
268
- this._drawWrappers = [];
269
- this._useInstancing = this._engine.getCaps().instancedArrays;
270
- this._createIndexBuffer();
271
- this._createVertexBuffers();
272
- // Default emitter type
273
- this.particleEmitterType = new BoxParticleEmitter();
274
- let noiseTextureData = null;
275
- // Update
276
- this.updateFunction = (particles) => {
277
- let noiseTextureSize = null;
278
- if (this.noiseTexture) {
279
- // We need to get texture data back to CPU
280
- noiseTextureSize = this.noiseTexture.getSize();
281
- this.noiseTexture.getContent()?.then((data) => {
282
- noiseTextureData = data;
283
- });
284
- }
285
- const sameParticleArray = particles === this._particles;
286
- for (let index = 0; index < particles.length; index++) {
287
- const particle = particles[index];
288
- let scaledUpdateSpeed = this._scaledUpdateSpeed;
289
- const previousAge = particle.age;
290
- particle.age += scaledUpdateSpeed;
291
- // Evaluate step to death
292
- if (particle.age > particle.lifeTime) {
293
- const diff = particle.age - previousAge;
294
- const oldDiff = particle.lifeTime - previousAge;
295
- scaledUpdateSpeed = (oldDiff * scaledUpdateSpeed) / diff;
296
- particle.age = particle.lifeTime;
297
- }
298
- const ratio = particle.age / particle.lifeTime;
299
- // Color
300
- if (this._colorGradients && this._colorGradients.length > 0) {
301
- GradientHelper.GetCurrentGradient(ratio, this._colorGradients, (currentGradient, nextGradient, scale) => {
302
- if (currentGradient !== particle._currentColorGradient) {
303
- particle._currentColor1.copyFrom(particle._currentColor2);
304
- nextGradient.getColorToRef(particle._currentColor2);
305
- particle._currentColorGradient = currentGradient;
306
- }
307
- Color4.LerpToRef(particle._currentColor1, particle._currentColor2, scale, particle.color);
308
- });
309
- }
310
- else {
311
- particle.colorStep.scaleToRef(scaledUpdateSpeed, this._scaledColorStep);
312
- particle.color.addInPlace(this._scaledColorStep);
313
- if (particle.color.a < 0) {
314
- particle.color.a = 0;
315
- }
316
- }
317
- // Angular speed
318
- if (this._angularSpeedGradients && this._angularSpeedGradients.length > 0) {
319
- GradientHelper.GetCurrentGradient(ratio, this._angularSpeedGradients, (currentGradient, nextGradient, scale) => {
320
- if (currentGradient !== particle._currentAngularSpeedGradient) {
321
- particle._currentAngularSpeed1 = particle._currentAngularSpeed2;
322
- particle._currentAngularSpeed2 = nextGradient.getFactor();
323
- particle._currentAngularSpeedGradient = currentGradient;
324
- }
325
- particle.angularSpeed = Scalar.Lerp(particle._currentAngularSpeed1, particle._currentAngularSpeed2, scale);
326
- });
327
- }
328
- particle.angle += particle.angularSpeed * scaledUpdateSpeed;
329
- // Direction
330
- let directionScale = scaledUpdateSpeed;
331
- /// Velocity
332
- if (this._velocityGradients && this._velocityGradients.length > 0) {
333
- GradientHelper.GetCurrentGradient(ratio, this._velocityGradients, (currentGradient, nextGradient, scale) => {
334
- if (currentGradient !== particle._currentVelocityGradient) {
335
- particle._currentVelocity1 = particle._currentVelocity2;
336
- particle._currentVelocity2 = nextGradient.getFactor();
337
- particle._currentVelocityGradient = currentGradient;
338
- }
339
- directionScale *= Scalar.Lerp(particle._currentVelocity1, particle._currentVelocity2, scale);
340
- });
341
- }
342
- particle.direction.scaleToRef(directionScale, this._scaledDirection);
343
- /// Limit velocity
344
- if (this._limitVelocityGradients && this._limitVelocityGradients.length > 0) {
345
- GradientHelper.GetCurrentGradient(ratio, this._limitVelocityGradients, (currentGradient, nextGradient, scale) => {
346
- if (currentGradient !== particle._currentLimitVelocityGradient) {
347
- particle._currentLimitVelocity1 = particle._currentLimitVelocity2;
348
- particle._currentLimitVelocity2 = nextGradient.getFactor();
349
- particle._currentLimitVelocityGradient = currentGradient;
350
- }
351
- const limitVelocity = Scalar.Lerp(particle._currentLimitVelocity1, particle._currentLimitVelocity2, scale);
352
- const currentVelocity = particle.direction.length();
353
- if (currentVelocity > limitVelocity) {
354
- particle.direction.scaleInPlace(this.limitVelocityDamping);
355
- }
356
- });
357
- }
358
- /// Drag
359
- if (this._dragGradients && this._dragGradients.length > 0) {
360
- GradientHelper.GetCurrentGradient(ratio, this._dragGradients, (currentGradient, nextGradient, scale) => {
361
- if (currentGradient !== particle._currentDragGradient) {
362
- particle._currentDrag1 = particle._currentDrag2;
363
- particle._currentDrag2 = nextGradient.getFactor();
364
- particle._currentDragGradient = currentGradient;
365
- }
366
- const drag = Scalar.Lerp(particle._currentDrag1, particle._currentDrag2, scale);
367
- this._scaledDirection.scaleInPlace(1.0 - drag);
368
- });
369
- }
370
- if (this.isLocal && particle._localPosition) {
371
- particle._localPosition.addInPlace(this._scaledDirection);
372
- Vector3.TransformCoordinatesToRef(particle._localPosition, this._emitterWorldMatrix, particle.position);
373
- }
374
- else {
375
- particle.position.addInPlace(this._scaledDirection);
376
- }
377
- // Noise
378
- if (noiseTextureData && noiseTextureSize && particle._randomNoiseCoordinates1) {
379
- const fetchedColorR = this._fetchR(particle._randomNoiseCoordinates1.x, particle._randomNoiseCoordinates1.y, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
380
- const fetchedColorG = this._fetchR(particle._randomNoiseCoordinates1.z, particle._randomNoiseCoordinates2.x, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
381
- const fetchedColorB = this._fetchR(particle._randomNoiseCoordinates2.y, particle._randomNoiseCoordinates2.z, noiseTextureSize.width, noiseTextureSize.height, noiseTextureData);
382
- const force = TmpVectors.Vector3[0];
383
- const scaledForce = TmpVectors.Vector3[1];
384
- force.copyFromFloats((2 * fetchedColorR - 1) * this.noiseStrength.x, (2 * fetchedColorG - 1) * this.noiseStrength.y, (2 * fetchedColorB - 1) * this.noiseStrength.z);
385
- force.scaleToRef(scaledUpdateSpeed, scaledForce);
386
- particle.direction.addInPlace(scaledForce);
387
- }
388
- // Gravity
389
- this.gravity.scaleToRef(scaledUpdateSpeed, this._scaledGravity);
390
- particle.direction.addInPlace(this._scaledGravity);
391
- // Size
392
- if (this._sizeGradients && this._sizeGradients.length > 0) {
393
- GradientHelper.GetCurrentGradient(ratio, this._sizeGradients, (currentGradient, nextGradient, scale) => {
394
- if (currentGradient !== particle._currentSizeGradient) {
395
- particle._currentSize1 = particle._currentSize2;
396
- particle._currentSize2 = nextGradient.getFactor();
397
- particle._currentSizeGradient = currentGradient;
398
- }
399
- particle.size = Scalar.Lerp(particle._currentSize1, particle._currentSize2, scale);
400
- });
401
- }
402
- // Remap data
403
- if (this._useRampGradients) {
404
- if (this._colorRemapGradients && this._colorRemapGradients.length > 0) {
405
- GradientHelper.GetCurrentGradient(ratio, this._colorRemapGradients, (currentGradient, nextGradient, scale) => {
406
- const min = Scalar.Lerp(currentGradient.factor1, nextGradient.factor1, scale);
407
- const max = Scalar.Lerp(currentGradient.factor2, nextGradient.factor2, scale);
408
- particle.remapData.x = min;
409
- particle.remapData.y = max - min;
410
- });
411
- }
412
- if (this._alphaRemapGradients && this._alphaRemapGradients.length > 0) {
413
- GradientHelper.GetCurrentGradient(ratio, this._alphaRemapGradients, (currentGradient, nextGradient, scale) => {
414
- const min = Scalar.Lerp(currentGradient.factor1, nextGradient.factor1, scale);
415
- const max = Scalar.Lerp(currentGradient.factor2, nextGradient.factor2, scale);
416
- particle.remapData.z = min;
417
- particle.remapData.w = max - min;
418
- });
419
- }
420
- }
421
- if (this._isAnimationSheetEnabled) {
422
- particle.updateCellIndex();
423
- }
424
- // Update the position of the attached sub-emitters to match their attached particle
425
- particle._inheritParticleInfoToSubEmitters();
426
- if (particle.age >= particle.lifeTime) {
427
- // Recycle by swapping with last particle
428
- this._emitFromParticle(particle);
429
- if (particle._attachedSubEmitters) {
430
- particle._attachedSubEmitters.forEach((subEmitter) => {
431
- subEmitter.particleSystem.disposeOnStop = true;
432
- subEmitter.particleSystem.stop();
433
- });
434
- particle._attachedSubEmitters = null;
435
- }
436
- this.recycleParticle(particle);
437
- if (sameParticleArray) {
438
- index--;
439
- }
440
- continue;
441
- }
442
- }
443
- };
444
- }
445
- _addFactorGradient(factorGradients, gradient, factor, factor2) {
446
- const newGradient = new FactorGradient(gradient, factor, factor2);
447
- factorGradients.push(newGradient);
448
- factorGradients.sort((a, b) => {
449
- if (a.gradient < b.gradient) {
450
- return -1;
451
- }
452
- else if (a.gradient > b.gradient) {
453
- return 1;
454
- }
455
- return 0;
456
- });
457
- }
458
- _removeFactorGradient(factorGradients, gradient) {
459
- if (!factorGradients) {
460
- return;
461
- }
462
- let index = 0;
463
- for (const factorGradient of factorGradients) {
464
- if (factorGradient.gradient === gradient) {
465
- factorGradients.splice(index, 1);
466
- break;
467
- }
468
- index++;
469
- }
470
- }
471
- /**
472
- * Adds a new life time gradient
473
- * @param gradient defines the gradient to use (between 0 and 1)
474
- * @param factor defines the life time factor to affect to the specified gradient
475
- * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
476
- * @returns the current particle system
477
- */
478
- addLifeTimeGradient(gradient, factor, factor2) {
479
- if (!this._lifeTimeGradients) {
480
- this._lifeTimeGradients = [];
481
- }
482
- this._addFactorGradient(this._lifeTimeGradients, gradient, factor, factor2);
483
- return this;
484
- }
485
- /**
486
- * Remove a specific life time gradient
487
- * @param gradient defines the gradient to remove
488
- * @returns the current particle system
489
- */
490
- removeLifeTimeGradient(gradient) {
491
- this._removeFactorGradient(this._lifeTimeGradients, gradient);
492
- return this;
493
- }
494
- /**
495
- * Adds a new size gradient
496
- * @param gradient defines the gradient to use (between 0 and 1)
497
- * @param factor defines the size factor to affect to the specified gradient
498
- * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
499
- * @returns the current particle system
500
- */
501
- addSizeGradient(gradient, factor, factor2) {
502
- if (!this._sizeGradients) {
503
- this._sizeGradients = [];
504
- }
505
- this._addFactorGradient(this._sizeGradients, gradient, factor, factor2);
506
- return this;
507
- }
508
- /**
509
- * Remove a specific size gradient
510
- * @param gradient defines the gradient to remove
511
- * @returns the current particle system
512
- */
513
- removeSizeGradient(gradient) {
514
- this._removeFactorGradient(this._sizeGradients, gradient);
515
- return this;
516
- }
517
- /**
518
- * Adds a new color remap gradient
519
- * @param gradient defines the gradient to use (between 0 and 1)
520
- * @param min defines the color remap minimal range
521
- * @param max defines the color remap maximal range
522
- * @returns the current particle system
523
- */
524
- addColorRemapGradient(gradient, min, max) {
525
- if (!this._colorRemapGradients) {
526
- this._colorRemapGradients = [];
527
- }
528
- this._addFactorGradient(this._colorRemapGradients, gradient, min, max);
529
- return this;
530
- }
531
- /**
532
- * Remove a specific color remap gradient
533
- * @param gradient defines the gradient to remove
534
- * @returns the current particle system
535
- */
536
- removeColorRemapGradient(gradient) {
537
- this._removeFactorGradient(this._colorRemapGradients, gradient);
538
- return this;
539
- }
540
- /**
541
- * Adds a new alpha remap gradient
542
- * @param gradient defines the gradient to use (between 0 and 1)
543
- * @param min defines the alpha remap minimal range
544
- * @param max defines the alpha remap maximal range
545
- * @returns the current particle system
546
- */
547
- addAlphaRemapGradient(gradient, min, max) {
548
- if (!this._alphaRemapGradients) {
549
- this._alphaRemapGradients = [];
550
- }
551
- this._addFactorGradient(this._alphaRemapGradients, gradient, min, max);
552
- return this;
553
- }
554
- /**
555
- * Remove a specific alpha remap gradient
556
- * @param gradient defines the gradient to remove
557
- * @returns the current particle system
558
- */
559
- removeAlphaRemapGradient(gradient) {
560
- this._removeFactorGradient(this._alphaRemapGradients, gradient);
561
- return this;
562
- }
563
- /**
564
- * Adds a new angular speed gradient
565
- * @param gradient defines the gradient to use (between 0 and 1)
566
- * @param factor defines the angular speed to affect to the specified gradient
567
- * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
568
- * @returns the current particle system
569
- */
570
- addAngularSpeedGradient(gradient, factor, factor2) {
571
- if (!this._angularSpeedGradients) {
572
- this._angularSpeedGradients = [];
573
- }
574
- this._addFactorGradient(this._angularSpeedGradients, gradient, factor, factor2);
575
- return this;
576
47
  }
577
48
  /**
578
- * Remove a specific angular speed gradient
579
- * @param gradient defines the gradient to remove
580
- * @returns the current particle system
49
+ * Creates a Point Emitter for the particle system (emits directly from the emitter position)
50
+ * @param direction1 Particles are emitted between the direction1 and direction2 from within the box
51
+ * @param direction2 Particles are emitted between the direction1 and direction2 from within the box
52
+ * @returns the emitter
581
53
  */
582
- removeAngularSpeedGradient(gradient) {
583
- this._removeFactorGradient(this._angularSpeedGradients, gradient);
584
- return this;
54
+ createPointEmitter(direction1, direction2) {
55
+ const particleEmitter = CreatePointEmitter(direction1, direction2);
56
+ this.particleEmitterType = particleEmitter;
57
+ return particleEmitter;
585
58
  }
586
59
  /**
587
- * Adds a new velocity gradient
588
- * @param gradient defines the gradient to use (between 0 and 1)
589
- * @param factor defines the velocity to affect to the specified gradient
590
- * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
591
- * @returns the current particle system
60
+ * Creates a Hemisphere Emitter for the particle system (emits along the hemisphere radius)
61
+ * @param radius The radius of the hemisphere to emit from
62
+ * @param radiusRange The range of the hemisphere to emit from [0-1] 0 Surface Only, 1 Entire Radius
63
+ * @returns the emitter
592
64
  */
593
- addVelocityGradient(gradient, factor, factor2) {
594
- if (!this._velocityGradients) {
595
- this._velocityGradients = [];
596
- }
597
- this._addFactorGradient(this._velocityGradients, gradient, factor, factor2);
598
- return this;
599
- }
600
- /**
601
- * Remove a specific velocity gradient
602
- * @param gradient defines the gradient to remove
603
- * @returns the current particle system
604
- */
605
- removeVelocityGradient(gradient) {
606
- this._removeFactorGradient(this._velocityGradients, gradient);
607
- return this;
608
- }
609
- /**
610
- * Adds a new limit velocity gradient
611
- * @param gradient defines the gradient to use (between 0 and 1)
612
- * @param factor defines the limit velocity value to affect to the specified gradient
613
- * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
614
- * @returns the current particle system
615
- */
616
- addLimitVelocityGradient(gradient, factor, factor2) {
617
- if (!this._limitVelocityGradients) {
618
- this._limitVelocityGradients = [];
619
- }
620
- this._addFactorGradient(this._limitVelocityGradients, gradient, factor, factor2);
621
- return this;
622
- }
623
- /**
624
- * Remove a specific limit velocity gradient
625
- * @param gradient defines the gradient to remove
626
- * @returns the current particle system
627
- */
628
- removeLimitVelocityGradient(gradient) {
629
- this._removeFactorGradient(this._limitVelocityGradients, gradient);
630
- return this;
631
- }
632
- /**
633
- * Adds a new drag gradient
634
- * @param gradient defines the gradient to use (between 0 and 1)
635
- * @param factor defines the drag value to affect to the specified gradient
636
- * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
637
- * @returns the current particle system
638
- */
639
- addDragGradient(gradient, factor, factor2) {
640
- if (!this._dragGradients) {
641
- this._dragGradients = [];
642
- }
643
- this._addFactorGradient(this._dragGradients, gradient, factor, factor2);
644
- return this;
645
- }
646
- /**
647
- * Remove a specific drag gradient
648
- * @param gradient defines the gradient to remove
649
- * @returns the current particle system
650
- */
651
- removeDragGradient(gradient) {
652
- this._removeFactorGradient(this._dragGradients, gradient);
653
- return this;
654
- }
655
- /**
656
- * Adds a new emit rate gradient (please note that this will only work if you set the targetStopDuration property)
657
- * @param gradient defines the gradient to use (between 0 and 1)
658
- * @param factor defines the emit rate value to affect to the specified gradient
659
- * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
660
- * @returns the current particle system
661
- */
662
- addEmitRateGradient(gradient, factor, factor2) {
663
- if (!this._emitRateGradients) {
664
- this._emitRateGradients = [];
665
- }
666
- this._addFactorGradient(this._emitRateGradients, gradient, factor, factor2);
667
- return this;
668
- }
669
- /**
670
- * Remove a specific emit rate gradient
671
- * @param gradient defines the gradient to remove
672
- * @returns the current particle system
673
- */
674
- removeEmitRateGradient(gradient) {
675
- this._removeFactorGradient(this._emitRateGradients, gradient);
676
- return this;
677
- }
678
- /**
679
- * Adds a new start size gradient (please note that this will only work if you set the targetStopDuration property)
680
- * @param gradient defines the gradient to use (between 0 and 1)
681
- * @param factor defines the start size value to affect to the specified gradient
682
- * @param factor2 defines an additional factor used to define a range ([factor, factor2]) with main value to pick the final value from
683
- * @returns the current particle system
684
- */
685
- addStartSizeGradient(gradient, factor, factor2) {
686
- if (!this._startSizeGradients) {
687
- this._startSizeGradients = [];
688
- }
689
- this._addFactorGradient(this._startSizeGradients, gradient, factor, factor2);
690
- return this;
691
- }
692
- /**
693
- * Remove a specific start size gradient
694
- * @param gradient defines the gradient to remove
695
- * @returns the current particle system
696
- */
697
- removeStartSizeGradient(gradient) {
698
- this._removeFactorGradient(this._startSizeGradients, gradient);
699
- return this;
700
- }
701
- _createRampGradientTexture() {
702
- if (!this._rampGradients || !this._rampGradients.length || this._rampGradientsTexture || !this._scene) {
703
- return;
704
- }
705
- const data = new Uint8Array(this._rawTextureWidth * 4);
706
- const tmpColor = TmpColors.Color3[0];
707
- for (let x = 0; x < this._rawTextureWidth; x++) {
708
- const ratio = x / this._rawTextureWidth;
709
- GradientHelper.GetCurrentGradient(ratio, this._rampGradients, (currentGradient, nextGradient, scale) => {
710
- Color3.LerpToRef(currentGradient.color, nextGradient.color, scale, tmpColor);
711
- data[x * 4] = tmpColor.r * 255;
712
- data[x * 4 + 1] = tmpColor.g * 255;
713
- data[x * 4 + 2] = tmpColor.b * 255;
714
- data[x * 4 + 3] = 255;
715
- });
716
- }
717
- this._rampGradientsTexture = RawTexture.CreateRGBATexture(data, this._rawTextureWidth, 1, this._scene, false, false, 1);
718
- }
719
- /**
720
- * Gets the current list of ramp gradients.
721
- * You must use addRampGradient and removeRampGradient to update this list
722
- * @returns the list of ramp gradients
723
- */
724
- getRampGradients() {
725
- return this._rampGradients;
726
- }
727
- /** Force the system to rebuild all gradients that need to be resync */
728
- forceRefreshGradients() {
729
- this._syncRampGradientTexture();
730
- }
731
- _syncRampGradientTexture() {
732
- if (!this._rampGradients) {
733
- return;
734
- }
735
- this._rampGradients.sort((a, b) => {
736
- if (a.gradient < b.gradient) {
737
- return -1;
738
- }
739
- else if (a.gradient > b.gradient) {
740
- return 1;
741
- }
742
- return 0;
743
- });
744
- if (this._rampGradientsTexture) {
745
- this._rampGradientsTexture.dispose();
746
- this._rampGradientsTexture = null;
747
- }
748
- this._createRampGradientTexture();
65
+ createHemisphericEmitter(radius = 1, radiusRange = 1) {
66
+ const particleEmitter = CreateHemisphericEmitter(radius, radiusRange);
67
+ this.particleEmitterType = particleEmitter;
68
+ return particleEmitter;
749
69
  }
750
70
  /**
751
- * Adds a new ramp gradient used to remap particle colors
752
- * @param gradient defines the gradient to use (between 0 and 1)
753
- * @param color defines the color to affect to the specified gradient
754
- * @returns the current particle system
71
+ * Creates a Sphere Emitter for the particle system (emits along the sphere radius)
72
+ * @param radius The radius of the sphere to emit from
73
+ * @param radiusRange The range of the sphere to emit from [0-1] 0 Surface Only, 1 Entire Radius
74
+ * @returns the emitter
755
75
  */
756
- addRampGradient(gradient, color) {
757
- if (!this._rampGradients) {
758
- this._rampGradients = [];
759
- }
760
- const rampGradient = new Color3Gradient(gradient, color);
761
- this._rampGradients.push(rampGradient);
762
- this._syncRampGradientTexture();
763
- return this;
76
+ createSphereEmitter(radius = 1, radiusRange = 1) {
77
+ const particleEmitter = CreateSphereEmitter(radius, radiusRange);
78
+ this.particleEmitterType = particleEmitter;
79
+ return particleEmitter;
764
80
  }
765
81
  /**
766
- * Remove a specific ramp gradient
767
- * @param gradient defines the gradient to remove
768
- * @returns the current particle system
82
+ * Creates a Directed Sphere Emitter for the particle system (emits between direction1 and direction2)
83
+ * @param radius The radius of the sphere to emit from
84
+ * @param direction1 Particles are emitted between the direction1 and direction2 from within the sphere
85
+ * @param direction2 Particles are emitted between the direction1 and direction2 from within the sphere
86
+ * @returns the emitter
769
87
  */
770
- removeRampGradient(gradient) {
771
- this._removeGradientAndTexture(gradient, this._rampGradients, this._rampGradientsTexture);
772
- this._rampGradientsTexture = null;
773
- if (this._rampGradients && this._rampGradients.length > 0) {
774
- this._createRampGradientTexture();
775
- }
776
- return this;
777
- }
778
- /**
779
- * Adds a new color gradient
780
- * @param gradient defines the gradient to use (between 0 and 1)
781
- * @param color1 defines the color to affect to the specified gradient
782
- * @param color2 defines an additional color used to define a range ([color, color2]) with main color to pick the final color from
783
- * @returns this particle system
784
- */
785
- addColorGradient(gradient, color1, color2) {
786
- if (!this._colorGradients) {
787
- this._colorGradients = [];
788
- }
789
- const colorGradient = new ColorGradient(gradient, color1, color2);
790
- this._colorGradients.push(colorGradient);
791
- this._colorGradients.sort((a, b) => {
792
- if (a.gradient < b.gradient) {
793
- return -1;
794
- }
795
- else if (a.gradient > b.gradient) {
796
- return 1;
797
- }
798
- return 0;
799
- });
800
- return this;
801
- }
802
- /**
803
- * Remove a specific color gradient
804
- * @param gradient defines the gradient to remove
805
- * @returns this particle system
806
- */
807
- removeColorGradient(gradient) {
808
- if (!this._colorGradients) {
809
- return this;
810
- }
811
- let index = 0;
812
- for (const colorGradient of this._colorGradients) {
813
- if (colorGradient.gradient === gradient) {
814
- this._colorGradients.splice(index, 1);
815
- break;
816
- }
817
- index++;
818
- }
819
- return this;
88
+ createDirectedSphereEmitter(radius = 1, direction1 = new Vector3(0, 1.0, 0), direction2 = new Vector3(0, 1.0, 0)) {
89
+ const particleEmitter = CreateDirectedSphereEmitter(radius, direction1, direction2);
90
+ this.particleEmitterType = particleEmitter;
91
+ return particleEmitter;
820
92
  }
821
93
  /**
822
- * Resets the draw wrappers cache
94
+ * Creates a Cylinder Emitter for the particle system (emits from the cylinder to the particle position)
95
+ * @param radius The radius of the emission cylinder
96
+ * @param height The height of the emission cylinder
97
+ * @param radiusRange The range of emission [0-1] 0 Surface only, 1 Entire Radius
98
+ * @param directionRandomizer How much to randomize the particle direction [0-1]
99
+ * @returns the emitter
823
100
  */
824
- resetDrawCache() {
825
- for (const drawWrappers of this._drawWrappers) {
826
- if (drawWrappers) {
827
- for (const drawWrapper of drawWrappers) {
828
- drawWrapper?.dispose();
829
- }
830
- }
831
- }
832
- this._drawWrappers = [];
833
- }
834
- _fetchR(u, v, width, height, pixels) {
835
- u = Math.abs(u) * 0.5 + 0.5;
836
- v = Math.abs(v) * 0.5 + 0.5;
837
- const wrappedU = (u * width) % width | 0;
838
- const wrappedV = (v * height) % height | 0;
839
- const position = (wrappedU + wrappedV * width) * 4;
840
- return pixels[position] / 255;
841
- }
842
- _reset() {
843
- this._resetEffect();
844
- }
845
- _resetEffect() {
846
- if (this._vertexBuffer) {
847
- this._vertexBuffer.dispose();
848
- this._vertexBuffer = null;
849
- }
850
- if (this._spriteBuffer) {
851
- this._spriteBuffer.dispose();
852
- this._spriteBuffer = null;
853
- }
854
- if (this._vertexArrayObject) {
855
- this._engine.releaseVertexArrayObject(this._vertexArrayObject);
856
- this._vertexArrayObject = null;
857
- }
858
- this._createVertexBuffers();
859
- }
860
- _createVertexBuffers() {
861
- this._vertexBufferSize = this._useInstancing ? 10 : 12;
862
- if (this._isAnimationSheetEnabled) {
863
- this._vertexBufferSize += 1;
864
- }
865
- if (!this._isBillboardBased || this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED || this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL) {
866
- this._vertexBufferSize += 3;
867
- }
868
- if (this._useRampGradients) {
869
- this._vertexBufferSize += 4;
870
- }
871
- const engine = this._engine;
872
- const vertexSize = this._vertexBufferSize * (this._useInstancing ? 1 : 4);
873
- this._vertexData = new Float32Array(this._capacity * vertexSize);
874
- this._vertexBuffer = new Buffer(engine, this._vertexData, true, vertexSize);
875
- let dataOffset = 0;
876
- const positions = this._vertexBuffer.createVertexBuffer(VertexBuffer.PositionKind, dataOffset, 3, this._vertexBufferSize, this._useInstancing);
877
- this._vertexBuffers[VertexBuffer.PositionKind] = positions;
878
- dataOffset += 3;
879
- const colors = this._vertexBuffer.createVertexBuffer(VertexBuffer.ColorKind, dataOffset, 4, this._vertexBufferSize, this._useInstancing);
880
- this._vertexBuffers[VertexBuffer.ColorKind] = colors;
881
- dataOffset += 4;
882
- const options = this._vertexBuffer.createVertexBuffer("angle", dataOffset, 1, this._vertexBufferSize, this._useInstancing);
883
- this._vertexBuffers["angle"] = options;
884
- dataOffset += 1;
885
- const size = this._vertexBuffer.createVertexBuffer("size", dataOffset, 2, this._vertexBufferSize, this._useInstancing);
886
- this._vertexBuffers["size"] = size;
887
- dataOffset += 2;
888
- if (this._isAnimationSheetEnabled) {
889
- const cellIndexBuffer = this._vertexBuffer.createVertexBuffer("cellIndex", dataOffset, 1, this._vertexBufferSize, this._useInstancing);
890
- this._vertexBuffers["cellIndex"] = cellIndexBuffer;
891
- dataOffset += 1;
892
- }
893
- if (!this._isBillboardBased || this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED || this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL) {
894
- const directionBuffer = this._vertexBuffer.createVertexBuffer("direction", dataOffset, 3, this._vertexBufferSize, this._useInstancing);
895
- this._vertexBuffers["direction"] = directionBuffer;
896
- dataOffset += 3;
897
- }
898
- if (this._useRampGradients) {
899
- const rampDataBuffer = this._vertexBuffer.createVertexBuffer("remapData", dataOffset, 4, this._vertexBufferSize, this._useInstancing);
900
- this._vertexBuffers["remapData"] = rampDataBuffer;
901
- dataOffset += 4;
902
- }
903
- let offsets;
904
- if (this._useInstancing) {
905
- const spriteData = new Float32Array([0, 0, 1, 0, 0, 1, 1, 1]);
906
- this._spriteBuffer = new Buffer(engine, spriteData, false, 2);
907
- offsets = this._spriteBuffer.createVertexBuffer("offset", 0, 2);
908
- }
909
- else {
910
- offsets = this._vertexBuffer.createVertexBuffer("offset", dataOffset, 2, this._vertexBufferSize, this._useInstancing);
911
- dataOffset += 2;
912
- }
913
- this._vertexBuffers["offset"] = offsets;
914
- this.resetDrawCache();
915
- }
916
- _createIndexBuffer() {
917
- if (this._useInstancing) {
918
- this._linesIndexBufferUseInstancing = this._engine.createIndexBuffer(new Uint32Array([0, 1, 1, 3, 3, 2, 2, 0, 0, 3]));
919
- return;
920
- }
921
- const indices = [];
922
- const indicesWireframe = [];
923
- let index = 0;
924
- for (let count = 0; count < this._capacity; count++) {
925
- indices.push(index);
926
- indices.push(index + 1);
927
- indices.push(index + 2);
928
- indices.push(index);
929
- indices.push(index + 2);
930
- indices.push(index + 3);
931
- indicesWireframe.push(index, index + 1, index + 1, index + 2, index + 2, index + 3, index + 3, index, index, index + 3);
932
- index += 4;
933
- }
934
- this._indexBuffer = this._engine.createIndexBuffer(indices);
935
- this._linesIndexBuffer = this._engine.createIndexBuffer(indicesWireframe);
101
+ createCylinderEmitter(radius = 1, height = 1, radiusRange = 1, directionRandomizer = 0) {
102
+ const particleEmitter = CreateCylinderEmitter(radius, height, radiusRange, directionRandomizer);
103
+ this.particleEmitterType = particleEmitter;
104
+ return particleEmitter;
936
105
  }
937
106
  /**
938
- * Gets the maximum number of particles active at the same time.
939
- * @returns The max number of active particles.
107
+ * Creates a Directed Cylinder Emitter for the particle system (emits between direction1 and direction2)
108
+ * @param radius The radius of the cylinder to emit from
109
+ * @param height The height of the emission cylinder
110
+ * @param radiusRange the range of the emission cylinder [0-1] 0 Surface only, 1 Entire Radius (1 by default)
111
+ * @param direction1 Particles are emitted between the direction1 and direction2 from within the cylinder
112
+ * @param direction2 Particles are emitted between the direction1 and direction2 from within the cylinder
113
+ * @returns the emitter
940
114
  */
941
- getCapacity() {
942
- return this._capacity;
115
+ createDirectedCylinderEmitter(radius = 1, height = 1, radiusRange = 1, direction1 = new Vector3(0, 1.0, 0), direction2 = new Vector3(0, 1.0, 0)) {
116
+ const particleEmitter = CreateDirectedCylinderEmitter(radius, height, radiusRange, direction1, direction2);
117
+ this.particleEmitterType = particleEmitter;
118
+ return particleEmitter;
943
119
  }
944
120
  /**
945
- * Gets whether there are still active particles in the system.
946
- * @returns True if it is alive, otherwise false.
121
+ * Creates a Cone Emitter for the particle system (emits from the cone to the particle position)
122
+ * @param radius The radius of the cone to emit from
123
+ * @param angle The base angle of the cone
124
+ * @returns the emitter
947
125
  */
948
- isAlive() {
949
- return this._alive;
126
+ createConeEmitter(radius = 1, angle = Math.PI / 4) {
127
+ const particleEmitter = CreateConeEmitter(radius, angle);
128
+ this.particleEmitterType = particleEmitter;
129
+ return particleEmitter;
950
130
  }
951
131
  /**
952
- * Gets if the system has been started. (Note: this will still be true after stop is called)
953
- * @returns True if it has been started, otherwise false.
132
+ * Creates a Box Emitter for the particle system. (emits between direction1 and direction2 from withing the box defined by minEmitBox and maxEmitBox)
133
+ * @param direction1 Particles are emitted between the direction1 and direction2 from within the box
134
+ * @param direction2 Particles are emitted between the direction1 and direction2 from within the box
135
+ * @param minEmitBox Particles are emitted from the box between minEmitBox and maxEmitBox
136
+ * @param maxEmitBox Particles are emitted from the box between minEmitBox and maxEmitBox
137
+ * @returns the emitter
954
138
  */
955
- isStarted() {
956
- return this._started;
139
+ createBoxEmitter(direction1, direction2, minEmitBox, maxEmitBox) {
140
+ const particleEmitter = new BoxParticleEmitter();
141
+ this.particleEmitterType = particleEmitter;
142
+ this.direction1 = direction1;
143
+ this.direction2 = direction2;
144
+ this.minEmitBox = minEmitBox;
145
+ this.maxEmitBox = maxEmitBox;
146
+ return particleEmitter;
957
147
  }
958
148
  _prepareSubEmitterInternalArray() {
959
149
  this._subEmitters = new Array();
@@ -971,895 +161,349 @@ export class ParticleSystem extends BaseParticleSystem {
971
161
  });
972
162
  }
973
163
  }
974
- /**
975
- * Starts the particle system and begins to emit
976
- * @param delay defines the delay in milliseconds before starting the system (this.startDelay by default)
977
- */
978
- start(delay = this.startDelay) {
979
- if (!this.targetStopDuration && this._hasTargetStopDurationDependantGradient()) {
980
- // eslint-disable-next-line no-throw-literal
981
- throw "Particle system started with a targetStopDuration dependant gradient (eg. startSizeGradients) but no targetStopDuration set";
982
- }
983
- if (delay) {
984
- setTimeout(() => {
985
- this.start(0);
986
- }, delay);
164
+ _stopSubEmitters() {
165
+ if (!this.activeSubSystems) {
166
+ return;
167
+ }
168
+ this.activeSubSystems.forEach((subSystem) => {
169
+ subSystem.stop(true);
170
+ });
171
+ this.activeSubSystems = [];
172
+ }
173
+ _removeFromRoot() {
174
+ if (!this._rootParticleSystem) {
987
175
  return;
988
176
  }
177
+ const index = this._rootParticleSystem.activeSubSystems.indexOf(this);
178
+ if (index !== -1) {
179
+ this._rootParticleSystem.activeSubSystems.splice(index, 1);
180
+ }
181
+ this._rootParticleSystem = null;
182
+ }
183
+ _preStart() {
989
184
  // Convert the subEmitters field to the constant type field _subEmitters
990
185
  this._prepareSubEmitterInternalArray();
991
- this._started = true;
992
- this._stopped = false;
993
- this._actualFrame = 0;
994
186
  if (this._subEmitters && this._subEmitters.length != 0) {
995
187
  this.activeSubSystems = [];
996
188
  }
997
- // Reset emit gradient so it acts the same on every start
998
- if (this._emitRateGradients) {
999
- if (this._emitRateGradients.length > 0) {
1000
- this._currentEmitRateGradient = this._emitRateGradients[0];
1001
- this._currentEmitRate1 = this._currentEmitRateGradient.getFactor();
1002
- this._currentEmitRate2 = this._currentEmitRate1;
1003
- }
1004
- if (this._emitRateGradients.length > 1) {
1005
- this._currentEmitRate2 = this._emitRateGradients[1].getFactor();
1006
- }
189
+ }
190
+ _postStop(stopSubEmitters) {
191
+ if (stopSubEmitters) {
192
+ this._stopSubEmitters();
1007
193
  }
1008
- // Reset start size gradient so it acts the same on every start
1009
- if (this._startSizeGradients) {
1010
- if (this._startSizeGradients.length > 0) {
1011
- this._currentStartSizeGradient = this._startSizeGradients[0];
1012
- this._currentStartSize1 = this._currentStartSizeGradient.getFactor();
1013
- this._currentStartSize2 = this._currentStartSize1;
1014
- }
1015
- if (this._startSizeGradients.length > 1) {
1016
- this._currentStartSize2 = this._startSizeGradients[1].getFactor();
1017
- }
194
+ }
195
+ _prepareParticle(particle) {
196
+ // Attach emitters
197
+ if (this._subEmitters && this._subEmitters.length > 0) {
198
+ const subEmitters = this._subEmitters[Math.floor(Math.random() * this._subEmitters.length)];
199
+ particle._attachedSubEmitters = [];
200
+ subEmitters.forEach((subEmitter) => {
201
+ if (subEmitter.type === SubEmitterType.ATTACHED) {
202
+ const newEmitter = subEmitter.clone();
203
+ particle._attachedSubEmitters.push(newEmitter);
204
+ newEmitter.particleSystem.start();
205
+ }
206
+ });
1018
207
  }
1019
- if (this.preWarmCycles) {
1020
- if (this.emitter?.getClassName().indexOf("Mesh") !== -1) {
1021
- this.emitter.computeWorldMatrix(true);
1022
- }
1023
- const noiseTextureAsProcedural = this.noiseTexture;
1024
- if (noiseTextureAsProcedural && noiseTextureAsProcedural.onGeneratedObservable) {
1025
- noiseTextureAsProcedural.onGeneratedObservable.addOnce(() => {
1026
- setTimeout(() => {
1027
- for (let index = 0; index < this.preWarmCycles; index++) {
1028
- this.animate(true);
1029
- noiseTextureAsProcedural.render();
1030
- }
1031
- });
1032
- });
1033
- }
1034
- else {
1035
- for (let index = 0; index < this.preWarmCycles; index++) {
1036
- this.animate(true);
208
+ }
209
+ /** @internal */
210
+ _onDispose() {
211
+ this._removeFromRoot();
212
+ if (this.subEmitters && !this._subEmitters) {
213
+ this._prepareSubEmitterInternalArray();
214
+ }
215
+ if (this._subEmitters && this._subEmitters.length) {
216
+ for (let index = 0; index < this._subEmitters.length; index++) {
217
+ for (const subEmitter of this._subEmitters[index]) {
218
+ subEmitter.dispose();
1037
219
  }
1038
220
  }
221
+ this._subEmitters = [];
222
+ this.subEmitters = [];
1039
223
  }
1040
- // Animations
1041
- if (this.beginAnimationOnStart && this.animations && this.animations.length > 0 && this._scene) {
1042
- this._scene.beginAnimation(this, this.beginAnimationFrom, this.beginAnimationTo, this.beginAnimationLoop);
224
+ if (this._disposeEmitterOnDispose && this.emitter && this.emitter.dispose) {
225
+ this.emitter.dispose(true);
1043
226
  }
1044
227
  }
1045
228
  /**
1046
- * Stops the particle system.
1047
- * @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.
229
+ * @internal
1048
230
  */
1049
- stop(stopSubEmitters = true) {
1050
- if (this._stopped) {
1051
- return;
231
+ static _Parse(parsedParticleSystem, particleSystem, sceneOrEngine, rootUrl) {
232
+ let scene;
233
+ if (sceneOrEngine instanceof ThinEngine) {
234
+ scene = null;
1052
235
  }
1053
- this.onStoppedObservable.notifyObservers(this);
1054
- this._stopped = true;
1055
- if (stopSubEmitters) {
1056
- this._stopSubEmitters();
236
+ else {
237
+ scene = sceneOrEngine;
1057
238
  }
1058
- }
1059
- // animation sheet
1060
- /**
1061
- * Remove all active particles
1062
- */
1063
- reset() {
1064
- this._stockParticles.length = 0;
1065
- this._particles.length = 0;
1066
- }
1067
- /**
1068
- * @internal (for internal use only)
1069
- */
1070
- _appendParticleVertex(index, particle, offsetX, offsetY) {
1071
- let offset = index * this._vertexBufferSize;
1072
- this._vertexData[offset++] = particle.position.x + this.worldOffset.x;
1073
- this._vertexData[offset++] = particle.position.y + this.worldOffset.y;
1074
- this._vertexData[offset++] = particle.position.z + this.worldOffset.z;
1075
- this._vertexData[offset++] = particle.color.r;
1076
- this._vertexData[offset++] = particle.color.g;
1077
- this._vertexData[offset++] = particle.color.b;
1078
- this._vertexData[offset++] = particle.color.a;
1079
- this._vertexData[offset++] = particle.angle;
1080
- this._vertexData[offset++] = particle.scale.x * particle.size;
1081
- this._vertexData[offset++] = particle.scale.y * particle.size;
1082
- if (this._isAnimationSheetEnabled) {
1083
- this._vertexData[offset++] = particle.cellIndex;
1084
- }
1085
- if (!this._isBillboardBased) {
1086
- if (particle._initialDirection) {
1087
- let initialDirection = particle._initialDirection;
1088
- if (this.isLocal) {
1089
- Vector3.TransformNormalToRef(initialDirection, this._emitterWorldMatrix, TmpVectors.Vector3[0]);
1090
- initialDirection = TmpVectors.Vector3[0];
1091
- }
1092
- if (initialDirection.x === 0 && initialDirection.z === 0) {
1093
- initialDirection.x = 0.001;
1094
- }
1095
- this._vertexData[offset++] = initialDirection.x;
1096
- this._vertexData[offset++] = initialDirection.y;
1097
- this._vertexData[offset++] = initialDirection.z;
1098
- }
1099
- else {
1100
- let direction = particle.direction;
1101
- if (this.isLocal) {
1102
- Vector3.TransformNormalToRef(direction, this._emitterWorldMatrix, TmpVectors.Vector3[0]);
1103
- direction = TmpVectors.Vector3[0];
1104
- }
1105
- if (direction.x === 0 && direction.z === 0) {
1106
- direction.x = 0.001;
1107
- }
1108
- this._vertexData[offset++] = direction.x;
1109
- this._vertexData[offset++] = direction.y;
1110
- this._vertexData[offset++] = direction.z;
239
+ const internalClass = GetClass("BABYLON.Texture");
240
+ if (internalClass && scene) {
241
+ // Texture
242
+ if (parsedParticleSystem.texture) {
243
+ particleSystem.particleTexture = internalClass.Parse(parsedParticleSystem.texture, scene, rootUrl);
1111
244
  }
1112
- }
1113
- else if (this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED || this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL) {
1114
- this._vertexData[offset++] = particle.direction.x;
1115
- this._vertexData[offset++] = particle.direction.y;
1116
- this._vertexData[offset++] = particle.direction.z;
1117
- }
1118
- if (this._useRampGradients && particle.remapData) {
1119
- this._vertexData[offset++] = particle.remapData.x;
1120
- this._vertexData[offset++] = particle.remapData.y;
1121
- this._vertexData[offset++] = particle.remapData.z;
1122
- this._vertexData[offset++] = particle.remapData.w;
1123
- }
1124
- if (!this._useInstancing) {
1125
- if (this._isAnimationSheetEnabled) {
1126
- if (offsetX === 0) {
1127
- offsetX = this._epsilon;
1128
- }
1129
- else if (offsetX === 1) {
1130
- offsetX = 1 - this._epsilon;
1131
- }
1132
- if (offsetY === 0) {
1133
- offsetY = this._epsilon;
1134
- }
1135
- else if (offsetY === 1) {
1136
- offsetY = 1 - this._epsilon;
1137
- }
245
+ else if (parsedParticleSystem.textureName) {
246
+ particleSystem.particleTexture = new internalClass(rootUrl + parsedParticleSystem.textureName, scene, false, parsedParticleSystem.invertY !== undefined ? parsedParticleSystem.invertY : true);
247
+ particleSystem.particleTexture.name = parsedParticleSystem.textureName;
1138
248
  }
1139
- this._vertexData[offset++] = offsetX;
1140
- this._vertexData[offset++] = offsetY;
1141
- }
1142
- }
1143
- _stopSubEmitters() {
1144
- if (!this.activeSubSystems) {
1145
- return;
1146
- }
1147
- this.activeSubSystems.forEach((subSystem) => {
1148
- subSystem.stop(true);
1149
- });
1150
- this.activeSubSystems = [];
1151
- }
1152
- _removeFromRoot() {
1153
- if (!this._rootParticleSystem) {
1154
- return;
1155
249
  }
1156
- const index = this._rootParticleSystem.activeSubSystems.indexOf(this);
1157
- if (index !== -1) {
1158
- this._rootParticleSystem.activeSubSystems.splice(index, 1);
250
+ // Emitter
251
+ if (!parsedParticleSystem.emitterId && parsedParticleSystem.emitterId !== 0 && parsedParticleSystem.emitter === undefined) {
252
+ particleSystem.emitter = Vector3.Zero();
1159
253
  }
1160
- this._rootParticleSystem = null;
1161
- }
1162
- // End of sub system methods
1163
- _update(newParticles) {
1164
- // Update current
1165
- this._alive = this._particles.length > 0;
1166
- if (this.emitter.position) {
1167
- const emitterMesh = this.emitter;
1168
- this._emitterWorldMatrix = emitterMesh.getWorldMatrix();
254
+ else if (parsedParticleSystem.emitterId && scene) {
255
+ particleSystem.emitter = scene.getLastMeshById(parsedParticleSystem.emitterId);
1169
256
  }
1170
257
  else {
1171
- const emitterPosition = this.emitter;
1172
- this._emitterWorldMatrix = Matrix.Translation(emitterPosition.x, emitterPosition.y, emitterPosition.z);
1173
- }
1174
- this._emitterWorldMatrix.invertToRef(this._emitterInverseWorldMatrix);
1175
- this.updateFunction(this._particles);
1176
- // Add new ones
1177
- let particle;
1178
- for (let index = 0; index < newParticles; index++) {
1179
- if (this._particles.length === this._capacity) {
1180
- break;
1181
- }
1182
- particle = this._createParticle();
1183
- this._particles.push(particle);
1184
- // Life time
1185
- if (this.targetStopDuration && this._lifeTimeGradients && this._lifeTimeGradients.length > 0) {
1186
- const ratio = Scalar.Clamp(this._actualFrame / this.targetStopDuration);
1187
- GradientHelper.GetCurrentGradient(ratio, this._lifeTimeGradients, (currentGradient, nextGradient) => {
1188
- const factorGradient1 = currentGradient;
1189
- const factorGradient2 = nextGradient;
1190
- const lifeTime1 = factorGradient1.getFactor();
1191
- const lifeTime2 = factorGradient2.getFactor();
1192
- const gradient = (ratio - factorGradient1.gradient) / (factorGradient2.gradient - factorGradient1.gradient);
1193
- particle.lifeTime = Scalar.Lerp(lifeTime1, lifeTime2, gradient);
1194
- });
1195
- }
1196
- else {
1197
- particle.lifeTime = Scalar.RandomRange(this.minLifeTime, this.maxLifeTime);
1198
- }
1199
- // Emitter
1200
- const emitPower = Scalar.RandomRange(this.minEmitPower, this.maxEmitPower);
1201
- if (this.startPositionFunction) {
1202
- this.startPositionFunction(this._emitterWorldMatrix, particle.position, particle, this.isLocal);
1203
- }
1204
- else {
1205
- this.particleEmitterType.startPositionFunction(this._emitterWorldMatrix, particle.position, particle, this.isLocal);
1206
- }
1207
- if (this.isLocal) {
1208
- if (!particle._localPosition) {
1209
- particle._localPosition = particle.position.clone();
1210
- }
1211
- else {
1212
- particle._localPosition.copyFrom(particle.position);
1213
- }
1214
- Vector3.TransformCoordinatesToRef(particle._localPosition, this._emitterWorldMatrix, particle.position);
1215
- }
1216
- if (this.startDirectionFunction) {
1217
- this.startDirectionFunction(this._emitterWorldMatrix, particle.direction, particle, this.isLocal);
1218
- }
1219
- else {
1220
- this.particleEmitterType.startDirectionFunction(this._emitterWorldMatrix, particle.direction, particle, this.isLocal, this._emitterInverseWorldMatrix);
1221
- }
1222
- if (emitPower === 0) {
1223
- if (!particle._initialDirection) {
1224
- particle._initialDirection = particle.direction.clone();
1225
- }
1226
- else {
1227
- particle._initialDirection.copyFrom(particle.direction);
1228
- }
1229
- }
1230
- else {
1231
- particle._initialDirection = null;
1232
- }
1233
- particle.direction.scaleInPlace(emitPower);
1234
- // Size
1235
- if (!this._sizeGradients || this._sizeGradients.length === 0) {
1236
- particle.size = Scalar.RandomRange(this.minSize, this.maxSize);
1237
- }
1238
- else {
1239
- particle._currentSizeGradient = this._sizeGradients[0];
1240
- particle._currentSize1 = particle._currentSizeGradient.getFactor();
1241
- particle.size = particle._currentSize1;
1242
- if (this._sizeGradients.length > 1) {
1243
- particle._currentSize2 = this._sizeGradients[1].getFactor();
1244
- }
1245
- else {
1246
- particle._currentSize2 = particle._currentSize1;
1247
- }
1248
- }
1249
- // Size and scale
1250
- particle.scale.copyFromFloats(Scalar.RandomRange(this.minScaleX, this.maxScaleX), Scalar.RandomRange(this.minScaleY, this.maxScaleY));
1251
- // Adjust scale by start size
1252
- if (this._startSizeGradients && this._startSizeGradients[0] && this.targetStopDuration) {
1253
- const ratio = this._actualFrame / this.targetStopDuration;
1254
- GradientHelper.GetCurrentGradient(ratio, this._startSizeGradients, (currentGradient, nextGradient, scale) => {
1255
- if (currentGradient !== this._currentStartSizeGradient) {
1256
- this._currentStartSize1 = this._currentStartSize2;
1257
- this._currentStartSize2 = nextGradient.getFactor();
1258
- this._currentStartSizeGradient = currentGradient;
1259
- }
1260
- const value = Scalar.Lerp(this._currentStartSize1, this._currentStartSize2, scale);
1261
- particle.scale.scaleInPlace(value);
1262
- });
1263
- }
1264
- // Angle
1265
- if (!this._angularSpeedGradients || this._angularSpeedGradients.length === 0) {
1266
- particle.angularSpeed = Scalar.RandomRange(this.minAngularSpeed, this.maxAngularSpeed);
1267
- }
1268
- else {
1269
- particle._currentAngularSpeedGradient = this._angularSpeedGradients[0];
1270
- particle.angularSpeed = particle._currentAngularSpeedGradient.getFactor();
1271
- particle._currentAngularSpeed1 = particle.angularSpeed;
1272
- if (this._angularSpeedGradients.length > 1) {
1273
- particle._currentAngularSpeed2 = this._angularSpeedGradients[1].getFactor();
1274
- }
1275
- else {
1276
- particle._currentAngularSpeed2 = particle._currentAngularSpeed1;
1277
- }
1278
- }
1279
- particle.angle = Scalar.RandomRange(this.minInitialRotation, this.maxInitialRotation);
1280
- // Velocity
1281
- if (this._velocityGradients && this._velocityGradients.length > 0) {
1282
- particle._currentVelocityGradient = this._velocityGradients[0];
1283
- particle._currentVelocity1 = particle._currentVelocityGradient.getFactor();
1284
- if (this._velocityGradients.length > 1) {
1285
- particle._currentVelocity2 = this._velocityGradients[1].getFactor();
1286
- }
1287
- else {
1288
- particle._currentVelocity2 = particle._currentVelocity1;
1289
- }
1290
- }
1291
- // Limit velocity
1292
- if (this._limitVelocityGradients && this._limitVelocityGradients.length > 0) {
1293
- particle._currentLimitVelocityGradient = this._limitVelocityGradients[0];
1294
- particle._currentLimitVelocity1 = particle._currentLimitVelocityGradient.getFactor();
1295
- if (this._limitVelocityGradients.length > 1) {
1296
- particle._currentLimitVelocity2 = this._limitVelocityGradients[1].getFactor();
1297
- }
1298
- else {
1299
- particle._currentLimitVelocity2 = particle._currentLimitVelocity1;
1300
- }
1301
- }
1302
- // Drag
1303
- if (this._dragGradients && this._dragGradients.length > 0) {
1304
- particle._currentDragGradient = this._dragGradients[0];
1305
- particle._currentDrag1 = particle._currentDragGradient.getFactor();
1306
- if (this._dragGradients.length > 1) {
1307
- particle._currentDrag2 = this._dragGradients[1].getFactor();
1308
- }
1309
- else {
1310
- particle._currentDrag2 = particle._currentDrag1;
1311
- }
1312
- }
1313
- // Color
1314
- if (!this._colorGradients || this._colorGradients.length === 0) {
1315
- const step = Scalar.RandomRange(0, 1.0);
1316
- Color4.LerpToRef(this.color1, this.color2, step, particle.color);
1317
- this.colorDead.subtractToRef(particle.color, this._colorDiff);
1318
- this._colorDiff.scaleToRef(1.0 / particle.lifeTime, particle.colorStep);
1319
- }
1320
- else {
1321
- particle._currentColorGradient = this._colorGradients[0];
1322
- particle._currentColorGradient.getColorToRef(particle.color);
1323
- particle._currentColor1.copyFrom(particle.color);
1324
- if (this._colorGradients.length > 1) {
1325
- this._colorGradients[1].getColorToRef(particle._currentColor2);
1326
- }
1327
- else {
1328
- particle._currentColor2.copyFrom(particle.color);
1329
- }
1330
- }
1331
- // Sheet
1332
- if (this._isAnimationSheetEnabled) {
1333
- particle._initialStartSpriteCellID = this.startSpriteCellID;
1334
- particle._initialEndSpriteCellID = this.endSpriteCellID;
1335
- particle._initialSpriteCellLoop = this.spriteCellLoop;
1336
- }
1337
- // Inherited Velocity
1338
- particle.direction.addInPlace(this._inheritedVelocityOffset);
1339
- // Ramp
1340
- if (this._useRampGradients) {
1341
- particle.remapData = new Vector4(0, 1, 0, 1);
1342
- }
1343
- // Noise texture coordinates
1344
- if (this.noiseTexture) {
1345
- if (particle._randomNoiseCoordinates1) {
1346
- particle._randomNoiseCoordinates1.copyFromFloats(Math.random(), Math.random(), Math.random());
1347
- particle._randomNoiseCoordinates2.copyFromFloats(Math.random(), Math.random(), Math.random());
1348
- }
1349
- else {
1350
- particle._randomNoiseCoordinates1 = new Vector3(Math.random(), Math.random(), Math.random());
1351
- particle._randomNoiseCoordinates2 = new Vector3(Math.random(), Math.random(), Math.random());
1352
- }
1353
- }
1354
- // Update the position of the attached sub-emitters to match their attached particle
1355
- particle._inheritParticleInfoToSubEmitters();
1356
- }
1357
- }
1358
- /**
1359
- * @internal
1360
- */
1361
- static _GetAttributeNamesOrOptions(isAnimationSheetEnabled = false, isBillboardBased = false, useRampGradients = false) {
1362
- const attributeNamesOrOptions = [VertexBuffer.PositionKind, VertexBuffer.ColorKind, "angle", "offset", "size"];
1363
- if (isAnimationSheetEnabled) {
1364
- attributeNamesOrOptions.push("cellIndex");
1365
- }
1366
- if (!isBillboardBased) {
1367
- attributeNamesOrOptions.push("direction");
258
+ particleSystem.emitter = Vector3.FromArray(parsedParticleSystem.emitter);
1368
259
  }
1369
- if (useRampGradients) {
1370
- attributeNamesOrOptions.push("remapData");
260
+ particleSystem.isLocal = !!parsedParticleSystem.isLocal;
261
+ // Misc.
262
+ if (parsedParticleSystem.renderingGroupId !== undefined) {
263
+ particleSystem.renderingGroupId = parsedParticleSystem.renderingGroupId;
1371
264
  }
1372
- return attributeNamesOrOptions;
1373
- }
1374
- /**
1375
- * @internal
1376
- */
1377
- static _GetEffectCreationOptions(isAnimationSheetEnabled = false, useLogarithmicDepth = false, applyFog = false) {
1378
- const effectCreationOption = ["invView", "view", "projection", "textureMask", "translationPivot", "eyePosition"];
1379
- addClipPlaneUniforms(effectCreationOption);
1380
- if (isAnimationSheetEnabled) {
1381
- effectCreationOption.push("particlesInfos");
265
+ if (parsedParticleSystem.isBillboardBased !== undefined) {
266
+ particleSystem.isBillboardBased = parsedParticleSystem.isBillboardBased;
1382
267
  }
1383
- if (useLogarithmicDepth) {
1384
- effectCreationOption.push("logarithmicDepthConstant");
268
+ if (parsedParticleSystem.billboardMode !== undefined) {
269
+ particleSystem.billboardMode = parsedParticleSystem.billboardMode;
1385
270
  }
1386
- if (applyFog) {
1387
- effectCreationOption.push("vFogInfos");
1388
- effectCreationOption.push("vFogColor");
271
+ if (parsedParticleSystem.useLogarithmicDepth !== undefined) {
272
+ particleSystem.useLogarithmicDepth = parsedParticleSystem.useLogarithmicDepth;
1389
273
  }
1390
- return effectCreationOption;
1391
- }
1392
- /**
1393
- * Fill the defines array according to the current settings of the particle system
1394
- * @param defines Array to be updated
1395
- * @param blendMode blend mode to take into account when updating the array
1396
- */
1397
- fillDefines(defines, blendMode) {
1398
- if (this._scene) {
1399
- prepareStringDefinesForClipPlanes(this, this._scene, defines);
1400
- if (this.applyFog && this._scene.fogEnabled && this._scene.fogMode !== Scene.FOGMODE_NONE) {
1401
- defines.push("#define FOG");
274
+ // Animations
275
+ if (parsedParticleSystem.animations) {
276
+ for (let animationIndex = 0; animationIndex < parsedParticleSystem.animations.length; animationIndex++) {
277
+ const parsedAnimation = parsedParticleSystem.animations[animationIndex];
278
+ const internalClass = GetClass("BABYLON.Animation");
279
+ if (internalClass) {
280
+ particleSystem.animations.push(internalClass.Parse(parsedAnimation));
281
+ }
1402
282
  }
283
+ particleSystem.beginAnimationOnStart = parsedParticleSystem.beginAnimationOnStart;
284
+ particleSystem.beginAnimationFrom = parsedParticleSystem.beginAnimationFrom;
285
+ particleSystem.beginAnimationTo = parsedParticleSystem.beginAnimationTo;
286
+ particleSystem.beginAnimationLoop = parsedParticleSystem.beginAnimationLoop;
1403
287
  }
1404
- if (this._isAnimationSheetEnabled) {
1405
- defines.push("#define ANIMATESHEET");
1406
- }
1407
- if (this.useLogarithmicDepth) {
1408
- defines.push("#define LOGARITHMICDEPTH");
1409
- }
1410
- if (blendMode === ParticleSystem.BLENDMODE_MULTIPLY) {
1411
- defines.push("#define BLENDMULTIPLYMODE");
288
+ if (parsedParticleSystem.autoAnimate && scene) {
289
+ scene.beginAnimation(particleSystem, parsedParticleSystem.autoAnimateFrom, parsedParticleSystem.autoAnimateTo, parsedParticleSystem.autoAnimateLoop, parsedParticleSystem.autoAnimateSpeed || 1.0);
1412
290
  }
1413
- if (this._useRampGradients) {
1414
- defines.push("#define RAMPGRADIENT");
291
+ // Particle system
292
+ particleSystem.startDelay = parsedParticleSystem.startDelay | 0;
293
+ particleSystem.minAngularSpeed = parsedParticleSystem.minAngularSpeed;
294
+ particleSystem.maxAngularSpeed = parsedParticleSystem.maxAngularSpeed;
295
+ particleSystem.minSize = parsedParticleSystem.minSize;
296
+ particleSystem.maxSize = parsedParticleSystem.maxSize;
297
+ if (parsedParticleSystem.minScaleX) {
298
+ particleSystem.minScaleX = parsedParticleSystem.minScaleX;
299
+ particleSystem.maxScaleX = parsedParticleSystem.maxScaleX;
300
+ particleSystem.minScaleY = parsedParticleSystem.minScaleY;
301
+ particleSystem.maxScaleY = parsedParticleSystem.maxScaleY;
1415
302
  }
1416
- if (this._isBillboardBased) {
1417
- defines.push("#define BILLBOARD");
1418
- switch (this.billboardMode) {
1419
- case ParticleSystem.BILLBOARDMODE_Y:
1420
- defines.push("#define BILLBOARDY");
1421
- break;
1422
- case ParticleSystem.BILLBOARDMODE_STRETCHED:
1423
- case ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL:
1424
- defines.push("#define BILLBOARDSTRETCHED");
1425
- if (this.billboardMode === ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL) {
1426
- defines.push("#define BILLBOARDSTRETCHED_LOCAL");
1427
- }
1428
- break;
1429
- case ParticleSystem.BILLBOARDMODE_ALL:
1430
- defines.push("#define BILLBOARDMODE_ALL");
1431
- break;
1432
- default:
1433
- break;
1434
- }
303
+ if (parsedParticleSystem.preWarmCycles !== undefined) {
304
+ particleSystem.preWarmCycles = parsedParticleSystem.preWarmCycles;
305
+ particleSystem.preWarmStepOffset = parsedParticleSystem.preWarmStepOffset;
1435
306
  }
1436
- if (this._imageProcessingConfiguration) {
1437
- this._imageProcessingConfiguration.prepareDefines(this._imageProcessingConfigurationDefines);
1438
- defines.push(this._imageProcessingConfigurationDefines.toString());
307
+ if (parsedParticleSystem.minInitialRotation !== undefined) {
308
+ particleSystem.minInitialRotation = parsedParticleSystem.minInitialRotation;
309
+ particleSystem.maxInitialRotation = parsedParticleSystem.maxInitialRotation;
1439
310
  }
1440
- }
1441
- /**
1442
- * Fill the uniforms, attributes and samplers arrays according to the current settings of the particle system
1443
- * @param uniforms Uniforms array to fill
1444
- * @param attributes Attributes array to fill
1445
- * @param samplers Samplers array to fill
1446
- */
1447
- fillUniformsAttributesAndSamplerNames(uniforms, attributes, samplers) {
1448
- attributes.push(...ParticleSystem._GetAttributeNamesOrOptions(this._isAnimationSheetEnabled, this._isBillboardBased && this.billboardMode !== ParticleSystem.BILLBOARDMODE_STRETCHED && this.billboardMode !== ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL, this._useRampGradients));
1449
- uniforms.push(...ParticleSystem._GetEffectCreationOptions(this._isAnimationSheetEnabled, this.useLogarithmicDepth, this.applyFog));
1450
- samplers.push("diffuseSampler", "rampSampler");
1451
- if (this._imageProcessingConfiguration) {
1452
- ImageProcessingConfiguration.PrepareUniforms(uniforms, this._imageProcessingConfigurationDefines);
1453
- ImageProcessingConfiguration.PrepareSamplers(samplers, this._imageProcessingConfigurationDefines);
311
+ particleSystem.minLifeTime = parsedParticleSystem.minLifeTime;
312
+ particleSystem.maxLifeTime = parsedParticleSystem.maxLifeTime;
313
+ particleSystem.minEmitPower = parsedParticleSystem.minEmitPower;
314
+ particleSystem.maxEmitPower = parsedParticleSystem.maxEmitPower;
315
+ particleSystem.emitRate = parsedParticleSystem.emitRate;
316
+ particleSystem.gravity = Vector3.FromArray(parsedParticleSystem.gravity);
317
+ if (parsedParticleSystem.noiseStrength) {
318
+ particleSystem.noiseStrength = Vector3.FromArray(parsedParticleSystem.noiseStrength);
1454
319
  }
1455
- }
1456
- /**
1457
- * @internal
1458
- */
1459
- _getWrapper(blendMode) {
1460
- const customWrapper = this._getCustomDrawWrapper(blendMode);
1461
- if (customWrapper?.effect) {
1462
- return customWrapper;
1463
- }
1464
- const defines = [];
1465
- this.fillDefines(defines, blendMode);
1466
- // Effect
1467
- const currentRenderPassId = this._engine._features.supportRenderPasses ? this._engine.currentRenderPassId : 0;
1468
- let drawWrappers = this._drawWrappers[currentRenderPassId];
1469
- if (!drawWrappers) {
1470
- drawWrappers = this._drawWrappers[currentRenderPassId] = [];
1471
- }
1472
- let drawWrapper = drawWrappers[blendMode];
1473
- if (!drawWrapper) {
1474
- drawWrapper = new DrawWrapper(this._engine);
1475
- if (drawWrapper.drawContext) {
1476
- drawWrapper.drawContext.useInstancing = this._useInstancing;
320
+ particleSystem.color1 = Color4.FromArray(parsedParticleSystem.color1);
321
+ particleSystem.color2 = Color4.FromArray(parsedParticleSystem.color2);
322
+ particleSystem.colorDead = Color4.FromArray(parsedParticleSystem.colorDead);
323
+ particleSystem.updateSpeed = parsedParticleSystem.updateSpeed;
324
+ particleSystem.targetStopDuration = parsedParticleSystem.targetStopDuration;
325
+ particleSystem.blendMode = parsedParticleSystem.blendMode;
326
+ if (parsedParticleSystem.colorGradients) {
327
+ for (const colorGradient of parsedParticleSystem.colorGradients) {
328
+ particleSystem.addColorGradient(colorGradient.gradient, Color4.FromArray(colorGradient.color1), colorGradient.color2 ? Color4.FromArray(colorGradient.color2) : undefined);
1477
329
  }
1478
- drawWrappers[blendMode] = drawWrapper;
1479
- }
1480
- const join = defines.join("\n");
1481
- if (drawWrapper.defines !== join) {
1482
- const attributesNamesOrOptions = [];
1483
- const effectCreationOption = [];
1484
- const samplers = [];
1485
- this.fillUniformsAttributesAndSamplerNames(effectCreationOption, attributesNamesOrOptions, samplers);
1486
- drawWrapper.setEffect(this._engine.createEffect("particles", attributesNamesOrOptions, effectCreationOption, samplers, join), join);
1487
- }
1488
- return drawWrapper;
1489
- }
1490
- /**
1491
- * Animates the particle system for the current frame by emitting new particles and or animating the living ones.
1492
- * @param preWarmOnly will prevent the system from updating the vertex buffer (default is false)
1493
- */
1494
- animate(preWarmOnly = false) {
1495
- if (!this._started) {
1496
- return;
1497
330
  }
1498
- if (!preWarmOnly && this._scene) {
1499
- // Check
1500
- if (!this.isReady()) {
1501
- return;
1502
- }
1503
- if (this._currentRenderId === this._scene.getFrameId()) {
1504
- return;
331
+ if (parsedParticleSystem.rampGradients) {
332
+ for (const rampGradient of parsedParticleSystem.rampGradients) {
333
+ particleSystem.addRampGradient(rampGradient.gradient, Color3.FromArray(rampGradient.color));
1505
334
  }
1506
- this._currentRenderId = this._scene.getFrameId();
1507
- }
1508
- this._scaledUpdateSpeed = this.updateSpeed * (preWarmOnly ? this.preWarmStepOffset : this._scene?.getAnimationRatio() || 1);
1509
- // Determine the number of particles we need to create
1510
- let newParticles;
1511
- if (this.manualEmitCount > -1) {
1512
- newParticles = this.manualEmitCount;
1513
- this._newPartsExcess = 0;
1514
- this.manualEmitCount = 0;
335
+ particleSystem.useRampGradients = parsedParticleSystem.useRampGradients;
1515
336
  }
1516
- else {
1517
- let rate = this.emitRate;
1518
- if (this._emitRateGradients && this._emitRateGradients.length > 0 && this.targetStopDuration) {
1519
- const ratio = this._actualFrame / this.targetStopDuration;
1520
- GradientHelper.GetCurrentGradient(ratio, this._emitRateGradients, (currentGradient, nextGradient, scale) => {
1521
- if (currentGradient !== this._currentEmitRateGradient) {
1522
- this._currentEmitRate1 = this._currentEmitRate2;
1523
- this._currentEmitRate2 = nextGradient.getFactor();
1524
- this._currentEmitRateGradient = currentGradient;
1525
- }
1526
- rate = Scalar.Lerp(this._currentEmitRate1, this._currentEmitRate2, scale);
1527
- });
1528
- }
1529
- newParticles = (rate * this._scaledUpdateSpeed) >> 0;
1530
- this._newPartsExcess += rate * this._scaledUpdateSpeed - newParticles;
1531
- }
1532
- if (this._newPartsExcess > 1.0) {
1533
- newParticles += this._newPartsExcess >> 0;
1534
- this._newPartsExcess -= this._newPartsExcess >> 0;
1535
- }
1536
- this._alive = false;
1537
- if (!this._stopped) {
1538
- this._actualFrame += this._scaledUpdateSpeed;
1539
- if (this.targetStopDuration && this._actualFrame >= this.targetStopDuration) {
1540
- this.stop();
337
+ if (parsedParticleSystem.colorRemapGradients) {
338
+ for (const colorRemapGradient of parsedParticleSystem.colorRemapGradients) {
339
+ particleSystem.addColorRemapGradient(colorRemapGradient.gradient, colorRemapGradient.factor1 !== undefined ? colorRemapGradient.factor1 : colorRemapGradient.factor, colorRemapGradient.factor2);
1541
340
  }
1542
341
  }
1543
- else {
1544
- newParticles = 0;
1545
- }
1546
- this._update(newParticles);
1547
- // Stopped?
1548
- if (this._stopped) {
1549
- if (!this._alive) {
1550
- this._started = false;
1551
- if (this.onAnimationEnd) {
1552
- this.onAnimationEnd();
1553
- }
1554
- if (this.disposeOnStop && this._scene) {
1555
- this._scene._toBeDisposed.push(this);
1556
- }
342
+ if (parsedParticleSystem.alphaRemapGradients) {
343
+ for (const alphaRemapGradient of parsedParticleSystem.alphaRemapGradients) {
344
+ particleSystem.addAlphaRemapGradient(alphaRemapGradient.gradient, alphaRemapGradient.factor1 !== undefined ? alphaRemapGradient.factor1 : alphaRemapGradient.factor, alphaRemapGradient.factor2);
1557
345
  }
1558
346
  }
1559
- if (!preWarmOnly) {
1560
- // Update VBO
1561
- let offset = 0;
1562
- for (let index = 0; index < this._particles.length; index++) {
1563
- const particle = this._particles[index];
1564
- this._appendParticleVertices(offset, particle);
1565
- offset += this._useInstancing ? 1 : 4;
1566
- }
1567
- if (this._vertexBuffer) {
1568
- this._vertexBuffer.updateDirectly(this._vertexData, 0, this._particles.length);
347
+ if (parsedParticleSystem.sizeGradients) {
348
+ for (const sizeGradient of parsedParticleSystem.sizeGradients) {
349
+ particleSystem.addSizeGradient(sizeGradient.gradient, sizeGradient.factor1 !== undefined ? sizeGradient.factor1 : sizeGradient.factor, sizeGradient.factor2);
1569
350
  }
1570
351
  }
1571
- if (this.manualEmitCount === 0 && this.disposeOnStop) {
1572
- this.stop();
1573
- }
1574
- }
1575
- _appendParticleVertices(offset, particle) {
1576
- this._appendParticleVertex(offset++, particle, 0, 0);
1577
- if (!this._useInstancing) {
1578
- this._appendParticleVertex(offset++, particle, 1, 0);
1579
- this._appendParticleVertex(offset++, particle, 1, 1);
1580
- this._appendParticleVertex(offset++, particle, 0, 1);
1581
- }
1582
- }
1583
- /**
1584
- * Rebuilds the particle system.
1585
- */
1586
- rebuild() {
1587
- if (this._engine.getCaps().vertexArrayObject) {
1588
- this._vertexArrayObject = null;
1589
- }
1590
- this._createIndexBuffer();
1591
- this._spriteBuffer?._rebuild();
1592
- this._createVertexBuffers();
1593
- this.resetDrawCache();
1594
- }
1595
- /**
1596
- * Is this system ready to be used/rendered
1597
- * @returns true if the system is ready
1598
- */
1599
- isReady() {
1600
- if (!this.emitter || (this._imageProcessingConfiguration && !this._imageProcessingConfiguration.isReady()) || !this.particleTexture || !this.particleTexture.isReady()) {
1601
- return false;
1602
- }
1603
- if (this.blendMode !== ParticleSystem.BLENDMODE_MULTIPLYADD) {
1604
- if (!this._getWrapper(this.blendMode).effect.isReady()) {
1605
- return false;
352
+ if (parsedParticleSystem.angularSpeedGradients) {
353
+ for (const angularSpeedGradient of parsedParticleSystem.angularSpeedGradients) {
354
+ particleSystem.addAngularSpeedGradient(angularSpeedGradient.gradient, angularSpeedGradient.factor1 !== undefined ? angularSpeedGradient.factor1 : angularSpeedGradient.factor, angularSpeedGradient.factor2);
1606
355
  }
1607
356
  }
1608
- else {
1609
- if (!this._getWrapper(ParticleSystem.BLENDMODE_MULTIPLY).effect.isReady()) {
1610
- return false;
1611
- }
1612
- if (!this._getWrapper(ParticleSystem.BLENDMODE_ADD).effect.isReady()) {
1613
- return false;
357
+ if (parsedParticleSystem.velocityGradients) {
358
+ for (const velocityGradient of parsedParticleSystem.velocityGradients) {
359
+ particleSystem.addVelocityGradient(velocityGradient.gradient, velocityGradient.factor1 !== undefined ? velocityGradient.factor1 : velocityGradient.factor, velocityGradient.factor2);
1614
360
  }
1615
361
  }
1616
- return true;
1617
- }
1618
- _render(blendMode) {
1619
- const drawWrapper = this._getWrapper(blendMode);
1620
- const effect = drawWrapper.effect;
1621
- const engine = this._engine;
1622
- // Render
1623
- engine.enableEffect(drawWrapper);
1624
- const viewMatrix = this.defaultViewMatrix ?? this._scene.getViewMatrix();
1625
- effect.setTexture("diffuseSampler", this.particleTexture);
1626
- effect.setMatrix("view", viewMatrix);
1627
- effect.setMatrix("projection", this.defaultProjectionMatrix ?? this._scene.getProjectionMatrix());
1628
- if (this._isAnimationSheetEnabled && this.particleTexture) {
1629
- const baseSize = this.particleTexture.getBaseSize();
1630
- effect.setFloat3("particlesInfos", this.spriteCellWidth / baseSize.width, this.spriteCellHeight / baseSize.height, this.spriteCellWidth / baseSize.width);
1631
- }
1632
- effect.setVector2("translationPivot", this.translationPivot);
1633
- effect.setFloat4("textureMask", this.textureMask.r, this.textureMask.g, this.textureMask.b, this.textureMask.a);
1634
- if (this._isBillboardBased && this._scene) {
1635
- const camera = this._scene.activeCamera;
1636
- effect.setVector3("eyePosition", camera.globalPosition);
1637
- }
1638
- if (this._rampGradientsTexture) {
1639
- if (!this._rampGradients || !this._rampGradients.length) {
1640
- this._rampGradientsTexture.dispose();
1641
- this._rampGradientsTexture = null;
362
+ if (parsedParticleSystem.dragGradients) {
363
+ for (const dragGradient of parsedParticleSystem.dragGradients) {
364
+ particleSystem.addDragGradient(dragGradient.gradient, dragGradient.factor1 !== undefined ? dragGradient.factor1 : dragGradient.factor, dragGradient.factor2);
1642
365
  }
1643
- effect.setTexture("rampSampler", this._rampGradientsTexture);
1644
366
  }
1645
- const defines = effect.defines;
1646
- if (this._scene) {
1647
- bindClipPlane(effect, this, this._scene);
1648
- if (this.applyFog) {
1649
- BindFogParameters(this._scene, undefined, effect);
367
+ if (parsedParticleSystem.emitRateGradients) {
368
+ for (const emitRateGradient of parsedParticleSystem.emitRateGradients) {
369
+ particleSystem.addEmitRateGradient(emitRateGradient.gradient, emitRateGradient.factor1 !== undefined ? emitRateGradient.factor1 : emitRateGradient.factor, emitRateGradient.factor2);
1650
370
  }
1651
371
  }
1652
- if (defines.indexOf("#define BILLBOARDMODE_ALL") >= 0) {
1653
- viewMatrix.invertToRef(TmpVectors.Matrix[0]);
1654
- effect.setMatrix("invView", TmpVectors.Matrix[0]);
1655
- }
1656
- if (this._vertexArrayObject !== undefined) {
1657
- if (this._scene?.forceWireframe) {
1658
- engine.bindBuffers(this._vertexBuffers, this._linesIndexBufferUseInstancing, effect);
1659
- }
1660
- else {
1661
- if (!this._vertexArrayObject) {
1662
- this._vertexArrayObject = this._engine.recordVertexArrayObject(this._vertexBuffers, null, effect);
1663
- }
1664
- this._engine.bindVertexArrayObject(this._vertexArrayObject, this._scene?.forceWireframe ? this._linesIndexBufferUseInstancing : this._indexBuffer);
1665
- }
1666
- }
1667
- else {
1668
- if (!this._indexBuffer) {
1669
- // Use instancing mode
1670
- engine.bindBuffers(this._vertexBuffers, this._scene?.forceWireframe ? this._linesIndexBufferUseInstancing : null, effect);
1671
- }
1672
- else {
1673
- engine.bindBuffers(this._vertexBuffers, this._scene?.forceWireframe ? this._linesIndexBuffer : this._indexBuffer, effect);
372
+ if (parsedParticleSystem.startSizeGradients) {
373
+ for (const startSizeGradient of parsedParticleSystem.startSizeGradients) {
374
+ particleSystem.addStartSizeGradient(startSizeGradient.gradient, startSizeGradient.factor1 !== undefined ? startSizeGradient.factor1 : startSizeGradient.factor, startSizeGradient.factor2);
1674
375
  }
1675
376
  }
1676
- // Log. depth
1677
- if (this.useLogarithmicDepth && this._scene) {
1678
- BindLogDepth(defines, effect, this._scene);
1679
- }
1680
- // image processing
1681
- if (this._imageProcessingConfiguration && !this._imageProcessingConfiguration.applyByPostProcess) {
1682
- this._imageProcessingConfiguration.bind(effect);
1683
- }
1684
- // Draw order
1685
- switch (blendMode) {
1686
- case ParticleSystem.BLENDMODE_ADD:
1687
- engine.setAlphaMode(1);
1688
- break;
1689
- case ParticleSystem.BLENDMODE_ONEONE:
1690
- engine.setAlphaMode(6);
1691
- break;
1692
- case ParticleSystem.BLENDMODE_STANDARD:
1693
- engine.setAlphaMode(2);
1694
- break;
1695
- case ParticleSystem.BLENDMODE_MULTIPLY:
1696
- engine.setAlphaMode(4);
1697
- break;
1698
- }
1699
- if (this._onBeforeDrawParticlesObservable) {
1700
- this._onBeforeDrawParticlesObservable.notifyObservers(effect);
1701
- }
1702
- if (this._useInstancing) {
1703
- if (this._scene?.forceWireframe) {
1704
- engine.drawElementsType(6, 0, 10, this._particles.length);
1705
- }
1706
- else {
1707
- engine.drawArraysType(7, 0, 4, this._particles.length);
377
+ if (parsedParticleSystem.lifeTimeGradients) {
378
+ for (const lifeTimeGradient of parsedParticleSystem.lifeTimeGradients) {
379
+ particleSystem.addLifeTimeGradient(lifeTimeGradient.gradient, lifeTimeGradient.factor1 !== undefined ? lifeTimeGradient.factor1 : lifeTimeGradient.factor, lifeTimeGradient.factor2);
1708
380
  }
1709
381
  }
1710
- else {
1711
- if (this._scene?.forceWireframe) {
1712
- engine.drawElementsType(1, 0, this._particles.length * 10);
1713
- }
1714
- else {
1715
- engine.drawElementsType(0, 0, this._particles.length * 6);
382
+ if (parsedParticleSystem.limitVelocityGradients) {
383
+ for (const limitVelocityGradient of parsedParticleSystem.limitVelocityGradients) {
384
+ particleSystem.addLimitVelocityGradient(limitVelocityGradient.gradient, limitVelocityGradient.factor1 !== undefined ? limitVelocityGradient.factor1 : limitVelocityGradient.factor, limitVelocityGradient.factor2);
1716
385
  }
386
+ particleSystem.limitVelocityDamping = parsedParticleSystem.limitVelocityDamping;
1717
387
  }
1718
- return this._particles.length;
1719
- }
1720
- /**
1721
- * Renders the particle system in its current state.
1722
- * @returns the current number of particles
1723
- */
1724
- render() {
1725
- // Check
1726
- if (!this.isReady() || !this._particles.length) {
1727
- return 0;
388
+ if (parsedParticleSystem.noiseTexture && scene) {
389
+ const internalClass = GetClass("BABYLON.ProceduralTexture");
390
+ particleSystem.noiseTexture = internalClass.Parse(parsedParticleSystem.noiseTexture, scene, rootUrl);
1728
391
  }
1729
- const engine = this._engine;
1730
- if (engine.setState) {
1731
- engine.setState(false);
1732
- if (this.forceDepthWrite) {
1733
- engine.setDepthWrite(true);
392
+ // Emitter
393
+ let emitterType;
394
+ if (parsedParticleSystem.particleEmitterType) {
395
+ switch (parsedParticleSystem.particleEmitterType.type) {
396
+ case "SphereParticleEmitter":
397
+ emitterType = new SphereParticleEmitter();
398
+ break;
399
+ case "SphereDirectedParticleEmitter":
400
+ emitterType = new SphereDirectedParticleEmitter();
401
+ break;
402
+ case "ConeEmitter":
403
+ case "ConeParticleEmitter":
404
+ emitterType = new ConeParticleEmitter();
405
+ break;
406
+ case "CylinderParticleEmitter":
407
+ emitterType = new CylinderParticleEmitter();
408
+ break;
409
+ case "CylinderDirectedParticleEmitter":
410
+ emitterType = new CylinderDirectedParticleEmitter();
411
+ break;
412
+ case "HemisphericParticleEmitter":
413
+ emitterType = new HemisphericParticleEmitter();
414
+ break;
415
+ case "PointParticleEmitter":
416
+ emitterType = new PointParticleEmitter();
417
+ break;
418
+ case "MeshParticleEmitter":
419
+ emitterType = new MeshParticleEmitter();
420
+ break;
421
+ case "CustomParticleEmitter":
422
+ emitterType = new CustomParticleEmitter();
423
+ break;
424
+ case "BoxEmitter":
425
+ case "BoxParticleEmitter":
426
+ default:
427
+ emitterType = new BoxParticleEmitter();
428
+ break;
1734
429
  }
1735
- }
1736
- let outparticles = 0;
1737
- if (this.blendMode === ParticleSystem.BLENDMODE_MULTIPLYADD) {
1738
- outparticles = this._render(ParticleSystem.BLENDMODE_MULTIPLY) + this._render(ParticleSystem.BLENDMODE_ADD);
430
+ emitterType.parse(parsedParticleSystem.particleEmitterType, scene);
1739
431
  }
1740
432
  else {
1741
- outparticles = this._render(this.blendMode);
433
+ emitterType = new BoxParticleEmitter();
434
+ emitterType.parse(parsedParticleSystem, scene);
1742
435
  }
1743
- this._engine.unbindInstanceAttributes();
1744
- this._engine.setAlphaMode(0);
1745
- return outparticles;
436
+ particleSystem.particleEmitterType = emitterType;
437
+ // Animation sheet
438
+ particleSystem.startSpriteCellID = parsedParticleSystem.startSpriteCellID;
439
+ particleSystem.endSpriteCellID = parsedParticleSystem.endSpriteCellID;
440
+ particleSystem.spriteCellLoop = parsedParticleSystem.spriteCellLoop ?? true;
441
+ particleSystem.spriteCellWidth = parsedParticleSystem.spriteCellWidth;
442
+ particleSystem.spriteCellHeight = parsedParticleSystem.spriteCellHeight;
443
+ particleSystem.spriteCellChangeSpeed = parsedParticleSystem.spriteCellChangeSpeed;
444
+ particleSystem.spriteRandomStartCell = parsedParticleSystem.spriteRandomStartCell;
445
+ particleSystem.disposeOnStop = parsedParticleSystem.disposeOnStop ?? false;
446
+ particleSystem.manualEmitCount = parsedParticleSystem.manualEmitCount ?? -1;
1746
447
  }
1747
448
  /**
1748
- * Disposes the particle system and free the associated resources
1749
- * @param disposeTexture defines if the particle texture must be disposed as well (true by default)
449
+ * Parses a JSON object to create a particle system.
450
+ * @param parsedParticleSystem The JSON object to parse
451
+ * @param sceneOrEngine The scene or the engine to create the particle system in
452
+ * @param rootUrl The root url to use to load external dependencies like texture
453
+ * @param doNotStart Ignore the preventAutoStart attribute and does not start
454
+ * @param capacity defines the system capacity (if null or undefined the sotred capacity will be used)
455
+ * @returns the Parsed particle system
1750
456
  */
1751
- dispose(disposeTexture = true) {
1752
- this.resetDrawCache();
1753
- if (this._vertexBuffer) {
1754
- this._vertexBuffer.dispose();
1755
- this._vertexBuffer = null;
1756
- }
1757
- if (this._spriteBuffer) {
1758
- this._spriteBuffer.dispose();
1759
- this._spriteBuffer = null;
1760
- }
1761
- if (this._indexBuffer) {
1762
- this._engine._releaseBuffer(this._indexBuffer);
1763
- this._indexBuffer = null;
1764
- }
1765
- if (this._linesIndexBuffer) {
1766
- this._engine._releaseBuffer(this._linesIndexBuffer);
1767
- this._linesIndexBuffer = null;
1768
- }
1769
- if (this._linesIndexBufferUseInstancing) {
1770
- this._engine._releaseBuffer(this._linesIndexBufferUseInstancing);
1771
- this._linesIndexBufferUseInstancing = null;
1772
- }
1773
- if (this._vertexArrayObject) {
1774
- this._engine.releaseVertexArrayObject(this._vertexArrayObject);
1775
- this._vertexArrayObject = null;
1776
- }
1777
- if (disposeTexture && this.particleTexture) {
1778
- this.particleTexture.dispose();
1779
- this.particleTexture = null;
457
+ static Parse(parsedParticleSystem, sceneOrEngine, rootUrl, doNotStart = false, capacity) {
458
+ const name = parsedParticleSystem.name;
459
+ let custom = null;
460
+ let program = null;
461
+ let engine;
462
+ let scene;
463
+ if (sceneOrEngine instanceof ThinEngine) {
464
+ engine = sceneOrEngine;
1780
465
  }
1781
- if (disposeTexture && this.noiseTexture) {
1782
- this.noiseTexture.dispose();
1783
- this.noiseTexture = null;
466
+ else {
467
+ scene = sceneOrEngine;
468
+ engine = scene.getEngine();
1784
469
  }
1785
- if (this._rampGradientsTexture) {
1786
- this._rampGradientsTexture.dispose();
1787
- this._rampGradientsTexture = null;
470
+ if (parsedParticleSystem.customShader && engine.createEffectForParticles) {
471
+ program = parsedParticleSystem.customShader;
472
+ const defines = program.shaderOptions.defines.length > 0 ? program.shaderOptions.defines.join("\n") : "";
473
+ custom = engine.createEffectForParticles(program.shaderPath.fragmentElement, program.shaderOptions.uniforms, program.shaderOptions.samplers, defines);
1788
474
  }
1789
- this._removeFromRoot();
1790
- if (this.subEmitters && !this._subEmitters) {
1791
- this._prepareSubEmitterInternalArray();
475
+ const particleSystem = new ParticleSystem(name, capacity || parsedParticleSystem.capacity, sceneOrEngine, custom, parsedParticleSystem.isAnimationSheetEnabled);
476
+ particleSystem.customShader = program;
477
+ particleSystem._rootUrl = rootUrl;
478
+ if (parsedParticleSystem.id) {
479
+ particleSystem.id = parsedParticleSystem.id;
1792
480
  }
1793
- if (this._subEmitters && this._subEmitters.length) {
1794
- for (let index = 0; index < this._subEmitters.length; index++) {
1795
- for (const subEmitter of this._subEmitters[index]) {
1796
- subEmitter.dispose();
481
+ // SubEmitters
482
+ if (parsedParticleSystem.subEmitters) {
483
+ particleSystem.subEmitters = [];
484
+ for (const cell of parsedParticleSystem.subEmitters) {
485
+ const cellArray = [];
486
+ for (const sub of cell) {
487
+ cellArray.push(SubEmitter.Parse(sub, sceneOrEngine, rootUrl));
1797
488
  }
489
+ particleSystem.subEmitters.push(cellArray);
1798
490
  }
1799
- this._subEmitters = [];
1800
- this.subEmitters = [];
1801
- }
1802
- if (this._disposeEmitterOnDispose && this.emitter && this.emitter.dispose) {
1803
- this.emitter.dispose(true);
1804
- }
1805
- if (this._onBeforeDrawParticlesObservable) {
1806
- this._onBeforeDrawParticlesObservable.clear();
1807
- }
1808
- // Remove from scene
1809
- if (this._scene) {
1810
- const index = this._scene.particleSystems.indexOf(this);
1811
- if (index > -1) {
1812
- this._scene.particleSystems.splice(index, 1);
1813
- }
1814
- this._scene._activeParticleSystems.dispose();
1815
491
  }
1816
- // Callback
1817
- this.onDisposeObservable.notifyObservers(this);
1818
- this.onDisposeObservable.clear();
1819
- this.onStoppedObservable.clear();
1820
- this.reset();
1821
- }
1822
- // Clone
1823
- /**
1824
- * Clones the particle system.
1825
- * @param name The name of the cloned object
1826
- * @param newEmitter The new emitter to use
1827
- * @param cloneTexture Also clone the textures if true
1828
- * @returns the cloned particle system
1829
- */
1830
- clone(name, newEmitter, cloneTexture = false) {
1831
- const custom = { ...this._customWrappers };
1832
- let program = null;
1833
- const engine = this._engine;
1834
- if (engine.createEffectForParticles) {
1835
- if (this.customShader != null) {
1836
- program = this.customShader;
1837
- const defines = program.shaderOptions.defines.length > 0 ? program.shaderOptions.defines.join("\n") : "";
1838
- const effect = engine.createEffectForParticles(program.shaderPath.fragmentElement, program.shaderOptions.uniforms, program.shaderOptions.samplers, defines);
1839
- if (!custom[0]) {
1840
- this.setCustomEffect(effect, 0);
1841
- }
1842
- else {
1843
- custom[0].effect = effect;
1844
- }
1845
- }
492
+ ParticleSystem._Parse(parsedParticleSystem, particleSystem, sceneOrEngine, rootUrl);
493
+ if (parsedParticleSystem.textureMask) {
494
+ particleSystem.textureMask = Color4.FromArray(parsedParticleSystem.textureMask);
1846
495
  }
1847
- const serialization = this.serialize(cloneTexture);
1848
- const result = ParticleSystem.Parse(serialization, this._scene || this._engine, this._rootUrl);
1849
- result.name = name;
1850
- result.customShader = program;
1851
- result._customWrappers = custom;
1852
- if (newEmitter === undefined) {
1853
- newEmitter = this.emitter;
496
+ if (parsedParticleSystem.worldOffset) {
497
+ particleSystem.worldOffset = Vector3.FromArray(parsedParticleSystem.worldOffset);
1854
498
  }
1855
- if (this.noiseTexture) {
1856
- result.noiseTexture = this.noiseTexture.clone();
499
+ // Auto start
500
+ if (parsedParticleSystem.preventAutoStart) {
501
+ particleSystem.preventAutoStart = parsedParticleSystem.preventAutoStart;
1857
502
  }
1858
- result.emitter = newEmitter;
1859
- if (!this.preventAutoStart) {
1860
- result.start();
503
+ if (!doNotStart && !particleSystem.preventAutoStart) {
504
+ particleSystem.start();
1861
505
  }
1862
- return result;
506
+ return particleSystem;
1863
507
  }
1864
508
  /**
1865
509
  * Serializes the particle system to a JSON object
@@ -2170,285 +814,47 @@ export class ParticleSystem extends BaseParticleSystem {
2170
814
  serializationObject.noiseTexture = particleSystem.noiseTexture.serialize();
2171
815
  }
2172
816
  }
817
+ // Clone
2173
818
  /**
2174
- * @internal
2175
- */
2176
- static _Parse(parsedParticleSystem, particleSystem, sceneOrEngine, rootUrl) {
2177
- let scene;
2178
- if (sceneOrEngine instanceof ThinEngine) {
2179
- scene = null;
2180
- }
2181
- else {
2182
- scene = sceneOrEngine;
2183
- }
2184
- const internalClass = GetClass("BABYLON.Texture");
2185
- if (internalClass && scene) {
2186
- // Texture
2187
- if (parsedParticleSystem.texture) {
2188
- particleSystem.particleTexture = internalClass.Parse(parsedParticleSystem.texture, scene, rootUrl);
2189
- }
2190
- else if (parsedParticleSystem.textureName) {
2191
- particleSystem.particleTexture = new internalClass(rootUrl + parsedParticleSystem.textureName, scene, false, parsedParticleSystem.invertY !== undefined ? parsedParticleSystem.invertY : true);
2192
- particleSystem.particleTexture.name = parsedParticleSystem.textureName;
2193
- }
2194
- }
2195
- // Emitter
2196
- if (!parsedParticleSystem.emitterId && parsedParticleSystem.emitterId !== 0 && parsedParticleSystem.emitter === undefined) {
2197
- particleSystem.emitter = Vector3.Zero();
2198
- }
2199
- else if (parsedParticleSystem.emitterId && scene) {
2200
- particleSystem.emitter = scene.getLastMeshById(parsedParticleSystem.emitterId);
2201
- }
2202
- else {
2203
- particleSystem.emitter = Vector3.FromArray(parsedParticleSystem.emitter);
2204
- }
2205
- particleSystem.isLocal = !!parsedParticleSystem.isLocal;
2206
- // Misc.
2207
- if (parsedParticleSystem.renderingGroupId !== undefined) {
2208
- particleSystem.renderingGroupId = parsedParticleSystem.renderingGroupId;
2209
- }
2210
- if (parsedParticleSystem.isBillboardBased !== undefined) {
2211
- particleSystem.isBillboardBased = parsedParticleSystem.isBillboardBased;
2212
- }
2213
- if (parsedParticleSystem.billboardMode !== undefined) {
2214
- particleSystem.billboardMode = parsedParticleSystem.billboardMode;
2215
- }
2216
- if (parsedParticleSystem.useLogarithmicDepth !== undefined) {
2217
- particleSystem.useLogarithmicDepth = parsedParticleSystem.useLogarithmicDepth;
2218
- }
2219
- // Animations
2220
- if (parsedParticleSystem.animations) {
2221
- for (let animationIndex = 0; animationIndex < parsedParticleSystem.animations.length; animationIndex++) {
2222
- const parsedAnimation = parsedParticleSystem.animations[animationIndex];
2223
- const internalClass = GetClass("BABYLON.Animation");
2224
- if (internalClass) {
2225
- particleSystem.animations.push(internalClass.Parse(parsedAnimation));
2226
- }
2227
- }
2228
- particleSystem.beginAnimationOnStart = parsedParticleSystem.beginAnimationOnStart;
2229
- particleSystem.beginAnimationFrom = parsedParticleSystem.beginAnimationFrom;
2230
- particleSystem.beginAnimationTo = parsedParticleSystem.beginAnimationTo;
2231
- particleSystem.beginAnimationLoop = parsedParticleSystem.beginAnimationLoop;
2232
- }
2233
- if (parsedParticleSystem.autoAnimate && scene) {
2234
- scene.beginAnimation(particleSystem, parsedParticleSystem.autoAnimateFrom, parsedParticleSystem.autoAnimateTo, parsedParticleSystem.autoAnimateLoop, parsedParticleSystem.autoAnimateSpeed || 1.0);
2235
- }
2236
- // Particle system
2237
- particleSystem.startDelay = parsedParticleSystem.startDelay | 0;
2238
- particleSystem.minAngularSpeed = parsedParticleSystem.minAngularSpeed;
2239
- particleSystem.maxAngularSpeed = parsedParticleSystem.maxAngularSpeed;
2240
- particleSystem.minSize = parsedParticleSystem.minSize;
2241
- particleSystem.maxSize = parsedParticleSystem.maxSize;
2242
- if (parsedParticleSystem.minScaleX) {
2243
- particleSystem.minScaleX = parsedParticleSystem.minScaleX;
2244
- particleSystem.maxScaleX = parsedParticleSystem.maxScaleX;
2245
- particleSystem.minScaleY = parsedParticleSystem.minScaleY;
2246
- particleSystem.maxScaleY = parsedParticleSystem.maxScaleY;
2247
- }
2248
- if (parsedParticleSystem.preWarmCycles !== undefined) {
2249
- particleSystem.preWarmCycles = parsedParticleSystem.preWarmCycles;
2250
- particleSystem.preWarmStepOffset = parsedParticleSystem.preWarmStepOffset;
2251
- }
2252
- if (parsedParticleSystem.minInitialRotation !== undefined) {
2253
- particleSystem.minInitialRotation = parsedParticleSystem.minInitialRotation;
2254
- particleSystem.maxInitialRotation = parsedParticleSystem.maxInitialRotation;
2255
- }
2256
- particleSystem.minLifeTime = parsedParticleSystem.minLifeTime;
2257
- particleSystem.maxLifeTime = parsedParticleSystem.maxLifeTime;
2258
- particleSystem.minEmitPower = parsedParticleSystem.minEmitPower;
2259
- particleSystem.maxEmitPower = parsedParticleSystem.maxEmitPower;
2260
- particleSystem.emitRate = parsedParticleSystem.emitRate;
2261
- particleSystem.gravity = Vector3.FromArray(parsedParticleSystem.gravity);
2262
- if (parsedParticleSystem.noiseStrength) {
2263
- particleSystem.noiseStrength = Vector3.FromArray(parsedParticleSystem.noiseStrength);
2264
- }
2265
- particleSystem.color1 = Color4.FromArray(parsedParticleSystem.color1);
2266
- particleSystem.color2 = Color4.FromArray(parsedParticleSystem.color2);
2267
- particleSystem.colorDead = Color4.FromArray(parsedParticleSystem.colorDead);
2268
- particleSystem.updateSpeed = parsedParticleSystem.updateSpeed;
2269
- particleSystem.targetStopDuration = parsedParticleSystem.targetStopDuration;
2270
- particleSystem.blendMode = parsedParticleSystem.blendMode;
2271
- if (parsedParticleSystem.colorGradients) {
2272
- for (const colorGradient of parsedParticleSystem.colorGradients) {
2273
- particleSystem.addColorGradient(colorGradient.gradient, Color4.FromArray(colorGradient.color1), colorGradient.color2 ? Color4.FromArray(colorGradient.color2) : undefined);
2274
- }
2275
- }
2276
- if (parsedParticleSystem.rampGradients) {
2277
- for (const rampGradient of parsedParticleSystem.rampGradients) {
2278
- particleSystem.addRampGradient(rampGradient.gradient, Color3.FromArray(rampGradient.color));
2279
- }
2280
- particleSystem.useRampGradients = parsedParticleSystem.useRampGradients;
2281
- }
2282
- if (parsedParticleSystem.colorRemapGradients) {
2283
- for (const colorRemapGradient of parsedParticleSystem.colorRemapGradients) {
2284
- particleSystem.addColorRemapGradient(colorRemapGradient.gradient, colorRemapGradient.factor1 !== undefined ? colorRemapGradient.factor1 : colorRemapGradient.factor, colorRemapGradient.factor2);
2285
- }
2286
- }
2287
- if (parsedParticleSystem.alphaRemapGradients) {
2288
- for (const alphaRemapGradient of parsedParticleSystem.alphaRemapGradients) {
2289
- particleSystem.addAlphaRemapGradient(alphaRemapGradient.gradient, alphaRemapGradient.factor1 !== undefined ? alphaRemapGradient.factor1 : alphaRemapGradient.factor, alphaRemapGradient.factor2);
2290
- }
2291
- }
2292
- if (parsedParticleSystem.sizeGradients) {
2293
- for (const sizeGradient of parsedParticleSystem.sizeGradients) {
2294
- particleSystem.addSizeGradient(sizeGradient.gradient, sizeGradient.factor1 !== undefined ? sizeGradient.factor1 : sizeGradient.factor, sizeGradient.factor2);
2295
- }
2296
- }
2297
- if (parsedParticleSystem.angularSpeedGradients) {
2298
- for (const angularSpeedGradient of parsedParticleSystem.angularSpeedGradients) {
2299
- particleSystem.addAngularSpeedGradient(angularSpeedGradient.gradient, angularSpeedGradient.factor1 !== undefined ? angularSpeedGradient.factor1 : angularSpeedGradient.factor, angularSpeedGradient.factor2);
2300
- }
2301
- }
2302
- if (parsedParticleSystem.velocityGradients) {
2303
- for (const velocityGradient of parsedParticleSystem.velocityGradients) {
2304
- particleSystem.addVelocityGradient(velocityGradient.gradient, velocityGradient.factor1 !== undefined ? velocityGradient.factor1 : velocityGradient.factor, velocityGradient.factor2);
2305
- }
2306
- }
2307
- if (parsedParticleSystem.dragGradients) {
2308
- for (const dragGradient of parsedParticleSystem.dragGradients) {
2309
- particleSystem.addDragGradient(dragGradient.gradient, dragGradient.factor1 !== undefined ? dragGradient.factor1 : dragGradient.factor, dragGradient.factor2);
2310
- }
2311
- }
2312
- if (parsedParticleSystem.emitRateGradients) {
2313
- for (const emitRateGradient of parsedParticleSystem.emitRateGradients) {
2314
- particleSystem.addEmitRateGradient(emitRateGradient.gradient, emitRateGradient.factor1 !== undefined ? emitRateGradient.factor1 : emitRateGradient.factor, emitRateGradient.factor2);
2315
- }
2316
- }
2317
- if (parsedParticleSystem.startSizeGradients) {
2318
- for (const startSizeGradient of parsedParticleSystem.startSizeGradients) {
2319
- particleSystem.addStartSizeGradient(startSizeGradient.gradient, startSizeGradient.factor1 !== undefined ? startSizeGradient.factor1 : startSizeGradient.factor, startSizeGradient.factor2);
2320
- }
2321
- }
2322
- if (parsedParticleSystem.lifeTimeGradients) {
2323
- for (const lifeTimeGradient of parsedParticleSystem.lifeTimeGradients) {
2324
- particleSystem.addLifeTimeGradient(lifeTimeGradient.gradient, lifeTimeGradient.factor1 !== undefined ? lifeTimeGradient.factor1 : lifeTimeGradient.factor, lifeTimeGradient.factor2);
2325
- }
2326
- }
2327
- if (parsedParticleSystem.limitVelocityGradients) {
2328
- for (const limitVelocityGradient of parsedParticleSystem.limitVelocityGradients) {
2329
- particleSystem.addLimitVelocityGradient(limitVelocityGradient.gradient, limitVelocityGradient.factor1 !== undefined ? limitVelocityGradient.factor1 : limitVelocityGradient.factor, limitVelocityGradient.factor2);
2330
- }
2331
- particleSystem.limitVelocityDamping = parsedParticleSystem.limitVelocityDamping;
2332
- }
2333
- if (parsedParticleSystem.noiseTexture && scene) {
2334
- const internalClass = GetClass("BABYLON.ProceduralTexture");
2335
- particleSystem.noiseTexture = internalClass.Parse(parsedParticleSystem.noiseTexture, scene, rootUrl);
2336
- }
2337
- // Emitter
2338
- let emitterType;
2339
- if (parsedParticleSystem.particleEmitterType) {
2340
- switch (parsedParticleSystem.particleEmitterType.type) {
2341
- case "SphereParticleEmitter":
2342
- emitterType = new SphereParticleEmitter();
2343
- break;
2344
- case "SphereDirectedParticleEmitter":
2345
- emitterType = new SphereDirectedParticleEmitter();
2346
- break;
2347
- case "ConeEmitter":
2348
- case "ConeParticleEmitter":
2349
- emitterType = new ConeParticleEmitter();
2350
- break;
2351
- case "CylinderParticleEmitter":
2352
- emitterType = new CylinderParticleEmitter();
2353
- break;
2354
- case "CylinderDirectedParticleEmitter":
2355
- emitterType = new CylinderDirectedParticleEmitter();
2356
- break;
2357
- case "HemisphericParticleEmitter":
2358
- emitterType = new HemisphericParticleEmitter();
2359
- break;
2360
- case "PointParticleEmitter":
2361
- emitterType = new PointParticleEmitter();
2362
- break;
2363
- case "MeshParticleEmitter":
2364
- emitterType = new MeshParticleEmitter();
2365
- break;
2366
- case "CustomParticleEmitter":
2367
- emitterType = new CustomParticleEmitter();
2368
- break;
2369
- case "BoxEmitter":
2370
- case "BoxParticleEmitter":
2371
- default:
2372
- emitterType = new BoxParticleEmitter();
2373
- break;
2374
- }
2375
- emitterType.parse(parsedParticleSystem.particleEmitterType, scene);
2376
- }
2377
- else {
2378
- emitterType = new BoxParticleEmitter();
2379
- emitterType.parse(parsedParticleSystem, scene);
2380
- }
2381
- particleSystem.particleEmitterType = emitterType;
2382
- // Animation sheet
2383
- particleSystem.startSpriteCellID = parsedParticleSystem.startSpriteCellID;
2384
- particleSystem.endSpriteCellID = parsedParticleSystem.endSpriteCellID;
2385
- particleSystem.spriteCellLoop = parsedParticleSystem.spriteCellLoop ?? true;
2386
- particleSystem.spriteCellWidth = parsedParticleSystem.spriteCellWidth;
2387
- particleSystem.spriteCellHeight = parsedParticleSystem.spriteCellHeight;
2388
- particleSystem.spriteCellChangeSpeed = parsedParticleSystem.spriteCellChangeSpeed;
2389
- particleSystem.spriteRandomStartCell = parsedParticleSystem.spriteRandomStartCell;
2390
- particleSystem.disposeOnStop = parsedParticleSystem.disposeOnStop ?? false;
2391
- particleSystem.manualEmitCount = parsedParticleSystem.manualEmitCount ?? -1;
2392
- }
2393
- /**
2394
- * Parses a JSON object to create a particle system.
2395
- * @param parsedParticleSystem The JSON object to parse
2396
- * @param sceneOrEngine The scene or the engine to create the particle system in
2397
- * @param rootUrl The root url to use to load external dependencies like texture
2398
- * @param doNotStart Ignore the preventAutoStart attribute and does not start
2399
- * @param capacity defines the system capacity (if null or undefined the sotred capacity will be used)
2400
- * @returns the Parsed particle system
819
+ * Clones the particle system.
820
+ * @param name The name of the cloned object
821
+ * @param newEmitter The new emitter to use
822
+ * @param cloneTexture Also clone the textures if true
823
+ * @returns the cloned particle system
2401
824
  */
2402
- static Parse(parsedParticleSystem, sceneOrEngine, rootUrl, doNotStart = false, capacity) {
2403
- const name = parsedParticleSystem.name;
2404
- let custom = null;
825
+ clone(name, newEmitter, cloneTexture = false) {
826
+ const custom = { ...this._customWrappers };
2405
827
  let program = null;
2406
- let engine;
2407
- let scene;
2408
- if (sceneOrEngine instanceof ThinEngine) {
2409
- engine = sceneOrEngine;
2410
- }
2411
- else {
2412
- scene = sceneOrEngine;
2413
- engine = scene.getEngine();
2414
- }
2415
- if (parsedParticleSystem.customShader && engine.createEffectForParticles) {
2416
- program = parsedParticleSystem.customShader;
2417
- const defines = program.shaderOptions.defines.length > 0 ? program.shaderOptions.defines.join("\n") : "";
2418
- custom = engine.createEffectForParticles(program.shaderPath.fragmentElement, program.shaderOptions.uniforms, program.shaderOptions.samplers, defines);
2419
- }
2420
- const particleSystem = new ParticleSystem(name, capacity || parsedParticleSystem.capacity, sceneOrEngine, custom, parsedParticleSystem.isAnimationSheetEnabled);
2421
- particleSystem.customShader = program;
2422
- particleSystem._rootUrl = rootUrl;
2423
- if (parsedParticleSystem.id) {
2424
- particleSystem.id = parsedParticleSystem.id;
2425
- }
2426
- // SubEmitters
2427
- if (parsedParticleSystem.subEmitters) {
2428
- particleSystem.subEmitters = [];
2429
- for (const cell of parsedParticleSystem.subEmitters) {
2430
- const cellArray = [];
2431
- for (const sub of cell) {
2432
- cellArray.push(SubEmitter.Parse(sub, sceneOrEngine, rootUrl));
828
+ const engine = this._engine;
829
+ if (engine.createEffectForParticles) {
830
+ if (this.customShader != null) {
831
+ program = this.customShader;
832
+ const defines = program.shaderOptions.defines.length > 0 ? program.shaderOptions.defines.join("\n") : "";
833
+ const effect = engine.createEffectForParticles(program.shaderPath.fragmentElement, program.shaderOptions.uniforms, program.shaderOptions.samplers, defines);
834
+ if (!custom[0]) {
835
+ this.setCustomEffect(effect, 0);
836
+ }
837
+ else {
838
+ custom[0].effect = effect;
2433
839
  }
2434
- particleSystem.subEmitters.push(cellArray);
2435
840
  }
2436
841
  }
2437
- ParticleSystem._Parse(parsedParticleSystem, particleSystem, sceneOrEngine, rootUrl);
2438
- if (parsedParticleSystem.textureMask) {
2439
- particleSystem.textureMask = Color4.FromArray(parsedParticleSystem.textureMask);
2440
- }
2441
- if (parsedParticleSystem.worldOffset) {
2442
- particleSystem.worldOffset = Vector3.FromArray(parsedParticleSystem.worldOffset);
842
+ const serialization = this.serialize(cloneTexture);
843
+ const result = ParticleSystem.Parse(serialization, this._scene || this._engine, this._rootUrl);
844
+ result.name = name;
845
+ result.customShader = program;
846
+ result._customWrappers = custom;
847
+ if (newEmitter === undefined) {
848
+ newEmitter = this.emitter;
2443
849
  }
2444
- // Auto start
2445
- if (parsedParticleSystem.preventAutoStart) {
2446
- particleSystem.preventAutoStart = parsedParticleSystem.preventAutoStart;
850
+ if (this.noiseTexture) {
851
+ result.noiseTexture = this.noiseTexture.clone();
2447
852
  }
2448
- if (!doNotStart && !particleSystem.preventAutoStart) {
2449
- particleSystem.start();
853
+ result.emitter = newEmitter;
854
+ if (!this.preventAutoStart) {
855
+ result.start();
2450
856
  }
2451
- return particleSystem;
857
+ return result;
2452
858
  }
2453
859
  }
2454
860
  /**