Where a particle starts and which way it heads
Implement it for a shape of your own. sample runs once per particle, so allocate in the constructor, never in sample.
sample
class MyRingShape implements EmitterShape { public radius = 2; public sample(rng: () => number, outPos: Vector3, outDir: Vector3): void { const angle = rng() * Math.PI * 2; outPos.set(Math.cos(angle) * this.radius, 0, Math.sin(angle) * this.radius); outDir.set(0, 1, 0); }}const halo = new ParticleSystem3D({ shape: new MyRingShape(), speed: 1 }); Copy
class MyRingShape implements EmitterShape { public radius = 2; public sample(rng: () => number, outPos: Vector3, outDir: Vector3): void { const angle = rng() * Math.PI * 2; outPos.set(Math.cos(angle) * this.radius, 0, Math.sin(angle) * this.radius); outDir.set(0, 1, 0); }}const halo = new ParticleSystem3D({ shape: new MyRingShape(), speed: 1 });
Writes one spawn offset into outPos and a unit direction into outDir
outPos
outDir
The system's random source; use it, not Math.random, so seeded runs replay.
Math.random
Receives the spawn offset, relative to the emitter.
Receives a unit direction.
const preview = new Vector3();const heading = new Vector3();emitter.shape.sample(seededRandom('preview'), preview, heading); Copy
const preview = new Vector3();const heading = new Vector3();emitter.shape.sample(seededRandom('preview'), preview, heading);
Where a particle starts and which way it heads
Implement it for a shape of your own. sample runs once per particle, so allocate in the constructor, never in
sample.Example