playcanvas
Version:
Open-source WebGL/WebGPU 3D engine for the web
156 lines (155 loc) • 5.15 kB
JavaScript
import { Curve } from "../../../core/math/curve.js";
import { CurveSet } from "../../../core/math/curve-set.js";
import { Vec3 } from "../../../core/math/vec3.js";
import { Asset } from "../../asset/asset.js";
import { ComponentSystem } from "../system.js";
import { _properties, ParticleSystemComponent } from "./component.js";
import { particleChunksGLSL } from "../../../scene/shader-lib/glsl/collections/particle-chunks-glsl.js";
import { particleChunksWGSL } from "../../../scene/shader-lib/wgsl/collections/particle-chunks-wgsl.js";
import { SHADERLANGUAGE_GLSL, SHADERLANGUAGE_WGSL } from "../../../platform/graphics/constants.js";
import { ShaderChunks } from "../../../scene/shader-lib/shader-chunks.js";
const _propertyTypes = {
emitterExtents: "vec3",
emitterExtentsInner: "vec3",
particleNormal: "vec3",
wrapBounds: "vec3",
localVelocityGraph: "curveset",
localVelocityGraph2: "curveset",
velocityGraph: "curveset",
velocityGraph2: "curveset",
colorGraph: "curveset",
colorGraph2: "curveset",
alphaGraph: "curve",
alphaGraph2: "curve",
rotationSpeedGraph: "curve",
rotationSpeedGraph2: "curve",
radialSpeedGraph: "curve",
radialSpeedGraph2: "curve",
scaleGraph: "curve",
scaleGraph2: "curve"
};
class ParticleSystemComponentSystem extends ComponentSystem {
constructor(app) {
super(app);
this.id = "particlesystem";
this.ComponentType = ParticleSystemComponent;
this.on("beforeremove", this.onBeforeRemove, this);
this.app.systems.on("update", this.onUpdate, this);
ShaderChunks.get(app.graphicsDevice, SHADERLANGUAGE_GLSL).add(particleChunksGLSL);
ShaderChunks.get(app.graphicsDevice, SHADERLANGUAGE_WGSL).add(particleChunksWGSL);
}
initializeComponentData(component, _data) {
const data = { ..._data };
if (data.mesh instanceof Asset || typeof data.mesh === "number") {
data.meshAsset = data.mesh;
delete data.mesh;
}
for (const prop in data) {
if (data[prop] === void 0 || data[prop] === null) continue;
const type = _propertyTypes[prop];
if (type === "vec3") {
if (Array.isArray(data[prop])) {
data[prop] = new Vec3(data[prop][0], data[prop][1], data[prop][2]);
}
} else if (type === "curve") {
if (!(data[prop] instanceof Curve)) {
const t = data[prop].type;
data[prop] = new Curve(data[prop].keys);
data[prop].type = t;
}
} else if (type === "curveset") {
if (!(data[prop] instanceof CurveSet)) {
const t = data[prop].type;
data[prop] = new CurveSet(data[prop].keys);
data[prop].type = t;
}
}
}
if (data.layers && Array.isArray(data.layers)) {
data.layers = data.layers.slice(0);
}
if (data.enabled !== void 0) {
component._enabled = data.enabled;
}
for (let i = 0; i < _properties.length; i++) {
const property = _properties[i];
if (data[property] !== void 0) {
component[property] = data[property];
}
}
super.initializeComponentData(component, data);
}
cloneComponent(entity, clone) {
const c = entity.particlesystem;
const data = {
enabled: c.enabled
};
for (let i = 0; i < _properties.length; i++) {
const prop = _properties[i];
const value = c[prop];
if (value instanceof Vec3 || value instanceof Curve || value instanceof CurveSet) {
data[prop] = value.clone();
} else if (prop === "layers") {
data.layers = value.slice(0);
} else if (value !== null && value !== void 0) {
data[prop] = value;
}
}
return this.addComponent(clone, data);
}
onUpdate(dt) {
const components = this.store;
const stats = this.app.stats.particles;
const composition = this.app.scene.layers;
for (let i = 0; i < composition.layerList.length; i++) {
composition.layerList[i].requiresLightCube = false;
}
for (const id in components) {
if (components.hasOwnProperty(id)) {
const component = components[id].entity.particlesystem;
const entity = component.entity;
if (component.enabled && entity.enabled) {
const emitter = component.emitter;
if (!emitter?.meshInstance.visible) continue;
if (emitter.lighting) {
const layers = component.layers;
for (let i = 0; i < layers.length; i++) {
const layer = composition.getLayerById(layers[i]);
if (layer) {
layer.requiresLightCube = true;
}
}
}
if (!component._paused) {
let numSteps = 0;
emitter.simTime += dt;
if (emitter.simTime >= emitter.fixedTimeStep) {
numSteps = Math.floor(emitter.simTime / emitter.fixedTimeStep);
emitter.simTime -= numSteps * emitter.fixedTimeStep;
}
if (numSteps) {
numSteps = Math.min(numSteps, emitter.maxSubSteps);
for (let i = 0; i < numSteps; i++) {
emitter.addTime(emitter.fixedTimeStep, false);
}
stats._updatesPerFrame += numSteps;
stats._frameTime += emitter._addTimeTime;
emitter._addTimeTime = 0;
}
emitter.finishFrame();
}
}
}
}
}
onBeforeRemove(entity, component) {
component.onBeforeRemove();
}
destroy() {
super.destroy();
this.app.systems.off("update", this.onUpdate, this);
}
}
export {
ParticleSystemComponentSystem
};