@triforge/particle-core 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/core/BaseEmitter.d.ts +50 -0
- package/dist/core/BaseEmitter.d.ts.map +1 -0
- package/dist/core/BaseEmitter.js +53 -0
- package/dist/core/BaseEmitter.js.map +1 -0
- package/dist/core/BaseForce.d.ts +21 -0
- package/dist/core/BaseForce.d.ts.map +1 -0
- package/dist/core/BaseForce.js +15 -0
- package/dist/core/BaseForce.js.map +1 -0
- package/dist/core/BaseRenderer.d.ts +96 -0
- package/dist/core/BaseRenderer.d.ts.map +1 -0
- package/dist/core/BaseRenderer.js +190 -0
- package/dist/core/BaseRenderer.js.map +1 -0
- package/dist/core/DeflectorCollider.d.ts +46 -0
- package/dist/core/DeflectorCollider.d.ts.map +1 -0
- package/dist/core/DeflectorCollider.js +113 -0
- package/dist/core/DeflectorCollider.js.map +1 -0
- package/dist/core/Particle.d.ts +29 -0
- package/dist/core/Particle.d.ts.map +1 -0
- package/dist/core/Particle.js +41 -0
- package/dist/core/Particle.js.map +1 -0
- package/dist/core/ParticleCache.d.ts +73 -0
- package/dist/core/ParticleCache.d.ts.map +1 -0
- package/dist/core/ParticleCache.js +206 -0
- package/dist/core/ParticleCache.js.map +1 -0
- package/dist/core/ParticleSystem.d.ts +192 -0
- package/dist/core/ParticleSystem.d.ts.map +1 -0
- package/dist/core/ParticleSystem.js +484 -0
- package/dist/core/ParticleSystem.js.map +1 -0
- package/dist/core/SeededRandom.d.ts +17 -0
- package/dist/core/SeededRandom.d.ts.map +1 -0
- package/dist/core/SeededRandom.js +27 -0
- package/dist/core/SeededRandom.js.map +1 -0
- package/dist/emitters/EdgeEmitter.d.ts +43 -0
- package/dist/emitters/EdgeEmitter.d.ts.map +1 -0
- package/dist/emitters/EdgeEmitter.js +78 -0
- package/dist/emitters/EdgeEmitter.js.map +1 -0
- package/dist/emitters/MeshEmitter.d.ts +83 -0
- package/dist/emitters/MeshEmitter.d.ts.map +1 -0
- package/dist/emitters/MeshEmitter.js +240 -0
- package/dist/emitters/MeshEmitter.js.map +1 -0
- package/dist/emitters/PointEmitter.d.ts +22 -0
- package/dist/emitters/PointEmitter.d.ts.map +1 -0
- package/dist/emitters/PointEmitter.js +26 -0
- package/dist/emitters/PointEmitter.js.map +1 -0
- package/dist/forces/BoidField.d.ts +58 -0
- package/dist/forces/BoidField.d.ts.map +1 -0
- package/dist/forces/BoidField.js +82 -0
- package/dist/forces/BoidField.js.map +1 -0
- package/dist/forces/BoidForce.d.ts +54 -0
- package/dist/forces/BoidForce.d.ts.map +1 -0
- package/dist/forces/BoidForce.js +233 -0
- package/dist/forces/BoidForce.js.map +1 -0
- package/dist/forces/ChargeForce.d.ts +22 -0
- package/dist/forces/ChargeForce.d.ts.map +1 -0
- package/dist/forces/ChargeForce.js +35 -0
- package/dist/forces/ChargeForce.js.map +1 -0
- package/dist/forces/CurveGuideForce.d.ts +43 -0
- package/dist/forces/CurveGuideForce.d.ts.map +1 -0
- package/dist/forces/CurveGuideForce.js +118 -0
- package/dist/forces/CurveGuideForce.js.map +1 -0
- package/dist/forces/DragForce.d.ts +19 -0
- package/dist/forces/DragForce.d.ts.map +1 -0
- package/dist/forces/DragForce.js +31 -0
- package/dist/forces/DragForce.js.map +1 -0
- package/dist/forces/FlowFieldForce.d.ts +72 -0
- package/dist/forces/FlowFieldForce.d.ts.map +1 -0
- package/dist/forces/FlowFieldForce.js +68 -0
- package/dist/forces/FlowFieldForce.js.map +1 -0
- package/dist/forces/ForceField.d.ts +26 -0
- package/dist/forces/ForceField.d.ts.map +1 -0
- package/dist/forces/ForceField.js +41 -0
- package/dist/forces/ForceField.js.map +1 -0
- package/dist/forces/GravityForce.d.ts +9 -0
- package/dist/forces/GravityForce.d.ts.map +1 -0
- package/dist/forces/GravityForce.js +12 -0
- package/dist/forces/GravityForce.js.map +1 -0
- package/dist/forces/HarmonicForce.d.ts +22 -0
- package/dist/forces/HarmonicForce.d.ts.map +1 -0
- package/dist/forces/HarmonicForce.js +31 -0
- package/dist/forces/HarmonicForce.js.map +1 -0
- package/dist/forces/LennardJonesForce.d.ts +23 -0
- package/dist/forces/LennardJonesForce.d.ts.map +1 -0
- package/dist/forces/LennardJonesForce.js +38 -0
- package/dist/forces/LennardJonesForce.js.map +1 -0
- package/dist/forces/MagneticForce.d.ts +21 -0
- package/dist/forces/MagneticForce.d.ts.map +1 -0
- package/dist/forces/MagneticForce.js +30 -0
- package/dist/forces/MagneticForce.js.map +1 -0
- package/dist/forces/TextureForce.d.ts +37 -0
- package/dist/forces/TextureForce.d.ts.map +1 -0
- package/dist/forces/TextureForce.js +56 -0
- package/dist/forces/TextureForce.js.map +1 -0
- package/dist/forces/TurbulenceForce.d.ts +21 -0
- package/dist/forces/TurbulenceForce.d.ts.map +1 -0
- package/dist/forces/TurbulenceForce.js +39 -0
- package/dist/forces/TurbulenceForce.js.map +1 -0
- package/dist/forces/VortexForce.d.ts +21 -0
- package/dist/forces/VortexForce.d.ts.map +1 -0
- package/dist/forces/VortexForce.js +29 -0
- package/dist/forces/VortexForce.js.map +1 -0
- package/dist/forces/WindForce.d.ts +21 -0
- package/dist/forces/WindForce.d.ts.map +1 -0
- package/dist/forces/WindForce.js +29 -0
- package/dist/forces/WindForce.js.map +1 -0
- package/dist/index.d.ts +56 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +44 -0
- package/dist/index.js.map +1 -0
- package/dist/physics/KeyedPhysics.d.ts +43 -0
- package/dist/physics/KeyedPhysics.d.ts.map +1 -0
- package/dist/physics/KeyedPhysics.js +73 -0
- package/dist/physics/KeyedPhysics.js.map +1 -0
- package/dist/physics/SPHPhysics.d.ts +27 -0
- package/dist/physics/SPHPhysics.d.ts.map +1 -0
- package/dist/physics/SPHPhysics.js +119 -0
- package/dist/physics/SPHPhysics.js.map +1 -0
- package/dist/renderers/BillboardRenderer.d.ts +75 -0
- package/dist/renderers/BillboardRenderer.d.ts.map +1 -0
- package/dist/renderers/BillboardRenderer.js +106 -0
- package/dist/renderers/BillboardRenderer.js.map +1 -0
- package/dist/renderers/CollectionRenderer.d.ts +83 -0
- package/dist/renderers/CollectionRenderer.d.ts.map +1 -0
- package/dist/renderers/CollectionRenderer.js +161 -0
- package/dist/renderers/CollectionRenderer.js.map +1 -0
- package/dist/renderers/HaloRenderer.d.ts +3 -0
- package/dist/renderers/HaloRenderer.d.ts.map +1 -0
- package/dist/renderers/HaloRenderer.js +4 -0
- package/dist/renderers/HaloRenderer.js.map +1 -0
- package/dist/renderers/InstanceRenderer.d.ts +70 -0
- package/dist/renderers/InstanceRenderer.d.ts.map +1 -0
- package/dist/renderers/InstanceRenderer.js +86 -0
- package/dist/renderers/InstanceRenderer.js.map +1 -0
- package/dist/renderers/LineRenderer.d.ts +52 -0
- package/dist/renderers/LineRenderer.d.ts.map +1 -0
- package/dist/renderers/LineRenderer.js +96 -0
- package/dist/renderers/LineRenderer.js.map +1 -0
- package/dist/renderers/NoneRenderer.d.ts +19 -0
- package/dist/renderers/NoneRenderer.d.ts.map +1 -0
- package/dist/renderers/NoneRenderer.js +24 -0
- package/dist/renderers/NoneRenderer.js.map +1 -0
- package/dist/renderers/ObjectRenderer.d.ts +3 -0
- package/dist/renderers/ObjectRenderer.d.ts.map +1 -0
- package/dist/renderers/ObjectRenderer.js +4 -0
- package/dist/renderers/ObjectRenderer.js.map +1 -0
- package/dist/renderers/StrandRenderer.d.ts +169 -0
- package/dist/renderers/StrandRenderer.d.ts.map +1 -0
- package/dist/renderers/StrandRenderer.js +235 -0
- package/dist/renderers/StrandRenderer.js.map +1 -0
- package/dist/renderers/TrailRenderer.d.ts +54 -0
- package/dist/renderers/TrailRenderer.d.ts.map +1 -0
- package/dist/renderers/TrailRenderer.js +114 -0
- package/dist/renderers/TrailRenderer.js.map +1 -0
- package/package.json +45 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { Points, BufferGeometry, BufferAttribute, PointsMaterial, AdditiveBlending, NormalBlending, Color, } from 'three';
|
|
2
|
+
import { BaseRenderer } from '../core/BaseRenderer.js';
|
|
3
|
+
/**
|
|
4
|
+
* BillboardRenderer — renders particles as camera-facing point sprites.
|
|
5
|
+
* Uses THREE.Points for GPU-efficient batched rendering.
|
|
6
|
+
* (Blender: Render → Halo / Billboard)
|
|
7
|
+
*
|
|
8
|
+
* No allocations inside update() — all buffers are pre-allocated.
|
|
9
|
+
*/
|
|
10
|
+
export class BillboardRenderer extends BaseRenderer {
|
|
11
|
+
constructor(opts = {}) {
|
|
12
|
+
super();
|
|
13
|
+
const max = opts.maxCount ?? 10000;
|
|
14
|
+
this._maxCount = max;
|
|
15
|
+
const low = opts.colourLow ?? [1, 0, 0];
|
|
16
|
+
const high = opts.colourHigh ?? [0, 0, 1];
|
|
17
|
+
this.parameters = {
|
|
18
|
+
fadeOut: (opts.fadeOut ?? true) ? 1 : 0,
|
|
19
|
+
opacity: opts.opacity ?? 1,
|
|
20
|
+
size: 0.5,
|
|
21
|
+
colourMode: opts.colourMode ?? 0,
|
|
22
|
+
colourLowR: low[0], colourLowG: low[1], colourLowB: low[2],
|
|
23
|
+
colourHighR: high[0], colourHighG: high[1], colourHighB: high[2],
|
|
24
|
+
velocityMax: opts.velocityMax ?? 10,
|
|
25
|
+
};
|
|
26
|
+
this._positions = new Float32Array(max * 3);
|
|
27
|
+
this._sizes = new Float32Array(max);
|
|
28
|
+
this._colors = new Float32Array(max * 3);
|
|
29
|
+
const geo = new BufferGeometry();
|
|
30
|
+
this._posAttr = new BufferAttribute(this._positions, 3).setUsage(35048); // DYNAMIC_DRAW
|
|
31
|
+
this._sizeAttr = new BufferAttribute(this._sizes, 1).setUsage(35048);
|
|
32
|
+
this._colorAttr = new BufferAttribute(this._colors, 3).setUsage(35048);
|
|
33
|
+
geo.setAttribute('position', this._posAttr);
|
|
34
|
+
geo.setAttribute('size', this._sizeAttr);
|
|
35
|
+
geo.setAttribute('color', this._colorAttr);
|
|
36
|
+
geo.setDrawRange(0, 0);
|
|
37
|
+
const mat = new PointsMaterial({
|
|
38
|
+
color: new Color(opts.color ?? 0xffffff),
|
|
39
|
+
map: opts.map ?? null,
|
|
40
|
+
opacity: this.parameters.opacity,
|
|
41
|
+
transparent: true,
|
|
42
|
+
depthWrite: false,
|
|
43
|
+
blending: opts.additive ? AdditiveBlending : NormalBlending,
|
|
44
|
+
sizeAttenuation: opts.sizeAttenuation ?? true,
|
|
45
|
+
size: 0.5, // world-space size — updated each frame from particle pool
|
|
46
|
+
alphaTest: 0.01,
|
|
47
|
+
});
|
|
48
|
+
this.object3D = new Points(geo, mat);
|
|
49
|
+
this.object3D.frustumCulled = false;
|
|
50
|
+
this.object3D.visible = opts.showHelpers ?? true;
|
|
51
|
+
// Pre-allocate draw buffer for child expansion
|
|
52
|
+
this._allocDrawBuf(max);
|
|
53
|
+
}
|
|
54
|
+
update(particles, aliveCount, params, childRng) {
|
|
55
|
+
const childCount = params ? Math.round(Math.max(0, params.childCount ?? 0)) : 0;
|
|
56
|
+
const childType = params ? Math.round(params.childType ?? 0) : 0;
|
|
57
|
+
const childSpread = params ? (params.childSpread ?? 0.5) : 0.5;
|
|
58
|
+
const rawCount = this.expandWithChildren(particles, aliveCount, childCount, childType, childSpread, childRng ?? null, this._maxCount);
|
|
59
|
+
const displayAmount = params ? Math.min(1, Math.max(0, params.displayAmount ?? 1)) : 1;
|
|
60
|
+
const drawCount = displayAmount >= 1 ? rawCount : Math.round(rawCount * displayAmount);
|
|
61
|
+
const pr = this.parameters;
|
|
62
|
+
const fadeOut = pr.fadeOut >= 0.5;
|
|
63
|
+
const mode = Math.round(pr.colourMode);
|
|
64
|
+
let avgSize = 0;
|
|
65
|
+
for (let i = 0; i < drawCount; i++) {
|
|
66
|
+
const p = this._drawBuf[i];
|
|
67
|
+
const i3 = i * 3;
|
|
68
|
+
this._positions[i3] = p.position.x;
|
|
69
|
+
this._positions[i3 + 1] = p.position.y;
|
|
70
|
+
this._positions[i3 + 2] = p.position.z;
|
|
71
|
+
const s = p.size * (fadeOut ? 1 - p.normalised : 1);
|
|
72
|
+
this._sizes[i] = s;
|
|
73
|
+
avgSize += s;
|
|
74
|
+
if (mode > 0) {
|
|
75
|
+
let t;
|
|
76
|
+
if (mode === 1) {
|
|
77
|
+
const spd = Math.sqrt(p.velocity.x * p.velocity.x +
|
|
78
|
+
p.velocity.y * p.velocity.y +
|
|
79
|
+
p.velocity.z * p.velocity.z);
|
|
80
|
+
t = Math.min(1, spd / Math.max(pr.velocityMax, 0.0001));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
t = p.normalised;
|
|
84
|
+
}
|
|
85
|
+
this._colors[i3] = pr.colourLowR + (pr.colourHighR - pr.colourLowR) * t;
|
|
86
|
+
this._colors[i3 + 1] = pr.colourLowG + (pr.colourHighG - pr.colourLowG) * t;
|
|
87
|
+
this._colors[i3 + 2] = pr.colourLowB + (pr.colourHighB - pr.colourLowB) * t;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
const mat = this.object3D.material;
|
|
91
|
+
mat.opacity = pr.opacity;
|
|
92
|
+
mat.vertexColors = mode > 0;
|
|
93
|
+
if (drawCount > 0)
|
|
94
|
+
mat.size = avgSize / drawCount;
|
|
95
|
+
this._posAttr.needsUpdate = true;
|
|
96
|
+
this._sizeAttr.needsUpdate = true;
|
|
97
|
+
if (mode > 0)
|
|
98
|
+
this._colorAttr.needsUpdate = true;
|
|
99
|
+
this.object3D.geometry.setDrawRange(0, drawCount);
|
|
100
|
+
}
|
|
101
|
+
dispose() {
|
|
102
|
+
this.object3D.geometry.dispose();
|
|
103
|
+
this.object3D.material.dispose();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=BillboardRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BillboardRenderer.js","sourceRoot":"","sources":["../../src/renderers/BillboardRenderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { Group, BufferGeometry, Material, Camera } from 'three';
|
|
2
|
+
import { BaseRenderer } from '../core/BaseRenderer.js';
|
|
3
|
+
import type { ParticleLike } from '../core/BaseRenderer.js';
|
|
4
|
+
import type { SeededRandom } from '../core/SeededRandom.js';
|
|
5
|
+
export interface CollectionMesh {
|
|
6
|
+
geometry: BufferGeometry;
|
|
7
|
+
material: Material;
|
|
8
|
+
}
|
|
9
|
+
export interface CollectionRendererOptions {
|
|
10
|
+
/** Array of mesh configs — each particle is randomly assigned to one. */
|
|
11
|
+
meshes: CollectionMesh[];
|
|
12
|
+
/** Pool size — must match or exceed ParticleSystem.count. Default 1000. */
|
|
13
|
+
maxCount?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Rotate each instance to face the camera.
|
|
16
|
+
* Blender: Render → Collection with "Face Camera" orientation. Default: true.
|
|
17
|
+
*/
|
|
18
|
+
billboard?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Shrink each instance to scale 0 over its lifetime. Default: true.
|
|
21
|
+
*/
|
|
22
|
+
fadeOut?: boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Shifts random mesh assignment — different seeds give different distributions.
|
|
25
|
+
* Default: 0.
|
|
26
|
+
*/
|
|
27
|
+
seed?: number;
|
|
28
|
+
/**
|
|
29
|
+
* Relative spawn probability for each mesh (Blender: Render → Collection → Dupliweights).
|
|
30
|
+
* Length must match meshes.length. Values are normalised internally — [1,1,2] means
|
|
31
|
+
* mesh 0 and 1 each get 25%, mesh 2 gets 50%. Omit for uniform distribution.
|
|
32
|
+
*/
|
|
33
|
+
weights?: number[];
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* CollectionRenderer — picks randomly from a list of meshes and instances each group.
|
|
37
|
+
* (Blender: Render → Collection)
|
|
38
|
+
*
|
|
39
|
+
* Creates one THREE.InstancedMesh per collection entry, bundled in a THREE.Group.
|
|
40
|
+
* Assignment uses poolIdx so children of a parent always get the same mesh variant
|
|
41
|
+
* as their parent — stable across frames.
|
|
42
|
+
*
|
|
43
|
+
* No allocations inside update() — all temporaries are pre-allocated.
|
|
44
|
+
*/
|
|
45
|
+
export declare class CollectionRenderer extends BaseRenderer {
|
|
46
|
+
readonly object3D: Group;
|
|
47
|
+
/**
|
|
48
|
+
* Scalar inputs — safe to animate with GSAP or the keyframe system.
|
|
49
|
+
* fadeOut: 1 = shrink to 0 over lifetime, 0 = constant size.
|
|
50
|
+
* billboard: 1 = face camera, 0 = use particle rotation.
|
|
51
|
+
* seed: integer offset for mesh assignment.
|
|
52
|
+
* weight0…N: per-mesh relative weights (Blender: Dupliweights).
|
|
53
|
+
* Changing these at runtime calls _rebuildCDF() on the next update().
|
|
54
|
+
*/
|
|
55
|
+
parameters: Record<string, number>;
|
|
56
|
+
/** Set this to your active camera when billboard is 1 (the default). */
|
|
57
|
+
camera: Camera | null;
|
|
58
|
+
private readonly _instances;
|
|
59
|
+
private readonly _counts;
|
|
60
|
+
private readonly _prevCounts;
|
|
61
|
+
private readonly _matrix;
|
|
62
|
+
private readonly _pos;
|
|
63
|
+
private readonly _quat;
|
|
64
|
+
private readonly _camQuat;
|
|
65
|
+
private readonly _euler;
|
|
66
|
+
private readonly _scale;
|
|
67
|
+
private readonly _zeroMat;
|
|
68
|
+
private _maxCount;
|
|
69
|
+
/** Cumulative distribution function for weighted mesh selection. */
|
|
70
|
+
private _cdf;
|
|
71
|
+
/** Snapshot of weight keys at last CDF build — used to detect runtime changes. */
|
|
72
|
+
private _weightDigest;
|
|
73
|
+
constructor(opts: CollectionRendererOptions);
|
|
74
|
+
update(particles: ParticleLike[], aliveCount: number, params?: Record<string, number>, childRng?: SeededRandom): void;
|
|
75
|
+
/** Rebuild the CDF from current weight0…weightN parameters. */
|
|
76
|
+
private _rebuildCDF;
|
|
77
|
+
/** Sample the CDF with r ∈ [0,1) → mesh index. */
|
|
78
|
+
private _cdfSample;
|
|
79
|
+
/** Fast digest of current weight values — used to detect runtime changes. */
|
|
80
|
+
private _weightDigest_;
|
|
81
|
+
dispose(): void;
|
|
82
|
+
}
|
|
83
|
+
//# sourceMappingURL=CollectionRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CollectionRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/CollectionRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,EAAiB,cAAc,EAAE,QAAQ,EACT,MAAM,EAC5C,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAY,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAE5D,MAAM,WAAW,cAAc;IAC7B,QAAQ,EAAE,cAAc,CAAA;IACxB,QAAQ,EAAG,QAAQ,CAAA;CACpB;AAED,MAAM,WAAW,yBAAyB;IACxC,yEAAyE;IACzE,MAAM,EAAM,cAAc,EAAE,CAAA;IAC5B,2EAA2E;IAC3E,QAAQ,CAAC,EAAG,MAAM,CAAA;IAClB;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;OAEG;IACH,OAAO,CAAC,EAAI,OAAO,CAAA;IACnB;;;OAGG;IACH,IAAI,CAAC,EAAO,MAAM,CAAA;IAClB;;;;OAIG;IACH,OAAO,CAAC,EAAI,MAAM,EAAE,CAAA;CACrB;AAED;;;;;;;;;GASG;AACH,qBAAa,kBAAmB,SAAQ,YAAY;IAClD,QAAQ,CAAC,QAAQ,EAAE,KAAK,CAAA;IAExB;;;;;;;OAOG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAElC,wEAAwE;IACxE,MAAM,EAAE,MAAM,GAAG,IAAI,CAAO;IAE5B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAkB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAY;IACxC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IACxD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkD;IAC3E,OAAO,CAAC,SAAS,CAAQ;IACzB,oEAAoE;IACpE,OAAO,CAAC,IAAI,CAAuB;IACnC,kFAAkF;IAClF,OAAO,CAAC,aAAa,CAAQ;gBAEjB,IAAI,EAAE,yBAAyB;IAyC3C,MAAM,CACJ,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,QAAQ,CAAC,EAAG,YAAY,GACvB,IAAI;IAwEP,+DAA+D;IAC/D,OAAO,CAAC,WAAW;IAgBnB,kDAAkD;IAClD,OAAO,CAAC,UAAU;IAQlB,6EAA6E;IAC7E,OAAO,CAAC,cAAc;IAUtB,OAAO,IAAI,IAAI;CAMhB"}
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { Group, InstancedMesh, Matrix4, Quaternion, Vector3, Euler, } from 'three';
|
|
2
|
+
import { BaseRenderer } from '../core/BaseRenderer.js';
|
|
3
|
+
/**
|
|
4
|
+
* CollectionRenderer — picks randomly from a list of meshes and instances each group.
|
|
5
|
+
* (Blender: Render → Collection)
|
|
6
|
+
*
|
|
7
|
+
* Creates one THREE.InstancedMesh per collection entry, bundled in a THREE.Group.
|
|
8
|
+
* Assignment uses poolIdx so children of a parent always get the same mesh variant
|
|
9
|
+
* as their parent — stable across frames.
|
|
10
|
+
*
|
|
11
|
+
* No allocations inside update() — all temporaries are pre-allocated.
|
|
12
|
+
*/
|
|
13
|
+
export class CollectionRenderer extends BaseRenderer {
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
super();
|
|
16
|
+
/** Set this to your active camera when billboard is 1 (the default). */
|
|
17
|
+
this.camera = null;
|
|
18
|
+
this._matrix = new Matrix4();
|
|
19
|
+
this._pos = new Vector3();
|
|
20
|
+
this._quat = new Quaternion();
|
|
21
|
+
this._camQuat = new Quaternion();
|
|
22
|
+
this._euler = new Euler();
|
|
23
|
+
this._scale = new Vector3();
|
|
24
|
+
this._zeroMat = new Matrix4().makeScale(0, 0, 0);
|
|
25
|
+
const max = opts.maxCount ?? 1000;
|
|
26
|
+
this._maxCount = max;
|
|
27
|
+
const weightParams = {};
|
|
28
|
+
const n = opts.meshes.length;
|
|
29
|
+
for (let i = 0; i < n; i++) {
|
|
30
|
+
weightParams[`weight${i}`] = opts.weights?.[i] ?? 1;
|
|
31
|
+
}
|
|
32
|
+
this.parameters = {
|
|
33
|
+
billboard: (opts.billboard ?? true) ? 1 : 0,
|
|
34
|
+
fadeOut: (opts.fadeOut ?? true) ? 1 : 0,
|
|
35
|
+
seed: opts.seed ?? 0,
|
|
36
|
+
...weightParams,
|
|
37
|
+
};
|
|
38
|
+
this._cdf = new Float64Array(n);
|
|
39
|
+
this._weightDigest = -1; // force CDF build on first update
|
|
40
|
+
this._rebuildCDF();
|
|
41
|
+
this.object3D = new Group();
|
|
42
|
+
this.object3D.frustumCulled = false;
|
|
43
|
+
this._instances = opts.meshes.map(m => {
|
|
44
|
+
const mesh = new InstancedMesh(m.geometry, m.material, max);
|
|
45
|
+
mesh.frustumCulled = false;
|
|
46
|
+
mesh.count = 0;
|
|
47
|
+
for (let i = 0; i < max; i++)
|
|
48
|
+
mesh.setMatrixAt(i, this._zeroMat);
|
|
49
|
+
mesh.instanceMatrix.needsUpdate = true;
|
|
50
|
+
this.object3D.add(mesh);
|
|
51
|
+
return mesh;
|
|
52
|
+
});
|
|
53
|
+
this._counts = new Int32Array(n);
|
|
54
|
+
this._prevCounts = new Int32Array(n);
|
|
55
|
+
this._allocDrawBuf(max);
|
|
56
|
+
}
|
|
57
|
+
update(particles, aliveCount, params, childRng) {
|
|
58
|
+
const n = this._instances.length;
|
|
59
|
+
if (n === 0)
|
|
60
|
+
return;
|
|
61
|
+
const childCount = params ? Math.round(Math.max(0, params.childCount ?? 0)) : 0;
|
|
62
|
+
const childType = params ? Math.round(params.childType ?? 0) : 0;
|
|
63
|
+
const childSpread = params ? (params.childSpread ?? 0.5) : 0.5;
|
|
64
|
+
const rawCount = this.expandWithChildren(particles, aliveCount, childCount, childType, childSpread, childRng ?? null, this._maxCount);
|
|
65
|
+
const displayAmount = params ? Math.min(1, Math.max(0, params.displayAmount ?? 1)) : 1;
|
|
66
|
+
const drawCount = displayAmount >= 1 ? rawCount : Math.round(rawCount * displayAmount);
|
|
67
|
+
const billboard = this.parameters.billboard >= 0.5;
|
|
68
|
+
const fadeOut = this.parameters.fadeOut >= 0.5;
|
|
69
|
+
const seed = Math.floor(Math.abs(this.parameters.seed));
|
|
70
|
+
if (billboard && this.camera) {
|
|
71
|
+
this.camera.getWorldQuaternion(this._camQuat);
|
|
72
|
+
}
|
|
73
|
+
// Rebuild CDF if any weight parameter changed since last frame
|
|
74
|
+
const digest = this._weightDigest_(n);
|
|
75
|
+
if (digest !== this._weightDigest) {
|
|
76
|
+
this._rebuildCDF();
|
|
77
|
+
this._weightDigest = digest;
|
|
78
|
+
}
|
|
79
|
+
// Reset per-mesh write cursors
|
|
80
|
+
for (let i = 0; i < n; i++)
|
|
81
|
+
this._counts[i] = 0;
|
|
82
|
+
for (let di = 0; di < drawCount; di++) {
|
|
83
|
+
const d = this._drawBuf[di];
|
|
84
|
+
// Use parent's pool index for stable, deterministic mesh assignment.
|
|
85
|
+
// Mix seed into a cheap hash so seed shifts the distribution without
|
|
86
|
+
// breaking the per-particle stability guarantee.
|
|
87
|
+
const hash = (d.poolIdx * 2654435761 + seed * 40503) >>> 0;
|
|
88
|
+
const r = (hash & 0xFFFF) / 65536; // [0,1)
|
|
89
|
+
const mi = this._cdfSample(r);
|
|
90
|
+
const slot = this._counts[mi];
|
|
91
|
+
const s = d.size * (fadeOut ? 1 - d.normalised : 1);
|
|
92
|
+
this._pos.set(d.position.x, d.position.y, d.position.z);
|
|
93
|
+
this._scale.setScalar(Math.max(s, 0));
|
|
94
|
+
if (billboard && this.camera) {
|
|
95
|
+
this._matrix.compose(this._pos, this._camQuat, this._scale);
|
|
96
|
+
}
|
|
97
|
+
else {
|
|
98
|
+
this._euler.set(d.rotation.x, d.rotation.y, d.rotation.z);
|
|
99
|
+
this._quat.setFromEuler(this._euler);
|
|
100
|
+
this._matrix.compose(this._pos, this._quat, this._scale);
|
|
101
|
+
}
|
|
102
|
+
this._instances[mi].setMatrixAt(slot, this._matrix);
|
|
103
|
+
this._counts[mi]++;
|
|
104
|
+
}
|
|
105
|
+
for (let i = 0; i < n; i++) {
|
|
106
|
+
const mesh = this._instances[i];
|
|
107
|
+
// Zero slots that were alive last frame but aren't now
|
|
108
|
+
for (let j = this._counts[i]; j < this._prevCounts[i]; j++) {
|
|
109
|
+
mesh.setMatrixAt(j, this._zeroMat);
|
|
110
|
+
}
|
|
111
|
+
this._prevCounts[i] = this._counts[i];
|
|
112
|
+
mesh.count = this._counts[i];
|
|
113
|
+
mesh.instanceMatrix.needsUpdate = true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
/** Rebuild the CDF from current weight0…weightN parameters. */
|
|
117
|
+
_rebuildCDF() {
|
|
118
|
+
const n = this._cdf.length;
|
|
119
|
+
let sum = 0;
|
|
120
|
+
for (let i = 0; i < n; i++) {
|
|
121
|
+
const w = Math.max(0, this.parameters[`weight${i}`] ?? 1);
|
|
122
|
+
sum += w;
|
|
123
|
+
this._cdf[i] = sum;
|
|
124
|
+
}
|
|
125
|
+
if (sum > 0) {
|
|
126
|
+
for (let i = 0; i < n; i++)
|
|
127
|
+
this._cdf[i] /= sum;
|
|
128
|
+
}
|
|
129
|
+
else {
|
|
130
|
+
// All zero weights → uniform fallback
|
|
131
|
+
for (let i = 0; i < n; i++)
|
|
132
|
+
this._cdf[i] = (i + 1) / n;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
/** Sample the CDF with r ∈ [0,1) → mesh index. */
|
|
136
|
+
_cdfSample(r) {
|
|
137
|
+
const n = this._cdf.length;
|
|
138
|
+
for (let i = 0; i < n; i++) {
|
|
139
|
+
if (r < this._cdf[i])
|
|
140
|
+
return i;
|
|
141
|
+
}
|
|
142
|
+
return n - 1;
|
|
143
|
+
}
|
|
144
|
+
/** Fast digest of current weight values — used to detect runtime changes. */
|
|
145
|
+
_weightDigest_(n) {
|
|
146
|
+
let h = 0;
|
|
147
|
+
for (let i = 0; i < n; i++) {
|
|
148
|
+
const w = this.parameters[`weight${i}`] ?? 1;
|
|
149
|
+
// FNV-1a inspired mix
|
|
150
|
+
h = ((h ^ Math.round(w * 1000)) * 16777619) >>> 0;
|
|
151
|
+
}
|
|
152
|
+
return h;
|
|
153
|
+
}
|
|
154
|
+
dispose() {
|
|
155
|
+
for (const mesh of this._instances) {
|
|
156
|
+
mesh.geometry.dispose();
|
|
157
|
+
mesh.material.dispose();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=CollectionRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CollectionRenderer.js","sourceRoot":"","sources":["../../src/renderers/CollectionRenderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HaloRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/HaloRenderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,iBAAiB,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAA;AAC1E,YAAY,EAAE,wBAAwB,IAAI,mBAAmB,EAAE,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HaloRenderer.js","sourceRoot":"","sources":["../../src/renderers/HaloRenderer.ts"],"names":[],"mappings":"AAAA,wDAAwD;AACxD,2EAA2E;AAC3E,OAAO,EAAE,iBAAiB,IAAI,YAAY,EAAE,MAAM,wBAAwB,CAAA"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { InstancedMesh, BufferGeometry, Material, Camera } from 'three';
|
|
2
|
+
import { BaseRenderer } from '../core/BaseRenderer.js';
|
|
3
|
+
import type { ParticleLike } from '../core/BaseRenderer.js';
|
|
4
|
+
import type { SeededRandom } from '../core/SeededRandom.js';
|
|
5
|
+
export interface InstanceRendererOptions {
|
|
6
|
+
/** Geometry stamped at every particle position */
|
|
7
|
+
geometry: BufferGeometry;
|
|
8
|
+
/** Any Three.js material — including compiled shader node graphs */
|
|
9
|
+
material: Material;
|
|
10
|
+
/** Pool size — must match or exceed ParticleSystem.count */
|
|
11
|
+
maxCount?: number;
|
|
12
|
+
/**
|
|
13
|
+
* Rotate each instance to face the camera.
|
|
14
|
+
* Essential for flat foam/splash meshes — without this they render edge-on.
|
|
15
|
+
* Blender: Render → Object with "Face Camera" orientation.
|
|
16
|
+
* Default: true.
|
|
17
|
+
*/
|
|
18
|
+
billboard?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Shrink the instance scale to 0 over its lifetime.
|
|
21
|
+
* Simulates a fade when the material has no transparency.
|
|
22
|
+
* Default: true.
|
|
23
|
+
*/
|
|
24
|
+
fadeOut?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Show instances on startup.
|
|
27
|
+
* Mirrors Blender's viewport display toggle. Default: true.
|
|
28
|
+
*/
|
|
29
|
+
showHelpers?: boolean;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* InstanceRenderer — renders each particle as a full mesh instance.
|
|
33
|
+
* Uses THREE.InstancedMesh — one draw call regardless of particle count.
|
|
34
|
+
* Blender parallel: Particle System → Render → Object / Collection.
|
|
35
|
+
*
|
|
36
|
+
* Assign any material here, including a compiled @st-shader-core node graph,
|
|
37
|
+
* to get full PBR shading on every particle.
|
|
38
|
+
*
|
|
39
|
+
* No allocations inside update() — all temporaries are pre-allocated.
|
|
40
|
+
*/
|
|
41
|
+
export declare class InstanceRenderer extends BaseRenderer {
|
|
42
|
+
readonly object3D: InstancedMesh;
|
|
43
|
+
/**
|
|
44
|
+
* Scalar inputs — safe to animate with GSAP or the keyframe system.
|
|
45
|
+
* fadeOut: 1 = shrink to 0 over lifetime, 0 = constant size.
|
|
46
|
+
* billboard: 1 = face camera, 0 = use particle rotation.
|
|
47
|
+
*/
|
|
48
|
+
parameters: {
|
|
49
|
+
fadeOut: number;
|
|
50
|
+
billboard: number;
|
|
51
|
+
};
|
|
52
|
+
/**
|
|
53
|
+
* Set this to your active camera to enable billboard alignment.
|
|
54
|
+
* Required when billboard: 1 (the default).
|
|
55
|
+
*/
|
|
56
|
+
camera: Camera | null;
|
|
57
|
+
private readonly _matrix;
|
|
58
|
+
private readonly _pos;
|
|
59
|
+
private readonly _quat;
|
|
60
|
+
private readonly _camQuat;
|
|
61
|
+
private readonly _euler;
|
|
62
|
+
private readonly _scale;
|
|
63
|
+
private readonly _zeroMatrix;
|
|
64
|
+
private _prevCount;
|
|
65
|
+
private _maxCount;
|
|
66
|
+
constructor(opts: InstanceRendererOptions);
|
|
67
|
+
update(particles: ParticleLike[], aliveCount: number, params?: Record<string, number>, childRng?: SeededRandom): void;
|
|
68
|
+
dispose(): void;
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=InstanceRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InstanceRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/InstanceRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EAAE,cAAc,EAAE,QAAQ,EACF,MAAM,EAC5C,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAY,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAE5D,MAAM,WAAW,uBAAuB;IACtC,kDAAkD;IAClD,QAAQ,EAAI,cAAc,CAAA;IAC1B,oEAAoE;IACpE,QAAQ,EAAI,QAAQ,CAAA;IACpB,4DAA4D;IAC5D,QAAQ,CAAC,EAAG,MAAM,CAAA;IAClB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;IACnB;;;;OAIG;IACH,OAAO,CAAC,EAAI,OAAO,CAAA;IACnB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB;AAED;;;;;;;;;GASG;AACH,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;IAEhC;;;;OAIG;IACH,UAAU,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAA;IAElD;;;OAGG;IACH,MAAM,EAAE,MAAM,GAAG,IAAI,CAAO;IAC5B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgC;IACxD,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IACxD,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAqC;IAC3D,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAC3D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA+B;IACtD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiC;IACxD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAA+C;IAC3E,OAAO,CAAC,UAAU,CAAY;IAC9B,OAAO,CAAC,SAAS,CAAS;gBAEd,IAAI,EAAE,uBAAuB;IAuBzC,MAAM,CACJ,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,QAAQ,CAAC,EAAG,YAAY,GACvB,IAAI;IA8CP,OAAO,IAAI,IAAI;CAIhB"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { InstancedMesh, Matrix4, Quaternion, Vector3, Euler, } from 'three';
|
|
2
|
+
import { BaseRenderer } from '../core/BaseRenderer.js';
|
|
3
|
+
/**
|
|
4
|
+
* InstanceRenderer — renders each particle as a full mesh instance.
|
|
5
|
+
* Uses THREE.InstancedMesh — one draw call regardless of particle count.
|
|
6
|
+
* Blender parallel: Particle System → Render → Object / Collection.
|
|
7
|
+
*
|
|
8
|
+
* Assign any material here, including a compiled @st-shader-core node graph,
|
|
9
|
+
* to get full PBR shading on every particle.
|
|
10
|
+
*
|
|
11
|
+
* No allocations inside update() — all temporaries are pre-allocated.
|
|
12
|
+
*/
|
|
13
|
+
export class InstanceRenderer extends BaseRenderer {
|
|
14
|
+
constructor(opts) {
|
|
15
|
+
super();
|
|
16
|
+
/**
|
|
17
|
+
* Set this to your active camera to enable billboard alignment.
|
|
18
|
+
* Required when billboard: 1 (the default).
|
|
19
|
+
*/
|
|
20
|
+
this.camera = null;
|
|
21
|
+
this._matrix = new Matrix4();
|
|
22
|
+
this._pos = new Vector3();
|
|
23
|
+
this._quat = new Quaternion();
|
|
24
|
+
this._camQuat = new Quaternion();
|
|
25
|
+
this._euler = new Euler();
|
|
26
|
+
this._scale = new Vector3();
|
|
27
|
+
this._zeroMatrix = new Matrix4().makeScale(0, 0, 0);
|
|
28
|
+
this._prevCount = 0;
|
|
29
|
+
const max = opts.maxCount ?? 1000;
|
|
30
|
+
this._maxCount = max;
|
|
31
|
+
this.parameters = {
|
|
32
|
+
billboard: (opts.billboard ?? true) ? 1 : 0,
|
|
33
|
+
fadeOut: (opts.fadeOut ?? true) ? 1 : 0,
|
|
34
|
+
};
|
|
35
|
+
this.object3D = new InstancedMesh(opts.geometry, opts.material, max);
|
|
36
|
+
this.object3D.frustumCulled = false;
|
|
37
|
+
this.object3D.count = 0;
|
|
38
|
+
this.object3D.visible = opts.showHelpers ?? true;
|
|
39
|
+
// Pre-zero all slots so no stale instances flash on first frame
|
|
40
|
+
for (let i = 0; i < max; i++) {
|
|
41
|
+
this.object3D.setMatrixAt(i, this._zeroMatrix);
|
|
42
|
+
}
|
|
43
|
+
this.object3D.instanceMatrix.needsUpdate = true;
|
|
44
|
+
this._allocDrawBuf(max);
|
|
45
|
+
}
|
|
46
|
+
update(particles, aliveCount, params, childRng) {
|
|
47
|
+
const childCount = params ? Math.round(Math.max(0, params.childCount ?? 0)) : 0;
|
|
48
|
+
const childType = params ? Math.round(params.childType ?? 0) : 0;
|
|
49
|
+
const childSpread = params ? (params.childSpread ?? 0.5) : 0.5;
|
|
50
|
+
const rawCount = this.expandWithChildren(particles, aliveCount, childCount, childType, childSpread, childRng ?? null, this._maxCount);
|
|
51
|
+
const displayAmount = params ? Math.min(1, Math.max(0, params.displayAmount ?? 1)) : 1;
|
|
52
|
+
const drawCount = displayAmount >= 1 ? rawCount : Math.round(rawCount * displayAmount);
|
|
53
|
+
const billboard = this.parameters.billboard >= 0.5;
|
|
54
|
+
const fadeOut = this.parameters.fadeOut >= 0.5;
|
|
55
|
+
if (billboard && this.camera) {
|
|
56
|
+
this.camera.getWorldQuaternion(this._camQuat);
|
|
57
|
+
}
|
|
58
|
+
for (let i = 0; i < drawCount; i++) {
|
|
59
|
+
const p = this._drawBuf[i];
|
|
60
|
+
const s = p.size * (fadeOut ? 1 - p.normalised : 1);
|
|
61
|
+
this._pos.set(p.position.x, p.position.y, p.position.z);
|
|
62
|
+
this._scale.setScalar(Math.max(s, 0));
|
|
63
|
+
if (billboard && this.camera) {
|
|
64
|
+
this._matrix.compose(this._pos, this._camQuat, this._scale);
|
|
65
|
+
}
|
|
66
|
+
else {
|
|
67
|
+
this._euler.set(p.rotation.x, p.rotation.y, p.rotation.z);
|
|
68
|
+
this._quat.setFromEuler(this._euler);
|
|
69
|
+
this._matrix.compose(this._pos, this._quat, this._scale);
|
|
70
|
+
}
|
|
71
|
+
this.object3D.setMatrixAt(i, this._matrix);
|
|
72
|
+
}
|
|
73
|
+
// Zero out slots that were alive last frame but aren't now
|
|
74
|
+
for (let i = drawCount; i < this._prevCount; i++) {
|
|
75
|
+
this.object3D.setMatrixAt(i, this._zeroMatrix);
|
|
76
|
+
}
|
|
77
|
+
this._prevCount = drawCount;
|
|
78
|
+
this.object3D.count = drawCount;
|
|
79
|
+
this.object3D.instanceMatrix.needsUpdate = true;
|
|
80
|
+
}
|
|
81
|
+
dispose() {
|
|
82
|
+
this.object3D.geometry.dispose();
|
|
83
|
+
this.object3D.material.dispose();
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=InstanceRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"InstanceRenderer.js","sourceRoot":"","sources":["../../src/renderers/InstanceRenderer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { LineSegments } from 'three';
|
|
2
|
+
import { BaseRenderer } from '../core/BaseRenderer.js';
|
|
3
|
+
import type { ParticleLike } from '../core/BaseRenderer.js';
|
|
4
|
+
import type { SeededRandom } from '../core/SeededRandom.js';
|
|
5
|
+
export interface LineRendererOptions {
|
|
6
|
+
maxCount?: number;
|
|
7
|
+
color?: string | number;
|
|
8
|
+
/** Length multiplier — line extends velocity.length × scale behind particle */
|
|
9
|
+
lengthScale?: number;
|
|
10
|
+
/** Colour mode: 0=flat, 1=by velocity, 2=by age (Blender: Display Colour) */
|
|
11
|
+
colourMode?: number;
|
|
12
|
+
/** Low-speed / young colour RGB components [0–1] */
|
|
13
|
+
colourLow?: [number, number, number];
|
|
14
|
+
/** High-speed / old colour RGB components [0–1] */
|
|
15
|
+
colourHigh?: [number, number, number];
|
|
16
|
+
/** Velocity magnitude that maps to colourHigh in mode 1 */
|
|
17
|
+
velocityMax?: number;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* LineRenderer — renders each particle as a velocity-aligned line segment.
|
|
21
|
+
* (Blender: Render → Line)
|
|
22
|
+
*/
|
|
23
|
+
export declare class LineRenderer extends BaseRenderer {
|
|
24
|
+
readonly object3D: LineSegments;
|
|
25
|
+
/**
|
|
26
|
+
* Scalar inputs — safe to animate with GSAP or the keyframe system.
|
|
27
|
+
* lengthScale: line extends velocity × lengthScale behind the particle.
|
|
28
|
+
* opacity: overall alpha [0–1].
|
|
29
|
+
* colourMode: 0=flat, 1=by velocity, 2=by age.
|
|
30
|
+
*/
|
|
31
|
+
parameters: {
|
|
32
|
+
lengthScale: number;
|
|
33
|
+
opacity: number;
|
|
34
|
+
colourMode: number;
|
|
35
|
+
colourLowR: number;
|
|
36
|
+
colourLowG: number;
|
|
37
|
+
colourLowB: number;
|
|
38
|
+
colourHighR: number;
|
|
39
|
+
colourHighG: number;
|
|
40
|
+
colourHighB: number;
|
|
41
|
+
velocityMax: number;
|
|
42
|
+
};
|
|
43
|
+
private _positions;
|
|
44
|
+
private _colors;
|
|
45
|
+
private _posAttr;
|
|
46
|
+
private _colorAttr;
|
|
47
|
+
private _maxCount;
|
|
48
|
+
constructor(opts?: LineRendererOptions);
|
|
49
|
+
update(particles: ParticleLike[], aliveCount: number, params?: Record<string, number>, childRng?: SeededRandom): void;
|
|
50
|
+
dispose(): void;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=LineRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LineRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/LineRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAEb,MAAM,OAAO,CAAA;AACd,OAAO,EAAE,YAAY,EAAE,MAAY,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAC5D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAO,yBAAyB,CAAA;AAE5D,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,EAAK,MAAM,CAAA;IACpB,KAAK,CAAC,EAAQ,MAAM,GAAG,MAAM,CAAA;IAC7B,+EAA+E;IAC/E,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,6EAA6E;IAC7E,UAAU,CAAC,EAAG,MAAM,CAAA;IACpB,oDAAoD;IACpD,SAAS,CAAC,EAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,mDAAmD;IACnD,UAAU,CAAC,EAAG,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IACtC,2DAA2D;IAC3D,WAAW,CAAC,EAAE,MAAM,CAAA;CACrB;AAED;;;GAGG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,QAAQ,CAAC,QAAQ,EAAE,YAAY,CAAA;IAE/B;;;;;OAKG;IACH,UAAU,EAAE;QACV,WAAW,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;QACpC,UAAU,EAAE,MAAM,CAAA;QAClB,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAC;QAAC,UAAU,EAAE,MAAM,CAAA;QAC1D,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;QAC7D,WAAW,EAAE,MAAM,CAAA;KACpB,CAAA;IAED,OAAO,CAAC,UAAU,CAAc;IAChC,OAAO,CAAC,OAAO,CAAiB;IAChC,OAAO,CAAC,QAAQ,CAAmB;IACnC,OAAO,CAAC,UAAU,CAAiB;IACnC,OAAO,CAAC,SAAS,CAAS;gBAEd,IAAI,GAAE,mBAAwB;IAuC1C,MAAM,CACJ,SAAS,EAAE,YAAY,EAAE,EACzB,UAAU,EAAE,MAAM,EAClB,MAAM,CAAC,EAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAClC,QAAQ,CAAC,EAAG,YAAY,GACvB,IAAI;IA0DP,OAAO,IAAI,IAAI;CAIhB"}
|