@babylonjs/core
Version:
Getting started? Play directly with the Babylon.js API using our [playground](https://playground.babylonjs.com/). It also contains a lot of samples to learn how to use it.
349 lines (348 loc) • 15.5 kB
JavaScript
import { __decorate } from "../../../tslib.es6.js";
import { editableInPropertyPage } from "../../../Decorators/nodeDecorator.js";
import { RegisterClass } from "../../../Misc/typeStore.js";
import { Vector2, Vector3 } from "../../../Maths/math.vector.js";
import { Color4 } from "../../../Maths/math.color.js";
import { BaseParticleSystem } from "../../baseParticleSystem.js";
import { NodeParticleBlock } from "../nodeParticleBlock.js";
import { _TriggerSubEmitter } from "./Triggers/triggerTools.js";
import { NodeParticleBlockConnectionPointTypes } from "../Enums/nodeParticleBlockConnectionPointTypes.js";
/**
* Block used to get a system of particles
*/
export class SystemBlock extends NodeParticleBlock {
/**
* Create a new SystemBlock
* @param name defines the block name
*/
constructor(name) {
super(name);
/**
* Gets or sets the blend mode for the particle system
*/
this.blendMode = BaseParticleSystem.BLENDMODE_ONEONE;
/**
* Gets or sets the epsilon value used for comparison
*/
this.capacity = 1000;
/**
* Gets or sets the manual emit count
*/
this.manualEmitCount = -1;
/**
* Gets or sets the target stop duration for the particle system
*/
this.startDelay = 0;
/**
* Gets or sets the target stop duration for the particle system
*/
this.updateSpeed = 0.0167;
/**
* Gets or sets the number of pre-warm cycles before rendering the particle system
*/
this.preWarmCycles = 0;
/**
* Gets or sets the time step multiplier used for pre-warm
*/
this.preWarmStepOffset = 0;
/**
* Gets or sets a boolean indicating if the system is billboard based
*/
this.isBillboardBased = true;
/**
* Gets or sets the billboard mode for the particle system
*/
this.billBoardMode = 7;
/**
* Gets or sets a boolean indicating if the system coordinate space is local or global
*/
this.isLocal = false;
/**
* Gets or sets a boolean indicating if the system should be disposed when stopped
*/
this.disposeOnStop = false;
/**
* Gets or sets a boolean indicating if the system should not start automatically
*/
this.doNoStart = false;
/**
* Gets or sets the rendering group id for the particle system (0 by default)
*/
this.renderingGroupId = 0;
/** @internal */
this._internalId = SystemBlock._IdCounter++;
/**
* Gets or sets the custom shader configuration used to render the particles.
* This can be used to set your own shader to render the particle system.
*/
this.customShader = null;
/**
* Gets or sets the emitter for the particle system.
*/
this.emitter = Vector3.Zero();
this._isSystem = true;
this.registerInput("particle", NodeParticleBlockConnectionPointTypes.Particle);
this.registerInput("emitRate", NodeParticleBlockConnectionPointTypes.Int, true, 10, 0);
this.registerInput("texture", NodeParticleBlockConnectionPointTypes.Texture);
this.registerInput("translationPivot", NodeParticleBlockConnectionPointTypes.Vector2, true);
this.registerInput("textureMask", NodeParticleBlockConnectionPointTypes.Color4, true);
this.registerInput("targetStopDuration", NodeParticleBlockConnectionPointTypes.Float, true, 0, 0);
this.registerInput("onStart", NodeParticleBlockConnectionPointTypes.System, true);
this.registerInput("onEnd", NodeParticleBlockConnectionPointTypes.System, true);
this.registerOutput("system", NodeParticleBlockConnectionPointTypes.System);
}
/**
* Gets the current class name
* @returns the class name
*/
getClassName() {
return "SystemBlock";
}
/**
* Gets the particle input component
*/
get particle() {
return this._inputs[0];
}
/**
* Gets the emitRate input component
*/
get emitRate() {
return this._inputs[1];
}
/**
* Gets the texture input component
*/
get texture() {
return this._inputs[2];
}
/**
* Gets the translationPivot input component
*/
get translationPivot() {
return this._inputs[3];
}
/**
* Gets the textureMask input component
*/
get textureMask() {
return this._inputs[4];
}
/**
* Gets the targetStopDuration input component
*/
get targetStopDuration() {
return this._inputs[5];
}
/**
* Gets the onStart input component
*/
get onStart() {
return this._inputs[6];
}
/**
* Gets the onEnd input component
*/
get onEnd() {
return this._inputs[7];
}
/**
* Gets the system output component
*/
get system() {
return this._outputs[0];
}
/**
* Builds the block and return a functional particle system
* @param state defines the building state
* @returns the built particle system
*/
createSystem(state) {
state.capacity = this.capacity;
state.buildId = this._buildId++;
this.build(state);
const particleSystem = this.particle.getConnectedValue(state);
particleSystem.particleTexture = this.texture.getConnectedValue(state);
particleSystem.emitRate = this.emitRate.getConnectedValue(state);
particleSystem.manualEmitCount = this.manualEmitCount;
particleSystem.updateSpeed = this.updateSpeed;
particleSystem.preWarmCycles = this.preWarmCycles;
particleSystem.preWarmStepOffset = this.preWarmStepOffset;
particleSystem.blendMode = this.blendMode;
particleSystem.name = this.name;
particleSystem._targetStopDuration = this.targetStopDuration.getConnectedValue(state) ?? 0;
particleSystem.startDelay = this.startDelay;
particleSystem.isBillboardBased = this.isBillboardBased;
particleSystem.billboardMode = this.billBoardMode;
particleSystem.translationPivot = this.translationPivot.getConnectedValue(state) || Vector2.Zero();
particleSystem.textureMask = this.textureMask.getConnectedValue(state) ?? new Color4(1, 1, 1, 1);
particleSystem.isLocal = this.isLocal;
particleSystem.disposeOnStop = this.disposeOnStop;
particleSystem.renderingGroupId = this.renderingGroupId;
if (this.emitter) {
particleSystem.emitter = this.emitter;
}
// Apply custom shader if defined
if (this.customShader) {
const engine = particleSystem.getScene()?.getEngine();
if (engine?.createEffectForParticles) {
const defines = this.customShader.shaderOptions.defines.length > 0 ? this.customShader.shaderOptions.defines.join("\n") : "";
const effect = engine.createEffectForParticles(this.customShader.shaderPath.fragmentElement, this.customShader.shaderOptions.uniforms, this.customShader.shaderOptions.samplers, defines);
particleSystem.setCustomEffect(effect, 0);
particleSystem.customShader = this.customShader;
}
}
// The emit rate can vary if it is connected to another block like a gradient
particleSystem._calculateEmitRate = () => {
state.systemContext = particleSystem;
return this.emitRate.getConnectedValue(state);
};
this.system._storedValue = this;
particleSystem.canStart = () => {
return !this.doNoStart;
};
particleSystem.onStartedObservable.add((system) => {
// Triggers
const onStartSystem = this.onStart.getConnectedValue(state);
if (onStartSystem) {
system.onStartedObservable.addOnce(() => {
state.systemContext = particleSystem;
const clone = _TriggerSubEmitter(onStartSystem, state.scene, state.emitterPosition);
this.onDisposeObservable.addOnce(() => {
// Clean up the cloned system when the original system is disposed
clone.dispose();
});
});
}
const onEndSystem = this.onEnd.getConnectedValue(state);
if (onEndSystem) {
system.onStoppedObservable.addOnce(() => {
state.systemContext = particleSystem;
const clone = _TriggerSubEmitter(onEndSystem, state.scene, state.emitterPosition);
this.onDisposeObservable.addOnce(() => {
// Clean up the cloned system when the original system is disposed
clone.dispose();
});
});
}
});
this.onDisposeObservable.addOnce(() => {
particleSystem.dispose();
});
// Return
return particleSystem;
}
/**
* Serializes the system block
* @returns The serialized object
*/
serialize() {
const serializationObject = super.serialize();
serializationObject.capacity = this.capacity;
serializationObject.manualEmitCount = this.manualEmitCount;
serializationObject.blendMode = this.blendMode;
serializationObject.updateSpeed = this.updateSpeed;
serializationObject.preWarmCycles = this.preWarmCycles;
serializationObject.preWarmStepOffset = this.preWarmStepOffset;
serializationObject.isBillboardBased = this.isBillboardBased;
serializationObject.billBoardMode = this.billBoardMode;
serializationObject.isLocal = this.isLocal;
serializationObject.disposeOnStop = this.disposeOnStop;
serializationObject.doNoStart = this.doNoStart;
serializationObject.renderingGroupId = this.renderingGroupId;
serializationObject.startDelay = this.startDelay;
serializationObject.customShader = this.customShader;
return serializationObject;
}
/**
* Deserializes the system block
* @param serializationObject The serialized system
*/
_deserialize(serializationObject) {
super._deserialize(serializationObject);
this.capacity = serializationObject.capacity;
this.manualEmitCount = serializationObject.manualEmitCount ?? -1;
this.updateSpeed = serializationObject.updateSpeed ?? 0.0167;
this.preWarmCycles = serializationObject.preWarmCycles ?? 0;
this.preWarmStepOffset = serializationObject.preWarmStepOffset ?? 0;
this.isBillboardBased = serializationObject.isBillboardBased ?? true;
this.billBoardMode = serializationObject.billBoardMode ?? 7;
this.isLocal = serializationObject.isLocal ?? false;
this.disposeOnStop = serializationObject.disposeOnStop ?? false;
this.doNoStart = !!serializationObject.doNoStart;
this.renderingGroupId = serializationObject.renderingGroupId ?? 0;
if (serializationObject.emitRate !== undefined) {
this.emitRate.value = serializationObject.emitRate;
}
if (serializationObject.blendMode !== undefined) {
this.blendMode = serializationObject.blendMode;
}
if (serializationObject.startDelay !== undefined) {
this.startDelay = serializationObject.startDelay;
}
if (serializationObject.customShader !== undefined) {
this.customShader = serializationObject.customShader;
}
}
}
SystemBlock._IdCounter = 0;
__decorate([
editableInPropertyPage("Blend mode", 5 /* PropertyTypeForEdition.List */, "ADVANCED", {
notifiers: { rebuild: true },
embedded: true,
options: [
{ label: "Blend Mode OneOne", value: BaseParticleSystem.BLENDMODE_ONEONE },
{ label: "Blend Mode Standard", value: BaseParticleSystem.BLENDMODE_STANDARD },
{ label: "Blend Mode Add", value: BaseParticleSystem.BLENDMODE_ADD },
{ label: "Blend Mode Multiply", value: BaseParticleSystem.BLENDMODE_MULTIPLY },
{ label: "Blend Mode MultiplyAdd", value: BaseParticleSystem.BLENDMODE_MULTIPLYADD },
],
})
], SystemBlock.prototype, "blendMode", void 0);
__decorate([
editableInPropertyPage("Capacity", 2 /* PropertyTypeForEdition.Int */, "ADVANCED", { embedded: true, notifiers: { rebuild: true }, min: 0, max: 10000 })
], SystemBlock.prototype, "capacity", void 0);
__decorate([
editableInPropertyPage("Manual emit count", 2 /* PropertyTypeForEdition.Int */, "ADVANCED", { embedded: true, notifiers: { rebuild: true }, min: -1 })
], SystemBlock.prototype, "manualEmitCount", void 0);
__decorate([
editableInPropertyPage("Delay start(ms)", 1 /* PropertyTypeForEdition.Float */, "ADVANCED", { embedded: true, notifiers: { rebuild: true }, min: 0 })
], SystemBlock.prototype, "startDelay", void 0);
__decorate([
editableInPropertyPage("updateSpeed", 1 /* PropertyTypeForEdition.Float */, "ADVANCED", { embedded: true, notifiers: { rebuild: true }, min: 0, max: 0.1 })
], SystemBlock.prototype, "updateSpeed", void 0);
__decorate([
editableInPropertyPage("Pre-warm cycles", 1 /* PropertyTypeForEdition.Float */, "ADVANCED", { embedded: true, notifiers: { rebuild: true }, min: 0 })
], SystemBlock.prototype, "preWarmCycles", void 0);
__decorate([
editableInPropertyPage("Pre-warm step multiplier", 1 /* PropertyTypeForEdition.Float */, "ADVANCED", { embedded: true, notifiers: { rebuild: true }, min: 0 })
], SystemBlock.prototype, "preWarmStepOffset", void 0);
__decorate([
editableInPropertyPage("Is billboard based", 0 /* PropertyTypeForEdition.Boolean */, "ADVANCED", { embedded: true, notifiers: { rebuild: true } })
], SystemBlock.prototype, "isBillboardBased", void 0);
__decorate([
editableInPropertyPage("Billboard mode", 5 /* PropertyTypeForEdition.List */, "ADVANCED", {
notifiers: { rebuild: true },
embedded: true,
options: [
{ label: "Billboard Mode All", value: 7 },
{ label: "Billboard Mode Y", value: 2 },
{ label: "Billboard Mode Stretched", value: 8 },
{ label: "Billboard Mode Stretched Local", value: 9 },
],
})
], SystemBlock.prototype, "billBoardMode", void 0);
__decorate([
editableInPropertyPage("Is local", 0 /* PropertyTypeForEdition.Boolean */, "ADVANCED", { embedded: true, notifiers: { rebuild: true } })
], SystemBlock.prototype, "isLocal", void 0);
__decorate([
editableInPropertyPage("Dispose on stop", 0 /* PropertyTypeForEdition.Boolean */, "ADVANCED", { embedded: true, notifiers: { rebuild: true } })
], SystemBlock.prototype, "disposeOnStop", void 0);
__decorate([
editableInPropertyPage("Do no start", 0 /* PropertyTypeForEdition.Boolean */, "ADVANCED", { embedded: true, notifiers: { rebuild: true } })
], SystemBlock.prototype, "doNoStart", void 0);
__decorate([
editableInPropertyPage("Rendering group id", 2 /* PropertyTypeForEdition.Int */, "ADVANCED", { embedded: true, notifiers: { rebuild: true }, min: 0 })
], SystemBlock.prototype, "renderingGroupId", void 0);
RegisterClass("BABYLON.SystemBlock", SystemBlock);
//# sourceMappingURL=systemBlock.js.map