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