123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893 |
- import { ThinParticleSystem } from "./thinParticleSystem.js";
- import { SubEmitter, SubEmitterType } from "./subEmitter.js";
- import { Color3, Color4 } from "../Maths/math.color.js";
- import { Vector3 } from "../Maths/math.vector.js";
- import { AbstractEngine } from "../Engines/abstractEngine.js";
- import { GetClass } from "../Misc/typeStore.js";
- import { SerializationHelper } from "../Misc/decorators.serialization.js";
- import { MeshParticleEmitter } from "./EmitterTypes/meshParticleEmitter.js";
- import { CustomParticleEmitter } from "./EmitterTypes/customParticleEmitter.js";
- import { BoxParticleEmitter } from "./EmitterTypes/boxParticleEmitter.js";
- import { PointParticleEmitter } from "./EmitterTypes/pointParticleEmitter.js";
- import { HemisphericParticleEmitter } from "./EmitterTypes/hemisphericParticleEmitter.js";
- import { SphereDirectedParticleEmitter, SphereParticleEmitter } from "./EmitterTypes/sphereParticleEmitter.js";
- import { CylinderDirectedParticleEmitter, CylinderParticleEmitter } from "./EmitterTypes/cylinderParticleEmitter.js";
- import { ConeParticleEmitter } from "./EmitterTypes/coneParticleEmitter.js";
- import { CreateConeEmitter, CreateCylinderEmitter, CreateDirectedCylinderEmitter, CreateDirectedSphereEmitter, CreateHemisphericEmitter, CreatePointEmitter, CreateSphereEmitter, } from "./particleSystem.functions.js";
- /**
- * This represents a particle system in Babylon.
- * 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.
- * Particles can take different shapes while emitted like box, sphere, cone or you can write your custom function.
- * @example https://doc.babylonjs.com/features/featuresDeepDive/particles/particle_system/particle_system_intro
- */
- export class ParticleSystem extends ThinParticleSystem {
- constructor() {
- super(...arguments);
- /**
- * @internal
- * If the particle systems emitter should be disposed when the particle system is disposed
- */
- this._disposeEmitterOnDispose = false;
- this._emitFromParticle = (particle) => {
- if (!this._subEmitters || this._subEmitters.length === 0) {
- return;
- }
- const templateIndex = Math.floor(Math.random() * this._subEmitters.length);
- this._subEmitters[templateIndex].forEach((subEmitter) => {
- if (subEmitter.type === SubEmitterType.END) {
- const subSystem = subEmitter.clone();
- particle._inheritParticleInfoToSubEmitter(subSystem);
- subSystem.particleSystem._rootParticleSystem = this;
- this.activeSubSystems.push(subSystem.particleSystem);
- subSystem.particleSystem.start();
- }
- });
- };
- }
- /**
- * Creates a Point Emitter for the particle system (emits directly from the emitter position)
- * @param direction1 Particles are emitted between the direction1 and direction2 from within the box
- * @param direction2 Particles are emitted between the direction1 and direction2 from within the box
- * @returns the emitter
- */
- createPointEmitter(direction1, direction2) {
- const particleEmitter = CreatePointEmitter(direction1, direction2);
- this.particleEmitterType = particleEmitter;
- return particleEmitter;
- }
- /**
- * Creates a Hemisphere Emitter for the particle system (emits along the hemisphere radius)
- * @param radius The radius of the hemisphere to emit from
- * @param radiusRange The range of the hemisphere to emit from [0-1] 0 Surface Only, 1 Entire Radius
- * @returns the emitter
- */
- createHemisphericEmitter(radius = 1, radiusRange = 1) {
- const particleEmitter = CreateHemisphericEmitter(radius, radiusRange);
- this.particleEmitterType = particleEmitter;
- return particleEmitter;
- }
- /**
- * Creates a Sphere Emitter for the particle system (emits along the sphere radius)
- * @param radius The radius of the sphere to emit from
- * @param radiusRange The range of the sphere to emit from [0-1] 0 Surface Only, 1 Entire Radius
- * @returns the emitter
- */
- createSphereEmitter(radius = 1, radiusRange = 1) {
- const particleEmitter = CreateSphereEmitter(radius, radiusRange);
- this.particleEmitterType = particleEmitter;
- return particleEmitter;
- }
- /**
- * Creates a Directed Sphere Emitter for the particle system (emits between direction1 and direction2)
- * @param radius The radius of the sphere to emit from
- * @param direction1 Particles are emitted between the direction1 and direction2 from within the sphere
- * @param direction2 Particles are emitted between the direction1 and direction2 from within the sphere
- * @returns the emitter
- */
- createDirectedSphereEmitter(radius = 1, direction1 = new Vector3(0, 1.0, 0), direction2 = new Vector3(0, 1.0, 0)) {
- const particleEmitter = CreateDirectedSphereEmitter(radius, direction1, direction2);
- this.particleEmitterType = particleEmitter;
- return particleEmitter;
- }
- /**
- * Creates a Cylinder Emitter for the particle system (emits from the cylinder to the particle position)
- * @param radius The radius of the emission cylinder
- * @param height The height of the emission cylinder
- * @param radiusRange The range of emission [0-1] 0 Surface only, 1 Entire Radius
- * @param directionRandomizer How much to randomize the particle direction [0-1]
- * @returns the emitter
- */
- createCylinderEmitter(radius = 1, height = 1, radiusRange = 1, directionRandomizer = 0) {
- const particleEmitter = CreateCylinderEmitter(radius, height, radiusRange, directionRandomizer);
- this.particleEmitterType = particleEmitter;
- return particleEmitter;
- }
- /**
- * Creates a Directed Cylinder Emitter for the particle system (emits between direction1 and direction2)
- * @param radius The radius of the cylinder to emit from
- * @param height The height of the emission cylinder
- * @param radiusRange the range of the emission cylinder [0-1] 0 Surface only, 1 Entire Radius (1 by default)
- * @param direction1 Particles are emitted between the direction1 and direction2 from within the cylinder
- * @param direction2 Particles are emitted between the direction1 and direction2 from within the cylinder
- * @returns the emitter
- */
- createDirectedCylinderEmitter(radius = 1, height = 1, radiusRange = 1, direction1 = new Vector3(0, 1.0, 0), direction2 = new Vector3(0, 1.0, 0)) {
- const particleEmitter = CreateDirectedCylinderEmitter(radius, height, radiusRange, direction1, direction2);
- this.particleEmitterType = particleEmitter;
- return particleEmitter;
- }
- /**
- * Creates a Cone Emitter for the particle system (emits from the cone to the particle position)
- * @param radius The radius of the cone to emit from
- * @param angle The base angle of the cone
- * @returns the emitter
- */
- createConeEmitter(radius = 1, angle = Math.PI / 4) {
- const particleEmitter = CreateConeEmitter(radius, angle);
- this.particleEmitterType = particleEmitter;
- return particleEmitter;
- }
- /**
- * Creates a Box Emitter for the particle system. (emits between direction1 and direction2 from withing the box defined by minEmitBox and maxEmitBox)
- * @param direction1 Particles are emitted between the direction1 and direction2 from within the box
- * @param direction2 Particles are emitted between the direction1 and direction2 from within the box
- * @param minEmitBox Particles are emitted from the box between minEmitBox and maxEmitBox
- * @param maxEmitBox Particles are emitted from the box between minEmitBox and maxEmitBox
- * @returns the emitter
- */
- createBoxEmitter(direction1, direction2, minEmitBox, maxEmitBox) {
- const particleEmitter = new BoxParticleEmitter();
- this.particleEmitterType = particleEmitter;
- this.direction1 = direction1;
- this.direction2 = direction2;
- this.minEmitBox = minEmitBox;
- this.maxEmitBox = maxEmitBox;
- return particleEmitter;
- }
- _prepareSubEmitterInternalArray() {
- this._subEmitters = new Array();
- if (this.subEmitters) {
- this.subEmitters.forEach((subEmitter) => {
- if (subEmitter instanceof ParticleSystem) {
- this._subEmitters.push([new SubEmitter(subEmitter)]);
- }
- else if (subEmitter instanceof SubEmitter) {
- this._subEmitters.push([subEmitter]);
- }
- else if (subEmitter instanceof Array) {
- this._subEmitters.push(subEmitter);
- }
- });
- }
- }
- _stopSubEmitters() {
- if (!this.activeSubSystems) {
- return;
- }
- this.activeSubSystems.forEach((subSystem) => {
- subSystem.stop(true);
- });
- this.activeSubSystems = [];
- }
- _removeFromRoot() {
- if (!this._rootParticleSystem) {
- return;
- }
- const index = this._rootParticleSystem.activeSubSystems.indexOf(this);
- if (index !== -1) {
- this._rootParticleSystem.activeSubSystems.splice(index, 1);
- }
- this._rootParticleSystem = null;
- }
- _preStart() {
- // Convert the subEmitters field to the constant type field _subEmitters
- this._prepareSubEmitterInternalArray();
- if (this._subEmitters && this._subEmitters.length != 0) {
- this.activeSubSystems = [];
- }
- }
- _postStop(stopSubEmitters) {
- if (stopSubEmitters) {
- this._stopSubEmitters();
- }
- }
- _prepareParticle(particle) {
- // Attach emitters
- if (this._subEmitters && this._subEmitters.length > 0) {
- const subEmitters = this._subEmitters[Math.floor(Math.random() * this._subEmitters.length)];
- particle._attachedSubEmitters = [];
- subEmitters.forEach((subEmitter) => {
- if (subEmitter.type === SubEmitterType.ATTACHED) {
- const newEmitter = subEmitter.clone();
- particle._attachedSubEmitters.push(newEmitter);
- newEmitter.particleSystem.start();
- }
- });
- }
- }
- /** @internal */
- _onDispose(disposeAttachedSubEmitters = false, disposeEndSubEmitters = false) {
- this._removeFromRoot();
- if (this.subEmitters && !this._subEmitters) {
- this._prepareSubEmitterInternalArray();
- }
- if (disposeAttachedSubEmitters) {
- this.particles?.forEach((particle) => {
- if (particle._attachedSubEmitters) {
- for (let i = particle._attachedSubEmitters.length - 1; i >= 0; i -= 1) {
- particle._attachedSubEmitters[i].dispose();
- }
- }
- });
- }
- if (disposeEndSubEmitters) {
- if (this.activeSubSystems) {
- for (let i = this.activeSubSystems.length - 1; i >= 0; i -= 1) {
- this.activeSubSystems[i].dispose();
- }
- }
- }
- if (this._subEmitters && this._subEmitters.length) {
- for (let index = 0; index < this._subEmitters.length; index++) {
- for (const subEmitter of this._subEmitters[index]) {
- subEmitter.dispose();
- }
- }
- this._subEmitters = [];
- this.subEmitters = [];
- }
- if (this._disposeEmitterOnDispose && this.emitter && this.emitter.dispose) {
- this.emitter.dispose(true);
- }
- }
- /**
- * @internal
- */
- static _Parse(parsedParticleSystem, particleSystem, sceneOrEngine, rootUrl) {
- let scene;
- if (sceneOrEngine instanceof AbstractEngine) {
- scene = null;
- }
- else {
- scene = sceneOrEngine;
- }
- const internalClass = GetClass("BABYLON.Texture");
- if (internalClass && scene) {
- // Texture
- if (parsedParticleSystem.texture) {
- particleSystem.particleTexture = internalClass.Parse(parsedParticleSystem.texture, scene, rootUrl);
- }
- else if (parsedParticleSystem.textureName) {
- particleSystem.particleTexture = new internalClass(rootUrl + parsedParticleSystem.textureName, scene, false, parsedParticleSystem.invertY !== undefined ? parsedParticleSystem.invertY : true);
- particleSystem.particleTexture.name = parsedParticleSystem.textureName;
- }
- }
- // Emitter
- if (!parsedParticleSystem.emitterId && parsedParticleSystem.emitterId !== 0 && parsedParticleSystem.emitter === undefined) {
- particleSystem.emitter = Vector3.Zero();
- }
- else if (parsedParticleSystem.emitterId && scene) {
- particleSystem.emitter = scene.getLastMeshById(parsedParticleSystem.emitterId);
- }
- else {
- particleSystem.emitter = Vector3.FromArray(parsedParticleSystem.emitter);
- }
- particleSystem.isLocal = !!parsedParticleSystem.isLocal;
- // Misc.
- if (parsedParticleSystem.renderingGroupId !== undefined) {
- particleSystem.renderingGroupId = parsedParticleSystem.renderingGroupId;
- }
- if (parsedParticleSystem.isBillboardBased !== undefined) {
- particleSystem.isBillboardBased = parsedParticleSystem.isBillboardBased;
- }
- if (parsedParticleSystem.billboardMode !== undefined) {
- particleSystem.billboardMode = parsedParticleSystem.billboardMode;
- }
- if (parsedParticleSystem.useLogarithmicDepth !== undefined) {
- particleSystem.useLogarithmicDepth = parsedParticleSystem.useLogarithmicDepth;
- }
- // Animations
- if (parsedParticleSystem.animations) {
- for (let animationIndex = 0; animationIndex < parsedParticleSystem.animations.length; animationIndex++) {
- const parsedAnimation = parsedParticleSystem.animations[animationIndex];
- const internalClass = GetClass("BABYLON.Animation");
- if (internalClass) {
- particleSystem.animations.push(internalClass.Parse(parsedAnimation));
- }
- }
- particleSystem.beginAnimationOnStart = parsedParticleSystem.beginAnimationOnStart;
- particleSystem.beginAnimationFrom = parsedParticleSystem.beginAnimationFrom;
- particleSystem.beginAnimationTo = parsedParticleSystem.beginAnimationTo;
- particleSystem.beginAnimationLoop = parsedParticleSystem.beginAnimationLoop;
- }
- if (parsedParticleSystem.autoAnimate && scene) {
- scene.beginAnimation(particleSystem, parsedParticleSystem.autoAnimateFrom, parsedParticleSystem.autoAnimateTo, parsedParticleSystem.autoAnimateLoop, parsedParticleSystem.autoAnimateSpeed || 1.0);
- }
- // Particle system
- particleSystem.startDelay = parsedParticleSystem.startDelay | 0;
- particleSystem.minAngularSpeed = parsedParticleSystem.minAngularSpeed;
- particleSystem.maxAngularSpeed = parsedParticleSystem.maxAngularSpeed;
- particleSystem.minSize = parsedParticleSystem.minSize;
- particleSystem.maxSize = parsedParticleSystem.maxSize;
- if (parsedParticleSystem.minScaleX) {
- particleSystem.minScaleX = parsedParticleSystem.minScaleX;
- particleSystem.maxScaleX = parsedParticleSystem.maxScaleX;
- particleSystem.minScaleY = parsedParticleSystem.minScaleY;
- particleSystem.maxScaleY = parsedParticleSystem.maxScaleY;
- }
- if (parsedParticleSystem.preWarmCycles !== undefined) {
- particleSystem.preWarmCycles = parsedParticleSystem.preWarmCycles;
- particleSystem.preWarmStepOffset = parsedParticleSystem.preWarmStepOffset;
- }
- if (parsedParticleSystem.minInitialRotation !== undefined) {
- particleSystem.minInitialRotation = parsedParticleSystem.minInitialRotation;
- particleSystem.maxInitialRotation = parsedParticleSystem.maxInitialRotation;
- }
- particleSystem.minLifeTime = parsedParticleSystem.minLifeTime;
- particleSystem.maxLifeTime = parsedParticleSystem.maxLifeTime;
- particleSystem.minEmitPower = parsedParticleSystem.minEmitPower;
- particleSystem.maxEmitPower = parsedParticleSystem.maxEmitPower;
- particleSystem.emitRate = parsedParticleSystem.emitRate;
- particleSystem.gravity = Vector3.FromArray(parsedParticleSystem.gravity);
- if (parsedParticleSystem.noiseStrength) {
- particleSystem.noiseStrength = Vector3.FromArray(parsedParticleSystem.noiseStrength);
- }
- particleSystem.color1 = Color4.FromArray(parsedParticleSystem.color1);
- particleSystem.color2 = Color4.FromArray(parsedParticleSystem.color2);
- particleSystem.colorDead = Color4.FromArray(parsedParticleSystem.colorDead);
- particleSystem.updateSpeed = parsedParticleSystem.updateSpeed;
- particleSystem.targetStopDuration = parsedParticleSystem.targetStopDuration;
- particleSystem.blendMode = parsedParticleSystem.blendMode;
- if (parsedParticleSystem.colorGradients) {
- for (const colorGradient of parsedParticleSystem.colorGradients) {
- particleSystem.addColorGradient(colorGradient.gradient, Color4.FromArray(colorGradient.color1), colorGradient.color2 ? Color4.FromArray(colorGradient.color2) : undefined);
- }
- }
- if (parsedParticleSystem.rampGradients) {
- for (const rampGradient of parsedParticleSystem.rampGradients) {
- particleSystem.addRampGradient(rampGradient.gradient, Color3.FromArray(rampGradient.color));
- }
- particleSystem.useRampGradients = parsedParticleSystem.useRampGradients;
- }
- if (parsedParticleSystem.colorRemapGradients) {
- for (const colorRemapGradient of parsedParticleSystem.colorRemapGradients) {
- particleSystem.addColorRemapGradient(colorRemapGradient.gradient, colorRemapGradient.factor1 !== undefined ? colorRemapGradient.factor1 : colorRemapGradient.factor, colorRemapGradient.factor2);
- }
- }
- if (parsedParticleSystem.alphaRemapGradients) {
- for (const alphaRemapGradient of parsedParticleSystem.alphaRemapGradients) {
- particleSystem.addAlphaRemapGradient(alphaRemapGradient.gradient, alphaRemapGradient.factor1 !== undefined ? alphaRemapGradient.factor1 : alphaRemapGradient.factor, alphaRemapGradient.factor2);
- }
- }
- if (parsedParticleSystem.sizeGradients) {
- for (const sizeGradient of parsedParticleSystem.sizeGradients) {
- particleSystem.addSizeGradient(sizeGradient.gradient, sizeGradient.factor1 !== undefined ? sizeGradient.factor1 : sizeGradient.factor, sizeGradient.factor2);
- }
- }
- if (parsedParticleSystem.angularSpeedGradients) {
- for (const angularSpeedGradient of parsedParticleSystem.angularSpeedGradients) {
- particleSystem.addAngularSpeedGradient(angularSpeedGradient.gradient, angularSpeedGradient.factor1 !== undefined ? angularSpeedGradient.factor1 : angularSpeedGradient.factor, angularSpeedGradient.factor2);
- }
- }
- if (parsedParticleSystem.velocityGradients) {
- for (const velocityGradient of parsedParticleSystem.velocityGradients) {
- particleSystem.addVelocityGradient(velocityGradient.gradient, velocityGradient.factor1 !== undefined ? velocityGradient.factor1 : velocityGradient.factor, velocityGradient.factor2);
- }
- }
- if (parsedParticleSystem.dragGradients) {
- for (const dragGradient of parsedParticleSystem.dragGradients) {
- particleSystem.addDragGradient(dragGradient.gradient, dragGradient.factor1 !== undefined ? dragGradient.factor1 : dragGradient.factor, dragGradient.factor2);
- }
- }
- if (parsedParticleSystem.emitRateGradients) {
- for (const emitRateGradient of parsedParticleSystem.emitRateGradients) {
- particleSystem.addEmitRateGradient(emitRateGradient.gradient, emitRateGradient.factor1 !== undefined ? emitRateGradient.factor1 : emitRateGradient.factor, emitRateGradient.factor2);
- }
- }
- if (parsedParticleSystem.startSizeGradients) {
- for (const startSizeGradient of parsedParticleSystem.startSizeGradients) {
- particleSystem.addStartSizeGradient(startSizeGradient.gradient, startSizeGradient.factor1 !== undefined ? startSizeGradient.factor1 : startSizeGradient.factor, startSizeGradient.factor2);
- }
- }
- if (parsedParticleSystem.lifeTimeGradients) {
- for (const lifeTimeGradient of parsedParticleSystem.lifeTimeGradients) {
- particleSystem.addLifeTimeGradient(lifeTimeGradient.gradient, lifeTimeGradient.factor1 !== undefined ? lifeTimeGradient.factor1 : lifeTimeGradient.factor, lifeTimeGradient.factor2);
- }
- }
- if (parsedParticleSystem.limitVelocityGradients) {
- for (const limitVelocityGradient of parsedParticleSystem.limitVelocityGradients) {
- particleSystem.addLimitVelocityGradient(limitVelocityGradient.gradient, limitVelocityGradient.factor1 !== undefined ? limitVelocityGradient.factor1 : limitVelocityGradient.factor, limitVelocityGradient.factor2);
- }
- particleSystem.limitVelocityDamping = parsedParticleSystem.limitVelocityDamping;
- }
- if (parsedParticleSystem.noiseTexture && scene) {
- const internalClass = GetClass("BABYLON.ProceduralTexture");
- particleSystem.noiseTexture = internalClass.Parse(parsedParticleSystem.noiseTexture, scene, rootUrl);
- }
- // Emitter
- let emitterType;
- if (parsedParticleSystem.particleEmitterType) {
- switch (parsedParticleSystem.particleEmitterType.type) {
- case "SphereParticleEmitter":
- emitterType = new SphereParticleEmitter();
- break;
- case "SphereDirectedParticleEmitter":
- emitterType = new SphereDirectedParticleEmitter();
- break;
- case "ConeEmitter":
- case "ConeParticleEmitter":
- emitterType = new ConeParticleEmitter();
- break;
- case "CylinderParticleEmitter":
- emitterType = new CylinderParticleEmitter();
- break;
- case "CylinderDirectedParticleEmitter":
- emitterType = new CylinderDirectedParticleEmitter();
- break;
- case "HemisphericParticleEmitter":
- emitterType = new HemisphericParticleEmitter();
- break;
- case "PointParticleEmitter":
- emitterType = new PointParticleEmitter();
- break;
- case "MeshParticleEmitter":
- emitterType = new MeshParticleEmitter();
- break;
- case "CustomParticleEmitter":
- emitterType = new CustomParticleEmitter();
- break;
- case "BoxEmitter":
- case "BoxParticleEmitter":
- default:
- emitterType = new BoxParticleEmitter();
- break;
- }
- emitterType.parse(parsedParticleSystem.particleEmitterType, scene);
- }
- else {
- emitterType = new BoxParticleEmitter();
- emitterType.parse(parsedParticleSystem, scene);
- }
- particleSystem.particleEmitterType = emitterType;
- // Animation sheet
- particleSystem.startSpriteCellID = parsedParticleSystem.startSpriteCellID;
- particleSystem.endSpriteCellID = parsedParticleSystem.endSpriteCellID;
- particleSystem.spriteCellLoop = parsedParticleSystem.spriteCellLoop ?? true;
- particleSystem.spriteCellWidth = parsedParticleSystem.spriteCellWidth;
- particleSystem.spriteCellHeight = parsedParticleSystem.spriteCellHeight;
- particleSystem.spriteCellChangeSpeed = parsedParticleSystem.spriteCellChangeSpeed;
- particleSystem.spriteRandomStartCell = parsedParticleSystem.spriteRandomStartCell;
- particleSystem.disposeOnStop = parsedParticleSystem.disposeOnStop ?? false;
- particleSystem.manualEmitCount = parsedParticleSystem.manualEmitCount ?? -1;
- }
- /**
- * Parses a JSON object to create a particle system.
- * @param parsedParticleSystem The JSON object to parse
- * @param sceneOrEngine The scene or the engine to create the particle system in
- * @param rootUrl The root url to use to load external dependencies like texture
- * @param doNotStart Ignore the preventAutoStart attribute and does not start
- * @param capacity defines the system capacity (if null or undefined the sotred capacity will be used)
- * @returns the Parsed particle system
- */
- static Parse(parsedParticleSystem, sceneOrEngine, rootUrl, doNotStart = false, capacity) {
- const name = parsedParticleSystem.name;
- let custom = null;
- let program = null;
- let engine;
- let scene;
- if (sceneOrEngine instanceof AbstractEngine) {
- engine = sceneOrEngine;
- }
- else {
- scene = sceneOrEngine;
- engine = scene.getEngine();
- }
- if (parsedParticleSystem.customShader && engine.createEffectForParticles) {
- program = parsedParticleSystem.customShader;
- const defines = program.shaderOptions.defines.length > 0 ? program.shaderOptions.defines.join("\n") : "";
- custom = engine.createEffectForParticles(program.shaderPath.fragmentElement, program.shaderOptions.uniforms, program.shaderOptions.samplers, defines);
- }
- const particleSystem = new ParticleSystem(name, capacity || parsedParticleSystem.capacity, sceneOrEngine, custom, parsedParticleSystem.isAnimationSheetEnabled);
- particleSystem.customShader = program;
- particleSystem._rootUrl = rootUrl;
- if (parsedParticleSystem.id) {
- particleSystem.id = parsedParticleSystem.id;
- }
- // SubEmitters
- if (parsedParticleSystem.subEmitters) {
- particleSystem.subEmitters = [];
- for (const cell of parsedParticleSystem.subEmitters) {
- const cellArray = [];
- for (const sub of cell) {
- cellArray.push(SubEmitter.Parse(sub, sceneOrEngine, rootUrl));
- }
- particleSystem.subEmitters.push(cellArray);
- }
- }
- ParticleSystem._Parse(parsedParticleSystem, particleSystem, sceneOrEngine, rootUrl);
- if (parsedParticleSystem.textureMask) {
- particleSystem.textureMask = Color4.FromArray(parsedParticleSystem.textureMask);
- }
- if (parsedParticleSystem.worldOffset) {
- particleSystem.worldOffset = Vector3.FromArray(parsedParticleSystem.worldOffset);
- }
- // Auto start
- if (parsedParticleSystem.preventAutoStart) {
- particleSystem.preventAutoStart = parsedParticleSystem.preventAutoStart;
- }
- if (!doNotStart && !particleSystem.preventAutoStart) {
- particleSystem.start();
- }
- return particleSystem;
- }
- /**
- * Serializes the particle system to a JSON object
- * @param serializeTexture defines if the texture must be serialized as well
- * @returns the JSON object
- */
- serialize(serializeTexture = false) {
- const serializationObject = {};
- ParticleSystem._Serialize(serializationObject, this, serializeTexture);
- serializationObject.textureMask = this.textureMask.asArray();
- serializationObject.customShader = this.customShader;
- serializationObject.preventAutoStart = this.preventAutoStart;
- serializationObject.worldOffset = this.worldOffset.asArray();
- // SubEmitters
- if (this.subEmitters) {
- serializationObject.subEmitters = [];
- if (!this._subEmitters) {
- this._prepareSubEmitterInternalArray();
- }
- for (const subs of this._subEmitters) {
- const cell = [];
- for (const sub of subs) {
- cell.push(sub.serialize(serializeTexture));
- }
- serializationObject.subEmitters.push(cell);
- }
- }
- return serializationObject;
- }
- /**
- * @internal
- */
- static _Serialize(serializationObject, particleSystem, serializeTexture) {
- serializationObject.name = particleSystem.name;
- serializationObject.id = particleSystem.id;
- serializationObject.capacity = particleSystem.getCapacity();
- serializationObject.disposeOnStop = particleSystem.disposeOnStop;
- serializationObject.manualEmitCount = particleSystem.manualEmitCount;
- // Emitter
- if (particleSystem.emitter.position) {
- const emitterMesh = particleSystem.emitter;
- serializationObject.emitterId = emitterMesh.id;
- }
- else {
- const emitterPosition = particleSystem.emitter;
- serializationObject.emitter = emitterPosition.asArray();
- }
- // Emitter
- if (particleSystem.particleEmitterType) {
- serializationObject.particleEmitterType = particleSystem.particleEmitterType.serialize();
- }
- if (particleSystem.particleTexture) {
- if (serializeTexture) {
- serializationObject.texture = particleSystem.particleTexture.serialize();
- }
- else {
- serializationObject.textureName = particleSystem.particleTexture.name;
- serializationObject.invertY = !!particleSystem.particleTexture._invertY;
- }
- }
- serializationObject.isLocal = particleSystem.isLocal;
- // Animations
- SerializationHelper.AppendSerializedAnimations(particleSystem, serializationObject);
- serializationObject.beginAnimationOnStart = particleSystem.beginAnimationOnStart;
- serializationObject.beginAnimationFrom = particleSystem.beginAnimationFrom;
- serializationObject.beginAnimationTo = particleSystem.beginAnimationTo;
- serializationObject.beginAnimationLoop = particleSystem.beginAnimationLoop;
- // Particle system
- serializationObject.startDelay = particleSystem.startDelay;
- serializationObject.renderingGroupId = particleSystem.renderingGroupId;
- serializationObject.isBillboardBased = particleSystem.isBillboardBased;
- serializationObject.billboardMode = particleSystem.billboardMode;
- serializationObject.minAngularSpeed = particleSystem.minAngularSpeed;
- serializationObject.maxAngularSpeed = particleSystem.maxAngularSpeed;
- serializationObject.minSize = particleSystem.minSize;
- serializationObject.maxSize = particleSystem.maxSize;
- serializationObject.minScaleX = particleSystem.minScaleX;
- serializationObject.maxScaleX = particleSystem.maxScaleX;
- serializationObject.minScaleY = particleSystem.minScaleY;
- serializationObject.maxScaleY = particleSystem.maxScaleY;
- serializationObject.minEmitPower = particleSystem.minEmitPower;
- serializationObject.maxEmitPower = particleSystem.maxEmitPower;
- serializationObject.minLifeTime = particleSystem.minLifeTime;
- serializationObject.maxLifeTime = particleSystem.maxLifeTime;
- serializationObject.emitRate = particleSystem.emitRate;
- serializationObject.gravity = particleSystem.gravity.asArray();
- serializationObject.noiseStrength = particleSystem.noiseStrength.asArray();
- serializationObject.color1 = particleSystem.color1.asArray();
- serializationObject.color2 = particleSystem.color2.asArray();
- serializationObject.colorDead = particleSystem.colorDead.asArray();
- serializationObject.updateSpeed = particleSystem.updateSpeed;
- serializationObject.targetStopDuration = particleSystem.targetStopDuration;
- serializationObject.blendMode = particleSystem.blendMode;
- serializationObject.preWarmCycles = particleSystem.preWarmCycles;
- serializationObject.preWarmStepOffset = particleSystem.preWarmStepOffset;
- serializationObject.minInitialRotation = particleSystem.minInitialRotation;
- serializationObject.maxInitialRotation = particleSystem.maxInitialRotation;
- serializationObject.startSpriteCellID = particleSystem.startSpriteCellID;
- serializationObject.spriteCellLoop = particleSystem.spriteCellLoop;
- serializationObject.endSpriteCellID = particleSystem.endSpriteCellID;
- serializationObject.spriteCellChangeSpeed = particleSystem.spriteCellChangeSpeed;
- serializationObject.spriteCellWidth = particleSystem.spriteCellWidth;
- serializationObject.spriteCellHeight = particleSystem.spriteCellHeight;
- serializationObject.spriteRandomStartCell = particleSystem.spriteRandomStartCell;
- serializationObject.isAnimationSheetEnabled = particleSystem.isAnimationSheetEnabled;
- serializationObject.useLogarithmicDepth = particleSystem.useLogarithmicDepth;
- const colorGradients = particleSystem.getColorGradients();
- if (colorGradients) {
- serializationObject.colorGradients = [];
- for (const colorGradient of colorGradients) {
- const serializedGradient = {
- gradient: colorGradient.gradient,
- color1: colorGradient.color1.asArray(),
- };
- if (colorGradient.color2) {
- serializedGradient.color2 = colorGradient.color2.asArray();
- }
- else {
- serializedGradient.color2 = colorGradient.color1.asArray();
- }
- serializationObject.colorGradients.push(serializedGradient);
- }
- }
- const rampGradients = particleSystem.getRampGradients();
- if (rampGradients) {
- serializationObject.rampGradients = [];
- for (const rampGradient of rampGradients) {
- const serializedGradient = {
- gradient: rampGradient.gradient,
- color: rampGradient.color.asArray(),
- };
- serializationObject.rampGradients.push(serializedGradient);
- }
- serializationObject.useRampGradients = particleSystem.useRampGradients;
- }
- const colorRemapGradients = particleSystem.getColorRemapGradients();
- if (colorRemapGradients) {
- serializationObject.colorRemapGradients = [];
- for (const colorRemapGradient of colorRemapGradients) {
- const serializedGradient = {
- gradient: colorRemapGradient.gradient,
- factor1: colorRemapGradient.factor1,
- };
- if (colorRemapGradient.factor2 !== undefined) {
- serializedGradient.factor2 = colorRemapGradient.factor2;
- }
- else {
- serializedGradient.factor2 = colorRemapGradient.factor1;
- }
- serializationObject.colorRemapGradients.push(serializedGradient);
- }
- }
- const alphaRemapGradients = particleSystem.getAlphaRemapGradients();
- if (alphaRemapGradients) {
- serializationObject.alphaRemapGradients = [];
- for (const alphaRemapGradient of alphaRemapGradients) {
- const serializedGradient = {
- gradient: alphaRemapGradient.gradient,
- factor1: alphaRemapGradient.factor1,
- };
- if (alphaRemapGradient.factor2 !== undefined) {
- serializedGradient.factor2 = alphaRemapGradient.factor2;
- }
- else {
- serializedGradient.factor2 = alphaRemapGradient.factor1;
- }
- serializationObject.alphaRemapGradients.push(serializedGradient);
- }
- }
- const sizeGradients = particleSystem.getSizeGradients();
- if (sizeGradients) {
- serializationObject.sizeGradients = [];
- for (const sizeGradient of sizeGradients) {
- const serializedGradient = {
- gradient: sizeGradient.gradient,
- factor1: sizeGradient.factor1,
- };
- if (sizeGradient.factor2 !== undefined) {
- serializedGradient.factor2 = sizeGradient.factor2;
- }
- else {
- serializedGradient.factor2 = sizeGradient.factor1;
- }
- serializationObject.sizeGradients.push(serializedGradient);
- }
- }
- const angularSpeedGradients = particleSystem.getAngularSpeedGradients();
- if (angularSpeedGradients) {
- serializationObject.angularSpeedGradients = [];
- for (const angularSpeedGradient of angularSpeedGradients) {
- const serializedGradient = {
- gradient: angularSpeedGradient.gradient,
- factor1: angularSpeedGradient.factor1,
- };
- if (angularSpeedGradient.factor2 !== undefined) {
- serializedGradient.factor2 = angularSpeedGradient.factor2;
- }
- else {
- serializedGradient.factor2 = angularSpeedGradient.factor1;
- }
- serializationObject.angularSpeedGradients.push(serializedGradient);
- }
- }
- const velocityGradients = particleSystem.getVelocityGradients();
- if (velocityGradients) {
- serializationObject.velocityGradients = [];
- for (const velocityGradient of velocityGradients) {
- const serializedGradient = {
- gradient: velocityGradient.gradient,
- factor1: velocityGradient.factor1,
- };
- if (velocityGradient.factor2 !== undefined) {
- serializedGradient.factor2 = velocityGradient.factor2;
- }
- else {
- serializedGradient.factor2 = velocityGradient.factor1;
- }
- serializationObject.velocityGradients.push(serializedGradient);
- }
- }
- const dragGradients = particleSystem.getDragGradients();
- if (dragGradients) {
- serializationObject.dragGradients = [];
- for (const dragGradient of dragGradients) {
- const serializedGradient = {
- gradient: dragGradient.gradient,
- factor1: dragGradient.factor1,
- };
- if (dragGradient.factor2 !== undefined) {
- serializedGradient.factor2 = dragGradient.factor2;
- }
- else {
- serializedGradient.factor2 = dragGradient.factor1;
- }
- serializationObject.dragGradients.push(serializedGradient);
- }
- }
- const emitRateGradients = particleSystem.getEmitRateGradients();
- if (emitRateGradients) {
- serializationObject.emitRateGradients = [];
- for (const emitRateGradient of emitRateGradients) {
- const serializedGradient = {
- gradient: emitRateGradient.gradient,
- factor1: emitRateGradient.factor1,
- };
- if (emitRateGradient.factor2 !== undefined) {
- serializedGradient.factor2 = emitRateGradient.factor2;
- }
- else {
- serializedGradient.factor2 = emitRateGradient.factor1;
- }
- serializationObject.emitRateGradients.push(serializedGradient);
- }
- }
- const startSizeGradients = particleSystem.getStartSizeGradients();
- if (startSizeGradients) {
- serializationObject.startSizeGradients = [];
- for (const startSizeGradient of startSizeGradients) {
- const serializedGradient = {
- gradient: startSizeGradient.gradient,
- factor1: startSizeGradient.factor1,
- };
- if (startSizeGradient.factor2 !== undefined) {
- serializedGradient.factor2 = startSizeGradient.factor2;
- }
- else {
- serializedGradient.factor2 = startSizeGradient.factor1;
- }
- serializationObject.startSizeGradients.push(serializedGradient);
- }
- }
- const lifeTimeGradients = particleSystem.getLifeTimeGradients();
- if (lifeTimeGradients) {
- serializationObject.lifeTimeGradients = [];
- for (const lifeTimeGradient of lifeTimeGradients) {
- const serializedGradient = {
- gradient: lifeTimeGradient.gradient,
- factor1: lifeTimeGradient.factor1,
- };
- if (lifeTimeGradient.factor2 !== undefined) {
- serializedGradient.factor2 = lifeTimeGradient.factor2;
- }
- else {
- serializedGradient.factor2 = lifeTimeGradient.factor1;
- }
- serializationObject.lifeTimeGradients.push(serializedGradient);
- }
- }
- const limitVelocityGradients = particleSystem.getLimitVelocityGradients();
- if (limitVelocityGradients) {
- serializationObject.limitVelocityGradients = [];
- for (const limitVelocityGradient of limitVelocityGradients) {
- const serializedGradient = {
- gradient: limitVelocityGradient.gradient,
- factor1: limitVelocityGradient.factor1,
- };
- if (limitVelocityGradient.factor2 !== undefined) {
- serializedGradient.factor2 = limitVelocityGradient.factor2;
- }
- else {
- serializedGradient.factor2 = limitVelocityGradient.factor1;
- }
- serializationObject.limitVelocityGradients.push(serializedGradient);
- }
- serializationObject.limitVelocityDamping = particleSystem.limitVelocityDamping;
- }
- if (particleSystem.noiseTexture) {
- serializationObject.noiseTexture = particleSystem.noiseTexture.serialize();
- }
- }
- // Clone
- /**
- * Clones the particle system.
- * @param name The name of the cloned object
- * @param newEmitter The new emitter to use
- * @param cloneTexture Also clone the textures if true
- * @returns the cloned particle system
- */
- clone(name, newEmitter, cloneTexture = false) {
- const custom = { ...this._customWrappers };
- let program = null;
- const engine = this._engine;
- if (engine.createEffectForParticles) {
- if (this.customShader != null) {
- program = this.customShader;
- const defines = program.shaderOptions.defines.length > 0 ? program.shaderOptions.defines.join("\n") : "";
- const effect = engine.createEffectForParticles(program.shaderPath.fragmentElement, program.shaderOptions.uniforms, program.shaderOptions.samplers, defines);
- if (!custom[0]) {
- this.setCustomEffect(effect, 0);
- }
- else {
- custom[0].effect = effect;
- }
- }
- }
- const serialization = this.serialize(cloneTexture);
- const result = ParticleSystem.Parse(serialization, this._scene || this._engine, this._rootUrl);
- result.name = name;
- result.customShader = program;
- result._customWrappers = custom;
- if (newEmitter === undefined) {
- newEmitter = this.emitter;
- }
- if (this.noiseTexture) {
- result.noiseTexture = this.noiseTexture.clone();
- }
- result.emitter = newEmitter;
- if (!this.preventAutoStart) {
- result.start();
- }
- return result;
- }
- }
- /**
- * Billboard mode will only apply to Y axis
- */
- ParticleSystem.BILLBOARDMODE_Y = 2;
- /**
- * Billboard mode will apply to all axes
- */
- ParticleSystem.BILLBOARDMODE_ALL = 7;
- /**
- * Special billboard mode where the particle will be biilboard to the camera but rotated to align with direction
- */
- ParticleSystem.BILLBOARDMODE_STRETCHED = 8;
- /**
- * Special billboard mode where the particle will be billboard to the camera but only around the axis of the direction of particle emission
- */
- ParticleSystem.BILLBOARDMODE_STRETCHED_LOCAL = 9;
- SubEmitter._ParseParticleSystem = ParticleSystem.Parse;
- //# sourceMappingURL=particleSystem.js.map
|