@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.
Files changed (153) hide show
  1. package/dist/core/BaseEmitter.d.ts +50 -0
  2. package/dist/core/BaseEmitter.d.ts.map +1 -0
  3. package/dist/core/BaseEmitter.js +53 -0
  4. package/dist/core/BaseEmitter.js.map +1 -0
  5. package/dist/core/BaseForce.d.ts +21 -0
  6. package/dist/core/BaseForce.d.ts.map +1 -0
  7. package/dist/core/BaseForce.js +15 -0
  8. package/dist/core/BaseForce.js.map +1 -0
  9. package/dist/core/BaseRenderer.d.ts +96 -0
  10. package/dist/core/BaseRenderer.d.ts.map +1 -0
  11. package/dist/core/BaseRenderer.js +190 -0
  12. package/dist/core/BaseRenderer.js.map +1 -0
  13. package/dist/core/DeflectorCollider.d.ts +46 -0
  14. package/dist/core/DeflectorCollider.d.ts.map +1 -0
  15. package/dist/core/DeflectorCollider.js +113 -0
  16. package/dist/core/DeflectorCollider.js.map +1 -0
  17. package/dist/core/Particle.d.ts +29 -0
  18. package/dist/core/Particle.d.ts.map +1 -0
  19. package/dist/core/Particle.js +41 -0
  20. package/dist/core/Particle.js.map +1 -0
  21. package/dist/core/ParticleCache.d.ts +73 -0
  22. package/dist/core/ParticleCache.d.ts.map +1 -0
  23. package/dist/core/ParticleCache.js +206 -0
  24. package/dist/core/ParticleCache.js.map +1 -0
  25. package/dist/core/ParticleSystem.d.ts +192 -0
  26. package/dist/core/ParticleSystem.d.ts.map +1 -0
  27. package/dist/core/ParticleSystem.js +484 -0
  28. package/dist/core/ParticleSystem.js.map +1 -0
  29. package/dist/core/SeededRandom.d.ts +17 -0
  30. package/dist/core/SeededRandom.d.ts.map +1 -0
  31. package/dist/core/SeededRandom.js +27 -0
  32. package/dist/core/SeededRandom.js.map +1 -0
  33. package/dist/emitters/EdgeEmitter.d.ts +43 -0
  34. package/dist/emitters/EdgeEmitter.d.ts.map +1 -0
  35. package/dist/emitters/EdgeEmitter.js +78 -0
  36. package/dist/emitters/EdgeEmitter.js.map +1 -0
  37. package/dist/emitters/MeshEmitter.d.ts +83 -0
  38. package/dist/emitters/MeshEmitter.d.ts.map +1 -0
  39. package/dist/emitters/MeshEmitter.js +240 -0
  40. package/dist/emitters/MeshEmitter.js.map +1 -0
  41. package/dist/emitters/PointEmitter.d.ts +22 -0
  42. package/dist/emitters/PointEmitter.d.ts.map +1 -0
  43. package/dist/emitters/PointEmitter.js +26 -0
  44. package/dist/emitters/PointEmitter.js.map +1 -0
  45. package/dist/forces/BoidField.d.ts +58 -0
  46. package/dist/forces/BoidField.d.ts.map +1 -0
  47. package/dist/forces/BoidField.js +82 -0
  48. package/dist/forces/BoidField.js.map +1 -0
  49. package/dist/forces/BoidForce.d.ts +54 -0
  50. package/dist/forces/BoidForce.d.ts.map +1 -0
  51. package/dist/forces/BoidForce.js +233 -0
  52. package/dist/forces/BoidForce.js.map +1 -0
  53. package/dist/forces/ChargeForce.d.ts +22 -0
  54. package/dist/forces/ChargeForce.d.ts.map +1 -0
  55. package/dist/forces/ChargeForce.js +35 -0
  56. package/dist/forces/ChargeForce.js.map +1 -0
  57. package/dist/forces/CurveGuideForce.d.ts +43 -0
  58. package/dist/forces/CurveGuideForce.d.ts.map +1 -0
  59. package/dist/forces/CurveGuideForce.js +118 -0
  60. package/dist/forces/CurveGuideForce.js.map +1 -0
  61. package/dist/forces/DragForce.d.ts +19 -0
  62. package/dist/forces/DragForce.d.ts.map +1 -0
  63. package/dist/forces/DragForce.js +31 -0
  64. package/dist/forces/DragForce.js.map +1 -0
  65. package/dist/forces/FlowFieldForce.d.ts +72 -0
  66. package/dist/forces/FlowFieldForce.d.ts.map +1 -0
  67. package/dist/forces/FlowFieldForce.js +68 -0
  68. package/dist/forces/FlowFieldForce.js.map +1 -0
  69. package/dist/forces/ForceField.d.ts +26 -0
  70. package/dist/forces/ForceField.d.ts.map +1 -0
  71. package/dist/forces/ForceField.js +41 -0
  72. package/dist/forces/ForceField.js.map +1 -0
  73. package/dist/forces/GravityForce.d.ts +9 -0
  74. package/dist/forces/GravityForce.d.ts.map +1 -0
  75. package/dist/forces/GravityForce.js +12 -0
  76. package/dist/forces/GravityForce.js.map +1 -0
  77. package/dist/forces/HarmonicForce.d.ts +22 -0
  78. package/dist/forces/HarmonicForce.d.ts.map +1 -0
  79. package/dist/forces/HarmonicForce.js +31 -0
  80. package/dist/forces/HarmonicForce.js.map +1 -0
  81. package/dist/forces/LennardJonesForce.d.ts +23 -0
  82. package/dist/forces/LennardJonesForce.d.ts.map +1 -0
  83. package/dist/forces/LennardJonesForce.js +38 -0
  84. package/dist/forces/LennardJonesForce.js.map +1 -0
  85. package/dist/forces/MagneticForce.d.ts +21 -0
  86. package/dist/forces/MagneticForce.d.ts.map +1 -0
  87. package/dist/forces/MagneticForce.js +30 -0
  88. package/dist/forces/MagneticForce.js.map +1 -0
  89. package/dist/forces/TextureForce.d.ts +37 -0
  90. package/dist/forces/TextureForce.d.ts.map +1 -0
  91. package/dist/forces/TextureForce.js +56 -0
  92. package/dist/forces/TextureForce.js.map +1 -0
  93. package/dist/forces/TurbulenceForce.d.ts +21 -0
  94. package/dist/forces/TurbulenceForce.d.ts.map +1 -0
  95. package/dist/forces/TurbulenceForce.js +39 -0
  96. package/dist/forces/TurbulenceForce.js.map +1 -0
  97. package/dist/forces/VortexForce.d.ts +21 -0
  98. package/dist/forces/VortexForce.d.ts.map +1 -0
  99. package/dist/forces/VortexForce.js +29 -0
  100. package/dist/forces/VortexForce.js.map +1 -0
  101. package/dist/forces/WindForce.d.ts +21 -0
  102. package/dist/forces/WindForce.d.ts.map +1 -0
  103. package/dist/forces/WindForce.js +29 -0
  104. package/dist/forces/WindForce.js.map +1 -0
  105. package/dist/index.d.ts +56 -0
  106. package/dist/index.d.ts.map +1 -0
  107. package/dist/index.js +44 -0
  108. package/dist/index.js.map +1 -0
  109. package/dist/physics/KeyedPhysics.d.ts +43 -0
  110. package/dist/physics/KeyedPhysics.d.ts.map +1 -0
  111. package/dist/physics/KeyedPhysics.js +73 -0
  112. package/dist/physics/KeyedPhysics.js.map +1 -0
  113. package/dist/physics/SPHPhysics.d.ts +27 -0
  114. package/dist/physics/SPHPhysics.d.ts.map +1 -0
  115. package/dist/physics/SPHPhysics.js +119 -0
  116. package/dist/physics/SPHPhysics.js.map +1 -0
  117. package/dist/renderers/BillboardRenderer.d.ts +75 -0
  118. package/dist/renderers/BillboardRenderer.d.ts.map +1 -0
  119. package/dist/renderers/BillboardRenderer.js +106 -0
  120. package/dist/renderers/BillboardRenderer.js.map +1 -0
  121. package/dist/renderers/CollectionRenderer.d.ts +83 -0
  122. package/dist/renderers/CollectionRenderer.d.ts.map +1 -0
  123. package/dist/renderers/CollectionRenderer.js +161 -0
  124. package/dist/renderers/CollectionRenderer.js.map +1 -0
  125. package/dist/renderers/HaloRenderer.d.ts +3 -0
  126. package/dist/renderers/HaloRenderer.d.ts.map +1 -0
  127. package/dist/renderers/HaloRenderer.js +4 -0
  128. package/dist/renderers/HaloRenderer.js.map +1 -0
  129. package/dist/renderers/InstanceRenderer.d.ts +70 -0
  130. package/dist/renderers/InstanceRenderer.d.ts.map +1 -0
  131. package/dist/renderers/InstanceRenderer.js +86 -0
  132. package/dist/renderers/InstanceRenderer.js.map +1 -0
  133. package/dist/renderers/LineRenderer.d.ts +52 -0
  134. package/dist/renderers/LineRenderer.d.ts.map +1 -0
  135. package/dist/renderers/LineRenderer.js +96 -0
  136. package/dist/renderers/LineRenderer.js.map +1 -0
  137. package/dist/renderers/NoneRenderer.d.ts +19 -0
  138. package/dist/renderers/NoneRenderer.d.ts.map +1 -0
  139. package/dist/renderers/NoneRenderer.js +24 -0
  140. package/dist/renderers/NoneRenderer.js.map +1 -0
  141. package/dist/renderers/ObjectRenderer.d.ts +3 -0
  142. package/dist/renderers/ObjectRenderer.d.ts.map +1 -0
  143. package/dist/renderers/ObjectRenderer.js +4 -0
  144. package/dist/renderers/ObjectRenderer.js.map +1 -0
  145. package/dist/renderers/StrandRenderer.d.ts +169 -0
  146. package/dist/renderers/StrandRenderer.d.ts.map +1 -0
  147. package/dist/renderers/StrandRenderer.js +235 -0
  148. package/dist/renderers/StrandRenderer.js.map +1 -0
  149. package/dist/renderers/TrailRenderer.d.ts +54 -0
  150. package/dist/renderers/TrailRenderer.d.ts.map +1 -0
  151. package/dist/renderers/TrailRenderer.js +114 -0
  152. package/dist/renderers/TrailRenderer.js.map +1 -0
  153. package/package.json +45 -0
@@ -0,0 +1,96 @@
1
+ import { LineSegments, BufferGeometry, BufferAttribute, LineBasicMaterial, Color, } from 'three';
2
+ import { BaseRenderer } from '../core/BaseRenderer.js';
3
+ /**
4
+ * LineRenderer — renders each particle as a velocity-aligned line segment.
5
+ * (Blender: Render → Line)
6
+ */
7
+ export class LineRenderer extends BaseRenderer {
8
+ constructor(opts = {}) {
9
+ super();
10
+ const max = opts.maxCount ?? 10000;
11
+ this._maxCount = max;
12
+ const low = opts.colourLow ?? [1, 0, 0];
13
+ const high = opts.colourHigh ?? [0, 0, 1];
14
+ this.parameters = {
15
+ lengthScale: opts.lengthScale ?? 0.1,
16
+ opacity: 1,
17
+ colourMode: opts.colourMode ?? 0,
18
+ colourLowR: low[0], colourLowG: low[1], colourLowB: low[2],
19
+ colourHighR: high[0], colourHighG: high[1], colourHighB: high[2],
20
+ velocityMax: opts.velocityMax ?? 10,
21
+ };
22
+ // Each line = 2 vertices × 3 floats
23
+ this._positions = new Float32Array(max * 6);
24
+ this._colors = new Float32Array(max * 6); // 2 vertices × RGB
25
+ const geo = new BufferGeometry();
26
+ this._posAttr = new BufferAttribute(this._positions, 3).setUsage(35048);
27
+ this._colorAttr = new BufferAttribute(this._colors, 3).setUsage(35048);
28
+ geo.setAttribute('position', this._posAttr);
29
+ geo.setAttribute('color', this._colorAttr);
30
+ geo.setDrawRange(0, 0);
31
+ const mat = new LineBasicMaterial({
32
+ color: new Color(opts.color ?? 0xffffff),
33
+ transparent: true,
34
+ depthWrite: false,
35
+ });
36
+ this.object3D = new LineSegments(geo, mat);
37
+ this.object3D.frustumCulled = false;
38
+ this._allocDrawBuf(max);
39
+ }
40
+ update(particles, aliveCount, params, childRng) {
41
+ const childCount = params ? Math.round(Math.max(0, params.childCount ?? 0)) : 0;
42
+ const childType = params ? Math.round(params.childType ?? 0) : 0;
43
+ const childSpread = params ? (params.childSpread ?? 0.5) : 0.5;
44
+ const rawCount = this.expandWithChildren(particles, aliveCount, childCount, childType, childSpread, childRng ?? null, this._maxCount);
45
+ const displayAmount = params ? Math.min(1, Math.max(0, params.displayAmount ?? 1)) : 1;
46
+ const drawCount = displayAmount >= 1 ? rawCount : Math.round(rawCount * displayAmount);
47
+ const pr = this.parameters;
48
+ const ls = pr.lengthScale;
49
+ const mode = Math.round(pr.colourMode);
50
+ for (let i = 0; i < drawCount; i++) {
51
+ const p = this._drawBuf[i];
52
+ const i6 = i * 6;
53
+ // Tail (velocity direction behind particle)
54
+ this._positions[i6] = p.position.x - p.velocity.x * ls;
55
+ this._positions[i6 + 1] = p.position.y - p.velocity.y * ls;
56
+ this._positions[i6 + 2] = p.position.z - p.velocity.z * ls;
57
+ // Head (current position)
58
+ this._positions[i6 + 3] = p.position.x;
59
+ this._positions[i6 + 4] = p.position.y;
60
+ this._positions[i6 + 5] = p.position.z;
61
+ if (mode > 0) {
62
+ let t;
63
+ if (mode === 1) {
64
+ const spd = Math.sqrt(p.velocity.x * p.velocity.x +
65
+ p.velocity.y * p.velocity.y +
66
+ p.velocity.z * p.velocity.z);
67
+ t = Math.min(1, spd / Math.max(pr.velocityMax, 0.0001));
68
+ }
69
+ else {
70
+ t = p.normalised;
71
+ }
72
+ const r = pr.colourLowR + (pr.colourHighR - pr.colourLowR) * t;
73
+ const g = pr.colourLowG + (pr.colourHighG - pr.colourLowG) * t;
74
+ const b = pr.colourLowB + (pr.colourHighB - pr.colourLowB) * t;
75
+ // Both tail and head vertices get the same colour
76
+ this._colors[i6] = r;
77
+ this._colors[i6 + 1] = g;
78
+ this._colors[i6 + 2] = b;
79
+ this._colors[i6 + 3] = r;
80
+ this._colors[i6 + 4] = g;
81
+ this._colors[i6 + 5] = b;
82
+ }
83
+ }
84
+ const mat = this.object3D.material;
85
+ mat.vertexColors = mode > 0;
86
+ this._posAttr.needsUpdate = true;
87
+ if (mode > 0)
88
+ this._colorAttr.needsUpdate = true;
89
+ this.object3D.geometry.setDrawRange(0, drawCount * 2);
90
+ }
91
+ dispose() {
92
+ this.object3D.geometry.dispose();
93
+ this.object3D.material.dispose();
94
+ }
95
+ }
96
+ //# sourceMappingURL=LineRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LineRenderer.js","sourceRoot":"","sources":["../../src/renderers/LineRenderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,19 @@
1
+ import { Object3D } 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
+ /**
6
+ * NoneRenderer — invisible particle renderer.
7
+ * Blender: Render → None.
8
+ *
9
+ * Useful when particles drive physics/emitters but should not be drawn,
10
+ * e.g. when particles spawn child systems or are consumed by a fluid sim.
11
+ */
12
+ export declare class NoneRenderer extends BaseRenderer {
13
+ readonly object3D: Object3D;
14
+ parameters: Record<string, number>;
15
+ constructor();
16
+ update(_particles: ParticleLike[], _aliveCount: number, _params?: Record<string, number>, _rng?: SeededRandom): void;
17
+ dispose(): void;
18
+ }
19
+ //# sourceMappingURL=NoneRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoneRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/NoneRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAS,OAAO,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAE3D;;;;;;GAMG;AACH,qBAAa,YAAa,SAAQ,YAAY;IAC5C,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAiB;IAC5C,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAK;;IAOvC,MAAM,CAAC,UAAU,EAAE,YAAY,EAAE,EAAE,WAAW,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,IAAI,CAAC,EAAE,YAAY,GAAG,IAAI;IAIpH,OAAO,IAAI,IAAI;CAGhB"}
@@ -0,0 +1,24 @@
1
+ import { Object3D } from 'three';
2
+ import { BaseRenderer } from '../core/BaseRenderer.js';
3
+ /**
4
+ * NoneRenderer — invisible particle renderer.
5
+ * Blender: Render → None.
6
+ *
7
+ * Useful when particles drive physics/emitters but should not be drawn,
8
+ * e.g. when particles spawn child systems or are consumed by a fluid sim.
9
+ */
10
+ export class NoneRenderer extends BaseRenderer {
11
+ constructor() {
12
+ super();
13
+ this.object3D = new Object3D();
14
+ this.parameters = {};
15
+ this.object3D.visible = false;
16
+ }
17
+ update(_particles, _aliveCount, _params, _rng) {
18
+ // intentionally empty — no visual output
19
+ }
20
+ dispose() {
21
+ // nothing to clean up
22
+ }
23
+ }
24
+ //# sourceMappingURL=NoneRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NoneRenderer.js","sourceRoot":"","sources":["../../src/renderers/NoneRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAS,OAAO,CAAA;AACnC,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAItD;;;;;;GAMG;AACH,MAAM,OAAO,YAAa,SAAQ,YAAY;IAI5C;QACE,KAAK,EAAE,CAAA;QAJA,aAAQ,GAAa,IAAI,QAAQ,EAAE,CAAA;QAC5C,eAAU,GAA2B,EAAE,CAAA;QAIrC,IAAI,CAAC,QAAQ,CAAC,OAAO,GAAG,KAAK,CAAA;IAC/B,CAAC;IAED,MAAM,CAAC,UAA0B,EAAE,WAAmB,EAAE,OAAgC,EAAE,IAAmB;QAC3G,yCAAyC;IAC3C,CAAC;IAED,OAAO;QACL,sBAAsB;IACxB,CAAC;CACF"}
@@ -0,0 +1,3 @@
1
+ export { InstanceRenderer as ObjectRenderer } from './InstanceRenderer.js';
2
+ export type { InstanceRendererOptions as ObjectRendererOptions } from './InstanceRenderer.js';
3
+ //# sourceMappingURL=ObjectRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ObjectRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/ObjectRenderer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,gBAAgB,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAA;AAC1E,YAAY,EAAE,uBAAuB,IAAI,qBAAqB,EAAE,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,4 @@
1
+ // Blender "Object" render mode alias → InstanceRenderer.
2
+ // Both names are exported so code may use either; they are the same class.
3
+ export { InstanceRenderer as ObjectRenderer } from './InstanceRenderer.js';
4
+ //# sourceMappingURL=ObjectRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ObjectRenderer.js","sourceRoot":"","sources":["../../src/renderers/ObjectRenderer.ts"],"names":[],"mappings":"AAAA,yDAAyD;AACzD,2EAA2E;AAC3E,OAAO,EAAE,gBAAgB,IAAI,cAAc,EAAE,MAAM,uBAAuB,CAAA"}
@@ -0,0 +1,169 @@
1
+ import { Group, LineBasicMaterial, MeshBasicMaterial } 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
+ /** Source geometry with optional vertex-group float attributes. */
6
+ export interface StrandSourceGeometry {
7
+ getAttribute(name: string): {
8
+ getX(i: number): number;
9
+ } | undefined;
10
+ }
11
+ export type StrandCurveFn = (particle: ParticleLike, t: number, // 0 = root, 1 = tip
12
+ index: number) => {
13
+ x: number;
14
+ y: number;
15
+ z: number;
16
+ };
17
+ export type StrandRenderMode = 'line' | 'tube';
18
+ export interface StrandRendererOptions {
19
+ /**
20
+ * Maximum number of live strands. Default 1000.
21
+ * Set to the particle system's `count` for best results.
22
+ */
23
+ maxCount?: number;
24
+ /**
25
+ * Number of segments per strand. Default 8.
26
+ * More segments = smoother curves, higher GPU cost.
27
+ */
28
+ segments?: number;
29
+ /**
30
+ * Strand cross-section radius for 'tube' mode. Default 0.02.
31
+ * Blender: Hair Shape → Diameter Root
32
+ */
33
+ thickness?: number;
34
+ /**
35
+ * Tip taper factor [0–1]. 1 = uniform, 0 = taper to point. Default 0.5.
36
+ * Blender: Hair Shape → Taper
37
+ */
38
+ taper?: number;
39
+ /**
40
+ * How strands are rendered.
41
+ * 'line' (default) — fast LineSegments, thickness controlled by material.
42
+ * 'tube' — mesh tube, supports lighting. Heavier, best for hero strands.
43
+ */
44
+ mode?: StrandRenderMode;
45
+ /**
46
+ * Function that returns a world-space point along the strand at normalised t ∈ [0,1].
47
+ * t=0 = root (particle position), t=1 = tip.
48
+ *
49
+ * Default: straight strand drooping 1 world unit downward along gravity.
50
+ *
51
+ * To connect with st-hair-core:
52
+ * const gen = new StrandGenerator({ ... })
53
+ * renderer = new StrandRenderer({
54
+ * strandCurve: (p, t) => gen.evaluateAt(p.position, p.velocity, t)
55
+ * })
56
+ */
57
+ strandCurve?: StrandCurveFn;
58
+ /** Material for the strands. Default: white LineBasicMaterial or MeshBasicMaterial. */
59
+ material?: LineBasicMaterial | MeshBasicMaterial;
60
+ /**
61
+ * Source geometry to read vertex-group float attributes from.
62
+ * The particle's `poolIdx` is used as the vertex index.
63
+ * Blender: Vertex Groups → Strand panel.
64
+ */
65
+ sourceGeometry?: StrandSourceGeometry;
66
+ /**
67
+ * Name of a float vertex attribute on `sourceGeometry` whose value [0–1]
68
+ * scales each strand's length multiplier. 0 = no strand, 1 = full length.
69
+ * Blender: Vertex Groups → Length.
70
+ */
71
+ lengthAttribute?: string;
72
+ /**
73
+ * Name of a float vertex attribute on `sourceGeometry` whose value [0–1]
74
+ * offsets the strand root toward the emitter surface centre (clumping).
75
+ * Blender: Vertex Groups → Clump.
76
+ */
77
+ clumpAttribute?: string;
78
+ /**
79
+ * Name of a float vertex attribute on `sourceGeometry` whose value [0–1]
80
+ * scales the kink amplitude for this strand.
81
+ * Blender: Vertex Groups → Roughness.
82
+ */
83
+ roughnessAttribute?: string;
84
+ /**
85
+ * Viewport display fraction [0–1]. Default 1 (show all).
86
+ * 0.5 shows 50% of strands in the viewport without affecting simulation.
87
+ * Blender: Display panel → Display Amount.
88
+ */
89
+ displayAmount?: number;
90
+ /**
91
+ * Optional callback that returns the world-space tangent direction at
92
+ * a normalised position t along the strand.
93
+ * Used to drive anisotropic shading in tube mode (e.g. PrincipledHair node).
94
+ *
95
+ * @example
96
+ * // Connect with st-hair-core StrandGenerator
97
+ * const gen = new StrandGenerator({ ... })
98
+ * new StrandRenderer({
99
+ * tangentFn: (particle, t) => gen.tangentAt(particle.position, particle.velocity, t)
100
+ * })
101
+ */
102
+ tangentFn?: (particle: ParticleLike, t: number) => {
103
+ x: number;
104
+ y: number;
105
+ z: number;
106
+ };
107
+ }
108
+ /**
109
+ * StrandRenderer — Blender: Hair / Path render type on a particle system.
110
+ *
111
+ * Renders each alive particle as a strand (hair, grass, fur).
112
+ * The strand shape is defined by a `strandCurve` callback — this allows
113
+ * integration with st-hair-core's StrandGenerator without a hard import.
114
+ *
115
+ * Usage:
116
+ * ```typescript
117
+ * const renderer = new StrandRenderer({
118
+ * maxCount: 500,
119
+ * segments: 8,
120
+ * strandCurve: (p, t) => ({
121
+ * x: p.position.x,
122
+ * y: p.position.y + t * 0.3,
123
+ * z: p.position.z,
124
+ * })
125
+ * })
126
+ * sys.setRenderer(renderer)
127
+ * scene.add(renderer.object3D)
128
+ * ```
129
+ *
130
+ * To use st-hair-core strand shapes, pass a generator callback:
131
+ * ```typescript
132
+ * // Outside st-particle-core — no import restriction applies here
133
+ * import { StrandGenerator } from 'st-hair-core'
134
+ * const gen = new StrandGenerator({ length: 0.4, gravity: 0.3 })
135
+ * const renderer = new StrandRenderer({
136
+ * strandCurve: (p, t) => gen.samplePoint(p.position, p.velocity, t)
137
+ * })
138
+ * ```
139
+ */
140
+ export declare class StrandRenderer extends BaseRenderer {
141
+ parameters: Record<string, number>;
142
+ readonly object3D: Group;
143
+ private readonly _segments;
144
+ private readonly _maxCount;
145
+ private readonly _mode;
146
+ private readonly _strandCurve;
147
+ private readonly _material;
148
+ private readonly _sourceGeo;
149
+ private readonly _lengthAttrName;
150
+ private readonly _clumpAttrName;
151
+ private readonly _roughnessAttrName;
152
+ private readonly _tangentFn;
153
+ private _lineGeo;
154
+ private _lineSegs;
155
+ private _linePosArr;
156
+ private _tubeMeshes;
157
+ private _tubeInScene;
158
+ constructor(opts?: StrandRendererOptions);
159
+ update(particles: ParticleLike[], aliveCount: number, params?: Record<string, number>, childRng?: SeededRandom): void;
160
+ dispose(): void;
161
+ private _initLineGeometry;
162
+ private _updateLine;
163
+ private _initTubePool;
164
+ private _updateTubes;
165
+ /** Read a float attribute value at vertex index `vi`; returns 1 if unavailable. */
166
+ private _attrVal;
167
+ private static _defaultCurve;
168
+ }
169
+ //# sourceMappingURL=StrandRenderer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StrandRenderer.d.ts","sourceRoot":"","sources":["../../src/renderers/StrandRenderer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,235 @@
1
+ import { Group, LineSegments, LineBasicMaterial, BufferGeometry, BufferAttribute, MeshBasicMaterial, Mesh, TubeGeometry, CatmullRomCurve3, Vector3, } from 'three';
2
+ import { BaseRenderer } from '../core/BaseRenderer.js';
3
+ /**
4
+ * StrandRenderer — Blender: Hair / Path render type on a particle system.
5
+ *
6
+ * Renders each alive particle as a strand (hair, grass, fur).
7
+ * The strand shape is defined by a `strandCurve` callback — this allows
8
+ * integration with st-hair-core's StrandGenerator without a hard import.
9
+ *
10
+ * Usage:
11
+ * ```typescript
12
+ * const renderer = new StrandRenderer({
13
+ * maxCount: 500,
14
+ * segments: 8,
15
+ * strandCurve: (p, t) => ({
16
+ * x: p.position.x,
17
+ * y: p.position.y + t * 0.3,
18
+ * z: p.position.z,
19
+ * })
20
+ * })
21
+ * sys.setRenderer(renderer)
22
+ * scene.add(renderer.object3D)
23
+ * ```
24
+ *
25
+ * To use st-hair-core strand shapes, pass a generator callback:
26
+ * ```typescript
27
+ * // Outside st-particle-core — no import restriction applies here
28
+ * import { StrandGenerator } from 'st-hair-core'
29
+ * const gen = new StrandGenerator({ length: 0.4, gravity: 0.3 })
30
+ * const renderer = new StrandRenderer({
31
+ * strandCurve: (p, t) => gen.samplePoint(p.position, p.velocity, t)
32
+ * })
33
+ * ```
34
+ */
35
+ export class StrandRenderer extends BaseRenderer {
36
+ constructor(opts = {}) {
37
+ super();
38
+ // Line mode geometry — one pre-allocated geometry updated in place
39
+ this._lineGeo = null;
40
+ this._lineSegs = null;
41
+ this._linePosArr = null;
42
+ // Tube mode — one Mesh per strand, pooled
43
+ this._tubeMeshes = [];
44
+ this._tubeInScene = [];
45
+ this._maxCount = opts.maxCount ?? 1000;
46
+ this._segments = opts.segments ?? 8;
47
+ this._mode = opts.mode ?? 'line';
48
+ this._strandCurve = opts.strandCurve ?? StrandRenderer._defaultCurve;
49
+ this._sourceGeo = opts.sourceGeometry ?? null;
50
+ this._lengthAttrName = opts.lengthAttribute ?? null;
51
+ this._clumpAttrName = opts.clumpAttribute ?? null;
52
+ this._roughnessAttrName = opts.roughnessAttribute ?? null;
53
+ this._tangentFn = opts.tangentFn ?? null;
54
+ this._material = opts.material ?? (this._mode === 'tube'
55
+ ? new MeshBasicMaterial({ color: 0xccaa77 })
56
+ : new LineBasicMaterial({ color: 0xccaa77 }));
57
+ this._allocDrawBuf(this._maxCount);
58
+ this.object3D = new Group();
59
+ this.parameters = {
60
+ thickness: opts.thickness ?? 0.02,
61
+ taper: opts.taper ?? 0.5,
62
+ segments: this._segments,
63
+ kinkAmplitude: 0, // wave displacement — Blender: Kink → Amplitude
64
+ kinkFrequency: 1, // waves per strand — Blender: Kink → Frequency
65
+ densityThreshold: 0, // skip strands where particle.size < this value
66
+ displayAmount: opts.displayAmount ?? 1.0, // fraction of strands shown [0–1]
67
+ };
68
+ if (this._mode === 'line') {
69
+ this._initLineGeometry();
70
+ }
71
+ else {
72
+ this._initTubePool();
73
+ }
74
+ }
75
+ update(particles, aliveCount, params, childRng) {
76
+ const n = this.expandWithChildren(particles, aliveCount, params?.childCount ?? 0, params?.childType ?? 0, params?.childSpread ?? 0.5, childRng ?? null, this._maxCount);
77
+ if (this._mode === 'line') {
78
+ this._updateLine(n);
79
+ }
80
+ else {
81
+ this._updateTubes(n);
82
+ }
83
+ }
84
+ dispose() {
85
+ this._lineGeo?.dispose();
86
+ this._material.dispose();
87
+ for (const m of this._tubeMeshes)
88
+ m.geometry.dispose();
89
+ }
90
+ // ── Line mode ─────────────────────────────────────────────────────────────
91
+ _initLineGeometry() {
92
+ // Each strand = _segments segments = _segments+1 points = _segments*2 line endpoints
93
+ const pointsPerStrand = this._segments + 1;
94
+ const totalPoints = this._maxCount * pointsPerStrand;
95
+ this._linePosArr = new Float32Array(totalPoints * 3);
96
+ this._lineGeo = new BufferGeometry();
97
+ this._lineGeo.setAttribute('position', new BufferAttribute(this._linePosArr, 3));
98
+ // Build index: pairs of consecutive points per strand
99
+ const indices = [];
100
+ for (let s = 0; s < this._maxCount; s++) {
101
+ const base = s * pointsPerStrand;
102
+ for (let seg = 0; seg < this._segments; seg++) {
103
+ indices.push(base + seg, base + seg + 1);
104
+ }
105
+ }
106
+ this._lineGeo.setIndex(indices);
107
+ this._lineSegs = new LineSegments(this._lineGeo, this._material);
108
+ this.object3D.add(this._lineSegs);
109
+ }
110
+ _updateLine(count) {
111
+ const arr = this._linePosArr;
112
+ const segs = this._segments;
113
+ const pps = segs + 1; // points per strand
114
+ const threshold = this.parameters.densityThreshold;
115
+ const displayMax = Math.round(count * Math.max(0, Math.min(1, this.parameters.displayAmount)));
116
+ for (let i = 0; i < count; i++) {
117
+ const d = this._drawBuf[i];
118
+ const base = i * pps * 3;
119
+ // Skip beyond displayAmount or low-weight strands
120
+ if (i >= displayMax || (threshold > 0 && d.size < threshold)) {
121
+ for (let j = 0; j < pps * 3; j++)
122
+ arr[base + j] = 0;
123
+ continue;
124
+ }
125
+ const lengthScale = this._attrVal(this._lengthAttrName, d.poolIdx);
126
+ const clumpScale = this._attrVal(this._clumpAttrName, d.poolIdx);
127
+ const roughnessScale = this._attrVal(this._roughnessAttrName, d.poolIdx);
128
+ const kinkAmp = this.parameters.kinkAmplitude * roughnessScale;
129
+ const kinkFreq = this.parameters.kinkFrequency;
130
+ for (let j = 0; j <= segs; j++) {
131
+ const t = (j / segs) * lengthScale;
132
+ const pt = this._strandCurve(d, t, d.poolIdx);
133
+ const kink = kinkAmp > 0 ? Math.sin(t * kinkFreq * Math.PI * 2) * kinkAmp * t : 0;
134
+ const clumpX = (d.position.x - pt.x) * (1 - clumpScale);
135
+ const clumpZ = (d.position.z - pt.z) * (1 - clumpScale);
136
+ const off = base + j * 3;
137
+ arr[off] = pt.x + kink + clumpX;
138
+ arr[off + 1] = pt.y;
139
+ arr[off + 2] = pt.z + kink * 0.5 + clumpZ;
140
+ }
141
+ }
142
+ // Zero out unused strands
143
+ for (let i = count; i < this._maxCount; i++) {
144
+ const base = i * pps * 3;
145
+ for (let j = 0; j < pps * 3; j++)
146
+ arr[base + j] = 0;
147
+ }
148
+ this._lineGeo.getAttribute('position').needsUpdate = true;
149
+ this._lineGeo.computeBoundingSphere();
150
+ }
151
+ // ── Tube mode ─────────────────────────────────────────────────────────────
152
+ _initTubePool() {
153
+ for (let i = 0; i < this._maxCount; i++) {
154
+ // Placeholder geometry — replaced each update
155
+ const geo = new BufferGeometry();
156
+ const mesh = new Mesh(geo, this._material);
157
+ mesh.visible = false;
158
+ this._tubeMeshes.push(mesh);
159
+ this._tubeInScene.push(false);
160
+ this.object3D.add(mesh);
161
+ }
162
+ }
163
+ _updateTubes(count) {
164
+ const segs = this._segments;
165
+ const thickness = this.parameters.thickness;
166
+ const taper = this.parameters.taper;
167
+ const threshold = this.parameters.densityThreshold;
168
+ const displayMax = Math.round(count * Math.max(0, Math.min(1, this.parameters.displayAmount)));
169
+ for (let i = 0; i < count; i++) {
170
+ const d = this._drawBuf[i];
171
+ const mesh = this._tubeMeshes[i];
172
+ if (i >= displayMax || (threshold > 0 && d.size < threshold)) {
173
+ mesh.visible = false;
174
+ continue;
175
+ }
176
+ const lengthScale = this._attrVal(this._lengthAttrName, d.poolIdx);
177
+ const clumpScale = this._attrVal(this._clumpAttrName, d.poolIdx);
178
+ const roughnessScale = this._attrVal(this._roughnessAttrName, d.poolIdx);
179
+ const kinkAmp = this.parameters.kinkAmplitude * roughnessScale;
180
+ const kinkFreq = this.parameters.kinkFrequency;
181
+ const pts = [];
182
+ for (let j = 0; j <= segs; j++) {
183
+ const t = (j / segs) * lengthScale;
184
+ const pt = this._strandCurve(d, t, d.poolIdx);
185
+ const kink = kinkAmp > 0 ? Math.sin(t * kinkFreq * Math.PI * 2) * kinkAmp * t : 0;
186
+ const clumpX = (d.position.x - pt.x) * (1 - clumpScale);
187
+ const clumpZ = (d.position.z - pt.z) * (1 - clumpScale);
188
+ pts.push(new Vector3(pt.x + kink + clumpX, pt.y, pt.z + kink * 0.5 + clumpZ));
189
+ }
190
+ // Build tube geometry along the curve
191
+ const curve = new CatmullRomCurve3(pts);
192
+ const radiusFn = (t) => thickness * (1 - t * (1 - taper));
193
+ const tubeRadius = thickness; // TubeGeometry doesn't support per-point radius
194
+ void radiusFn;
195
+ mesh.geometry.dispose();
196
+ const geo = new TubeGeometry(curve, segs, tubeRadius * taper, 4, false);
197
+ // Bake tangent attribute for anisotropic shading (PrincipledHair / HairInfo node)
198
+ if (this._tangentFn) {
199
+ const vtxCount = geo.attributes.position.count;
200
+ const tangents = new Float32Array(vtxCount * 3);
201
+ for (let vi = 0; vi < vtxCount; vi++) {
202
+ const t = (vi / vtxCount);
203
+ const tv = this._tangentFn(d, t);
204
+ tangents[vi * 3] = tv.x;
205
+ tangents[vi * 3 + 1] = tv.y;
206
+ tangents[vi * 3 + 2] = tv.z;
207
+ }
208
+ geo.setAttribute('strandTangent', new BufferAttribute(tangents, 3));
209
+ }
210
+ mesh.geometry = geo;
211
+ mesh.visible = true;
212
+ }
213
+ // Hide unused
214
+ for (let i = count; i < this._maxCount; i++) {
215
+ this._tubeMeshes[i].visible = false;
216
+ }
217
+ }
218
+ // ── Vertex group attribute helpers ───────────────────────────────────────
219
+ /** Read a float attribute value at vertex index `vi`; returns 1 if unavailable. */
220
+ _attrVal(attrName, vi) {
221
+ if (!attrName || !this._sourceGeo)
222
+ return 1;
223
+ const attr = this._sourceGeo.getAttribute(attrName);
224
+ if (!attr)
225
+ return 1;
226
+ return attr.getX(vi);
227
+ }
228
+ }
229
+ // ── Default strand curve ──────────────────────────────────────────────────
230
+ StrandRenderer._defaultCurve = (p, t) => ({
231
+ x: p.position.x,
232
+ y: p.position.y + t * p.size * 5, // strand grows upward from particle
233
+ z: p.position.z,
234
+ });
235
+ //# sourceMappingURL=StrandRenderer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"StrandRenderer.js","sourceRoot":"","sources":["../../src/renderers/StrandRenderer.ts"],"names":[],"mappings":"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"}