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