@needle-tools/engine
Version:
Needle Engine is a web-based runtime for 3D apps. It runs on your machine for development with great integrations into editors like Unity or Blender - and can be deployed onto any device! It is flexible, extensible and networking and XR are built-in.
112 lines (88 loc) • 3.75 kB
text/typescript
import { Matrix4,Quaternion, Vector3 } from "three";
import { type Behavior, type EmissionState, Matrix4 as QMatrix4,type Particle, type ParticleSystem } from "three.quarks";
import { CircularBuffer } from "../../engine/engine_utils.js";
import { $particleLife, SubEmitterType } from "./ParticleSystem.js";
import type { IParticleSystem } from "./ParticleSystemModules.js";
const VECTOR_ONE = new Vector3(1, 1, 1);
const VECTOR_Z = new Vector3(0, 0, 1);
const $emitterMatrix = Symbol("emitterMatrix");
export class ParticleSubEmitter implements Behavior {
type = "NeedleParticleSubEmitter";
emitterType?: SubEmitterType;
emitterProbability?: number;
//private matrix_ = new Matrix4();
private q_ = new Quaternion();
private v_ = new Vector3();
private v2_ = new Vector3();
private _emitterMatrix: QMatrix4 = new QMatrix4();
private _circularBuffer: CircularBuffer<QMatrix4>;
constructor(
private system: IParticleSystem,
private particleSystem: ParticleSystem,
private subSystem: IParticleSystem,
public subParticleSystem?: ParticleSystem
) {
if (this.subParticleSystem && this.subParticleSystem) {
this.subParticleSystem.onlyUsedByOther = true;
}
const maxMatrices = 1000;
this._circularBuffer = new CircularBuffer(() => new QMatrix4(), maxMatrices)
}
clone(): Behavior {
throw new Error("Method not implemented.");
}
initialize(particle: Particle): void {
particle.emissionState = {
burstIndex: 0,
burstWaveIndex: 0,
time: 0,
waitEmiting: 0,
// matrix: new Matrix4(),
} as EmissionState;
// particle[$emitterMatrix] = new Matrix4();
this._emitterMatrix.copy(this.subSystem.matrixWorld as unknown as QMatrix4).invert().premultiply(this.system.matrixWorld as unknown as QMatrix4);
this._emitterMatrix.setPosition(0, 0, 0);
if (this.emitterType === SubEmitterType.Birth) {
this.run(particle);
}
}
update(particle: Particle, _delta: number): void {
this.run(particle);
}
frameUpdate(_delta: number): void {
}
toJSON(): any {
}
reset() {
}
private run(particle: Particle) {
if (this.subSystem.currentParticles >= this.subSystem.main.maxParticles)
return;
if (!this.subParticleSystem || !particle.emissionState)
return;
if (this.emitterProbability && Math.random() > this.emitterProbability)
return;
const delta = this.system.deltaTime;
if (this.emitterType === SubEmitterType.Death) {
let lifeTime = particle.life;
if (particle[$particleLife] !== undefined) lifeTime = particle[$particleLife];
const willDie = particle.age + delta * 1.2 >= lifeTime;
if (!willDie) return;
// Just emit all for now, we should probably add a way to get the amount from the subsystem emission module
const maxAmount = this.subSystem.main.maxParticles - this.subSystem.currentParticles;
particle.emissionState.waitEmiting = maxAmount;
}
// TODO: figure out how to re-use matrices
const m = new QMatrix4();// this._circularBuffer.get();// new Matrix4();// particle[$emitterMatrix];
m.set(
1, 0, 0, particle.position.x,
0, 1, 0, particle.position.y,
0, 0, 1, particle.position.z,
0, 0, 0, 1
);
if (!this.particleSystem.worldSpace) {
m.multiplyMatrices(this._emitterMatrix, m)
}
this.subParticleSystem!.emit(delta, particle.emissionState!, m);
}
}