@triforge/modifier-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 (81) hide show
  1. package/dist/core/BaseModifier.d.ts +29 -0
  2. package/dist/core/BaseModifier.d.ts.map +1 -0
  3. package/dist/core/BaseModifier.js +16 -0
  4. package/dist/core/BaseModifier.js.map +1 -0
  5. package/dist/core/ModifierStack.d.ts +40 -0
  6. package/dist/core/ModifierStack.d.ts.map +1 -0
  7. package/dist/core/ModifierStack.js +71 -0
  8. package/dist/core/ModifierStack.js.map +1 -0
  9. package/dist/index.d.ts +34 -0
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +23 -0
  12. package/dist/index.js.map +1 -0
  13. package/dist/modifiers/deform/BendModifier.d.ts +25 -0
  14. package/dist/modifiers/deform/BendModifier.d.ts.map +1 -0
  15. package/dist/modifiers/deform/BendModifier.js +83 -0
  16. package/dist/modifiers/deform/BendModifier.js.map +1 -0
  17. package/dist/modifiers/deform/DisplacementModifier.d.ts +38 -0
  18. package/dist/modifiers/deform/DisplacementModifier.d.ts.map +1 -0
  19. package/dist/modifiers/deform/DisplacementModifier.js +58 -0
  20. package/dist/modifiers/deform/DisplacementModifier.js.map +1 -0
  21. package/dist/modifiers/deform/ShrinkwrapModifier.d.ts +24 -0
  22. package/dist/modifiers/deform/ShrinkwrapModifier.d.ts.map +1 -0
  23. package/dist/modifiers/deform/ShrinkwrapModifier.js +122 -0
  24. package/dist/modifiers/deform/ShrinkwrapModifier.js.map +1 -0
  25. package/dist/modifiers/deform/TwistModifier.d.ts +24 -0
  26. package/dist/modifiers/deform/TwistModifier.d.ts.map +1 -0
  27. package/dist/modifiers/deform/TwistModifier.js +76 -0
  28. package/dist/modifiers/deform/TwistModifier.js.map +1 -0
  29. package/dist/modifiers/deform/WarpModifier.d.ts +33 -0
  30. package/dist/modifiers/deform/WarpModifier.d.ts.map +1 -0
  31. package/dist/modifiers/deform/WarpModifier.js +61 -0
  32. package/dist/modifiers/deform/WarpModifier.js.map +1 -0
  33. package/dist/modifiers/generate/ArrayModifier.d.ts +22 -0
  34. package/dist/modifiers/generate/ArrayModifier.d.ts.map +1 -0
  35. package/dist/modifiers/generate/ArrayModifier.js +65 -0
  36. package/dist/modifiers/generate/ArrayModifier.js.map +1 -0
  37. package/dist/modifiers/generate/BevelModifier.d.ts +31 -0
  38. package/dist/modifiers/generate/BevelModifier.d.ts.map +1 -0
  39. package/dist/modifiers/generate/BevelModifier.js +234 -0
  40. package/dist/modifiers/generate/BevelModifier.js.map +1 -0
  41. package/dist/modifiers/generate/BooleanModifier.d.ts +37 -0
  42. package/dist/modifiers/generate/BooleanModifier.d.ts.map +1 -0
  43. package/dist/modifiers/generate/BooleanModifier.js +71 -0
  44. package/dist/modifiers/generate/BooleanModifier.js.map +1 -0
  45. package/dist/modifiers/generate/ExtrudeModifier.d.ts +25 -0
  46. package/dist/modifiers/generate/ExtrudeModifier.d.ts.map +1 -0
  47. package/dist/modifiers/generate/ExtrudeModifier.js +96 -0
  48. package/dist/modifiers/generate/ExtrudeModifier.js.map +1 -0
  49. package/dist/modifiers/generate/MirrorModifier.d.ts +35 -0
  50. package/dist/modifiers/generate/MirrorModifier.d.ts.map +1 -0
  51. package/dist/modifiers/generate/MirrorModifier.js +122 -0
  52. package/dist/modifiers/generate/MirrorModifier.js.map +1 -0
  53. package/dist/modifiers/generate/OceanModifier.d.ts +64 -0
  54. package/dist/modifiers/generate/OceanModifier.d.ts.map +1 -0
  55. package/dist/modifiers/generate/OceanModifier.js +279 -0
  56. package/dist/modifiers/generate/OceanModifier.js.map +1 -0
  57. package/dist/modifiers/generate/SolidifyModifier.d.ts +21 -0
  58. package/dist/modifiers/generate/SolidifyModifier.d.ts.map +1 -0
  59. package/dist/modifiers/generate/SolidifyModifier.js +92 -0
  60. package/dist/modifiers/generate/SolidifyModifier.js.map +1 -0
  61. package/dist/modifiers/generate/SubdivisionModifier.d.ts +27 -0
  62. package/dist/modifiers/generate/SubdivisionModifier.d.ts.map +1 -0
  63. package/dist/modifiers/generate/SubdivisionModifier.js +181 -0
  64. package/dist/modifiers/generate/SubdivisionModifier.js.map +1 -0
  65. package/dist/modifiers/generate/WireframeModifier.d.ts +21 -0
  66. package/dist/modifiers/generate/WireframeModifier.d.ts.map +1 -0
  67. package/dist/modifiers/generate/WireframeModifier.js +139 -0
  68. package/dist/modifiers/generate/WireframeModifier.js.map +1 -0
  69. package/dist/modifiers/transform/NormalRecalculateModifier.d.ts +18 -0
  70. package/dist/modifiers/transform/NormalRecalculateModifier.d.ts.map +1 -0
  71. package/dist/modifiers/transform/NormalRecalculateModifier.js +24 -0
  72. package/dist/modifiers/transform/NormalRecalculateModifier.js.map +1 -0
  73. package/dist/modifiers/transform/UVProjectionModifier.d.ts +35 -0
  74. package/dist/modifiers/transform/UVProjectionModifier.d.ts.map +1 -0
  75. package/dist/modifiers/transform/UVProjectionModifier.js +88 -0
  76. package/dist/modifiers/transform/UVProjectionModifier.js.map +1 -0
  77. package/dist/utils/noise.d.ts +3 -0
  78. package/dist/utils/noise.d.ts.map +1 -0
  79. package/dist/utils/noise.js +17 -0
  80. package/dist/utils/noise.js.map +1 -0
  81. package/package.json +47 -0
@@ -0,0 +1,279 @@
1
+ import { BufferGeometry, BufferAttribute } from 'three';
2
+ import { BaseModifier } from '../../core/BaseModifier.js';
3
+ import { noise3 as valueNoise3 } from '../../utils/noise.js';
4
+ /**
5
+ * Ocean Modifier — Blender "Ocean" modifier equivalent.
6
+ *
7
+ * Generates a flat grid displaced by physically-based Gerstner wave simulation
8
+ * with a Phillips-inspired spectral distribution.
9
+ * Ignores the input geometry — always generates its own grid.
10
+ *
11
+ * Two-pass foam computation:
12
+ * Pass 1: evaluate all Gerstner displacements, record height range
13
+ * Pass 2: foam = crest fraction × steepness — produces thin streaks at
14
+ * wave tips rather than broad blobs from the Jacobian alone.
15
+ *
16
+ * Turbulence parameter adds seeded value-noise on top of Gerstner waves,
17
+ * breaking up the regular periodic pattern at any scale setting.
18
+ *
19
+ * Writes a `foam` Float32BufferAttribute. Use OceanAttribute node to read it.
20
+ */
21
+ export class OceanModifier extends BaseModifier {
22
+ get name() { return 'Ocean'; }
23
+ constructor(options = {}) {
24
+ super();
25
+ this._waves = [];
26
+ this._waveHash = NaN;
27
+ this.parameters = {
28
+ time: options.time ?? 0.0,
29
+ scale: options.scale ?? 3.0,
30
+ choppiness: options.choppiness ?? 1.2,
31
+ windSpeed: options.windSpeed ?? 30.0,
32
+ windAngle: options.windAngle ?? 20.0,
33
+ resolution: options.resolution ?? 32,
34
+ size: options.size ?? 1.0,
35
+ depth: options.depth ?? 200.0,
36
+ foamCoverage: options.foamCoverage ?? 0.2,
37
+ seed: options.seed ?? 55,
38
+ damping: options.damping ?? 0.5,
39
+ waveCount: options.waveCount ?? 24,
40
+ turbulence: options.turbulence ?? 0.15,
41
+ };
42
+ }
43
+ apply(_geometry) {
44
+ const res = Math.max(2, Math.min(256, Math.round(this.parameters.resolution)));
45
+ const size = this.parameters.size;
46
+ this._ensureWaves();
47
+ const vCount = res * res;
48
+ // ── Pass 1: evaluate all displacements, track height range ─────────────
49
+ const evals = new Array(vCount);
50
+ let yMin = Infinity;
51
+ let yMax = -Infinity;
52
+ for (let zi = 0; zi < res; zi++) {
53
+ for (let xi = 0; xi < res; xi++) {
54
+ const vi = zi * res + xi;
55
+ const u = xi / (res - 1);
56
+ const v = zi / (res - 1);
57
+ const r = this._evaluate((u - 0.5) * size, (v - 0.5) * size);
58
+ evals[vi] = r;
59
+ if (r.dispY < yMin)
60
+ yMin = r.dispY;
61
+ if (r.dispY > yMax)
62
+ yMax = r.dispY;
63
+ }
64
+ }
65
+ // ── Pass 2: fill buffers + compute crest-based foam ─────────────────────
66
+ const yRange = Math.max(0.001, yMax - yMin);
67
+ const coverage = Math.max(0, Math.min(1, this.parameters.foamCoverage));
68
+ const pos = new Float32Array(vCount * 3);
69
+ const norm = new Float32Array(vCount * 3);
70
+ const uv = new Float32Array(vCount * 2);
71
+ const foam = new Float32Array(vCount);
72
+ for (let zi = 0; zi < res; zi++) {
73
+ for (let xi = 0; xi < res; xi++) {
74
+ const vi = zi * res + xi;
75
+ const r = evals[vi];
76
+ const u = xi / (res - 1);
77
+ const v = zi / (res - 1);
78
+ pos[vi * 3] = r.x;
79
+ pos[vi * 3 + 1] = r.y;
80
+ pos[vi * 3 + 2] = r.z;
81
+ norm[vi * 3] = r.nx;
82
+ norm[vi * 3 + 1] = r.ny;
83
+ norm[vi * 3 + 2] = r.nz;
84
+ uv[vi * 2] = u;
85
+ uv[vi * 2 + 1] = v;
86
+ // ── Crest-based foam ────────────────────────────────────────────────
87
+ const height = (r.dispY - yMin) / yRange;
88
+ const threshold = 1.0 - coverage;
89
+ const crestFrac = Math.max(0, (height - threshold) / Math.max(0.001, coverage));
90
+ const smoothCrest = crestFrac * crestFrac * (3 - 2 * crestFrac);
91
+ const steep = Math.min(1, r.steep * 1.5);
92
+ foam[vi] = Math.min(1, smoothCrest * Math.sqrt(steep));
93
+ }
94
+ }
95
+ // ── Index buffer (quads → triangles) ────────────────────────────────────
96
+ const tCount = (res - 1) * (res - 1) * 6;
97
+ const indices = vCount < 65536
98
+ ? new Uint16Array(tCount)
99
+ : new Uint32Array(tCount);
100
+ let ii = 0;
101
+ for (let zi = 0; zi < res - 1; zi++) {
102
+ for (let xi = 0; xi < res - 1; xi++) {
103
+ const a = zi * res + xi, b = zi * res + xi + 1;
104
+ const c = (zi + 1) * res + xi, d = (zi + 1) * res + xi + 1;
105
+ indices[ii++] = a;
106
+ indices[ii++] = c;
107
+ indices[ii++] = b;
108
+ indices[ii++] = b;
109
+ indices[ii++] = c;
110
+ indices[ii++] = d;
111
+ }
112
+ }
113
+ const result = new BufferGeometry();
114
+ result.setAttribute('position', new BufferAttribute(pos, 3));
115
+ result.setAttribute('normal', new BufferAttribute(norm, 3));
116
+ result.setAttribute('uv', new BufferAttribute(uv, 2));
117
+ result.setAttribute('foam', new BufferAttribute(foam, 1));
118
+ result.setIndex(new BufferAttribute(indices, 1));
119
+ return result;
120
+ }
121
+ // ── Wave cache ──────────────────────────────────────────────────────────────
122
+ _ensureWaves() {
123
+ const h = this.parameters.seed * 1e6
124
+ + this.parameters.scale * 1e4
125
+ + this.parameters.windSpeed * 1e2
126
+ + this.parameters.windAngle * 10
127
+ + this.parameters.damping * 1e3
128
+ + this.parameters.depth * 0.1
129
+ + this.parameters.waveCount
130
+ + this.parameters.size * 1e2; // size affects quantised wave vectors
131
+ if (h === this._waveHash)
132
+ return;
133
+ this._waveHash = h;
134
+ this._waves = this._buildWaves();
135
+ }
136
+ _buildWaves() {
137
+ const scale = Math.max(0.01, this.parameters.scale);
138
+ const V = Math.max(0.1, this.parameters.windSpeed);
139
+ const windRad = this.parameters.windAngle * Math.PI / 180;
140
+ const damping = Math.max(0, Math.min(1, this.parameters.damping));
141
+ const waveCount = Math.max(4, Math.min(64, Math.round(this.parameters.waveCount)));
142
+ const L = Math.max(0.01, this.parameters.size);
143
+ const rng = new SeededRandom(Math.round(this.parameters.seed));
144
+ const TWO_PI_L = (2 * Math.PI) / L; // one grid step in wave-number space
145
+ const k0 = (2 * Math.PI) / scale;
146
+ const kMin = k0 / 8;
147
+ const kMax = k0 * 8;
148
+ const g_eff = 0.4;
149
+ const depth_n = Math.max(0.01, this.parameters.depth / scale);
150
+ const waves = [];
151
+ const seen = new Set();
152
+ // Try up to 4× waveCount candidates so deduplication doesn't leave us short.
153
+ for (let attempt = 0; attempt < waveCount * 4 && waves.length < waveCount; attempt++) {
154
+ const t = (attempt + 0.5) / waveCount;
155
+ // Sample continuous spectral range (same log-spaced sweep as before)
156
+ const k_cont = kMin * Math.pow(kMax / kMin, t % 1.0);
157
+ // Direction with spread (same formula as before — rng call preserved for seed parity)
158
+ const swellFactor = Math.max(0, Math.log(k0 / k_cont) / Math.log(8) + 0.5);
159
+ const baseSpread = Math.PI * (1 - damping * 0.8);
160
+ const spread = Math.min(Math.PI * 1.8, baseSpread * (1 + swellFactor * 0.5));
161
+ const angle = windRad + (rng.next() - 0.5) * spread;
162
+ // ── TILING FIX ─────────────────────────────────────────────────────────
163
+ // Project the continuous wave vector onto the integer lattice
164
+ // k_vec = (2π/L) * (mx, mz) → k·dx·L = 2π·mx (periodic over tile)
165
+ // This guarantees the Gerstner displacement field repeats exactly with
166
+ // period L in both X and Z, so adjacent tiles seam perfectly.
167
+ const mx = Math.round(k_cont * Math.cos(angle) / TWO_PI_L);
168
+ const mz = Math.round(k_cont * Math.sin(angle) / TWO_PI_L);
169
+ if (mx === 0 && mz === 0)
170
+ continue;
171
+ // Skip duplicate wave vectors (same direction + frequency)
172
+ const key = `${mx},${mz}`;
173
+ if (seen.has(key))
174
+ continue;
175
+ seen.add(key);
176
+ const len = Math.sqrt(mx * mx + mz * mz);
177
+ const dx = mx / len;
178
+ const dz = mz / len;
179
+ const kq = TWO_PI_L * len; // exact quantised wave number
180
+ // Accept only waves that fall within the spectral range
181
+ if (kq < kMin * 0.5 || kq > kMax * 2.0)
182
+ continue;
183
+ const lnRatio = Math.log(kq / k0);
184
+ const spectralShape = Math.exp(-lnRatio * lnRatio * 0.4);
185
+ const baseAmp = spectralShape * scale * 0.08 * Math.pow(V / 30, 1.5);
186
+ if (baseAmp < 1e-8)
187
+ continue;
188
+ const dotWind = dx * Math.cos(windRad) + dz * Math.sin(windRad);
189
+ const dirW = 0.3 + 0.7 * Math.max(0, dotWind);
190
+ const omega = Math.sqrt(g_eff * kq * Math.tanh(kq * depth_n));
191
+ waves.push({ amp: baseAmp * dirW, dx, dz, k: kq, omega, phase: rng.next() * Math.PI * 2 });
192
+ }
193
+ return waves;
194
+ }
195
+ // ── Tileable noise ──────────────────────────────────────────────────────────
196
+ //
197
+ // Maps (x0, z0) onto a 4D torus with periods L in both axes, then projects
198
+ // to two overlapping 3D noise samples that are averaged.
199
+ //
200
+ // Why this works:
201
+ // cos(2π(x0+L)/L) = cos(2πx0/L + 2π) = cos(2πx0/L) — x0 and x0+L
202
+ // sin(2π(x0+L)/L) = sin(2πx0/L + 2π) = sin(2πx0/L) map to the
203
+ // SAME point
204
+ // So the noise value is identical at both tile edges — no seam possible.
205
+ //
206
+ // Noise frequency: R = L·noiseScale/(2π) keeps the apparent spatial
207
+ // frequency identical to a flat noiseScale sample over a tile of size L.
208
+ _tiledNoise(x0, z0, t, L, noiseScale) {
209
+ const TWO_PI_L = (2 * Math.PI) / L;
210
+ const R = L * noiseScale / (2 * Math.PI);
211
+ const cx = R * Math.cos(TWO_PI_L * x0);
212
+ const sx = R * Math.sin(TWO_PI_L * x0);
213
+ const cz = R * Math.cos(TWO_PI_L * z0);
214
+ const sz = R * Math.sin(TWO_PI_L * z0);
215
+ // Two 3D projections of the (cx,sx,cz,sz) 4D torus, averaged to reduce
216
+ // the directional bias that any single 3D projection introduces.
217
+ return 0.5 * (valueNoise3(cx + 0.3, sx + 7.1, cz + t * 0.15)
218
+ + valueNoise3(sx + 3.7, cz + 1.4, sz + t * 0.15));
219
+ }
220
+ // ── Per-vertex evaluation ───────────────────────────────────────────────────
221
+ _evaluate(x0, z0) {
222
+ const t = this.parameters.time;
223
+ const Q = this.parameters.choppiness * 0.8;
224
+ const turb = this.parameters.turbulence;
225
+ let dispX = 0, dispY = 0, dispZ = 0;
226
+ let Jxx = 0, Jzz = 0, Jxz = 0;
227
+ let dydx = 0, dydz = 0;
228
+ for (const w of this._waves) {
229
+ const phase = w.k * (w.dx * x0 + w.dz * z0) - w.omega * t + w.phase;
230
+ const sinP = Math.sin(phase);
231
+ const cosP = Math.cos(phase);
232
+ dispY += w.amp * sinP;
233
+ dispX += Q * w.amp * w.dx * cosP;
234
+ dispZ += Q * w.amp * w.dz * cosP;
235
+ Jxx += Q * w.k * w.amp * w.dx * w.dx * sinP;
236
+ Jzz += Q * w.k * w.amp * w.dz * w.dz * sinP;
237
+ Jxz += Q * w.k * w.amp * w.dx * w.dz * sinP;
238
+ dydx += w.k * w.amp * w.dx * cosP;
239
+ dydz += w.k * w.amp * w.dz * cosP;
240
+ }
241
+ // ── Turbulence ──────────────────────────────────────────────────────────
242
+ // Y-height perturbation only (no X/Z — those break tiling).
243
+ // Uses _tiledNoise which maps (x0,z0) to a 4D torus so the function is
244
+ // exactly periodic with the tile size in both axes → zero seam at any edge.
245
+ if (turb > 0) {
246
+ const L = this.parameters.size;
247
+ const noiseScale = 1.5 / Math.max(0.1, this.parameters.scale);
248
+ const ns = turb * this.parameters.scale * 0.12;
249
+ dispY += ns * this._tiledNoise(x0, z0, t, L, noiseScale);
250
+ const e = 0.02;
251
+ dydx += ns * (this._tiledNoise(x0 + e, z0, t, L, noiseScale)
252
+ - this._tiledNoise(x0 - e, z0, t, L, noiseScale)) / (2 * e);
253
+ dydz += ns * (this._tiledNoise(x0, z0 + e, t, L, noiseScale)
254
+ - this._tiledNoise(x0, z0 - e, t, L, noiseScale)) / (2 * e);
255
+ }
256
+ // Jacobian: 1 = flat, <1 = steepening, <0 = breaking
257
+ const J = (1 - Jxx) * (1 - Jzz) - Jxz * Jxz;
258
+ // Steepness: 0 on flat water, 1 where waves are breaking
259
+ const steep = Math.max(0, 1 - J);
260
+ // Normal from gradient
261
+ const nx_ = -dydx, ny_ = 1.0, nz_ = -dydz;
262
+ const nl = Math.sqrt(nx_ * nx_ + ny_ * ny_ + nz_ * nz_) || 1;
263
+ return {
264
+ x: x0 + dispX, y: dispY, z: z0 + dispZ,
265
+ nx: nx_ / nl, ny: ny_ / nl, nz: nz_ / nl,
266
+ dispY,
267
+ steep,
268
+ };
269
+ }
270
+ }
271
+ // ── Seeded LCG random ─────────────────────────────────────────────────────────
272
+ class SeededRandom {
273
+ constructor(seed) { this.s = seed >>> 0; }
274
+ next() {
275
+ this.s = (Math.imul(1664525, this.s) + 1013904223) >>> 0;
276
+ return this.s / 4294967296;
277
+ }
278
+ }
279
+ //# sourceMappingURL=OceanModifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"OceanModifier.js","sourceRoot":"","sources":["../../../src/modifiers/generate/OceanModifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,21 @@
1
+ import { BufferGeometry } from 'three';
2
+ import { BaseModifier } from '../../core/BaseModifier.js';
3
+ export interface SolidifyModifierOptions {
4
+ thickness?: number;
5
+ offset?: number;
6
+ }
7
+ /**
8
+ * Solidify Modifier — Blender "Solidify" modifier equivalent.
9
+ * Adds thickness to a surface by extruding it along vertex normals.
10
+ * Produces a closed shell: original face + offset face + side walls.
11
+ *
12
+ * parameters.thickness: extrusion distance
13
+ * parameters.offset: -1 (inward) to 1 (outward), 0 = centered
14
+ */
15
+ export declare class SolidifyModifier extends BaseModifier {
16
+ get name(): string;
17
+ parameters: Record<string, number>;
18
+ constructor(options?: SolidifyModifierOptions);
19
+ apply(geometry: BufferGeometry): BufferGeometry;
20
+ }
21
+ //# sourceMappingURL=SolidifyModifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SolidifyModifier.d.ts","sourceRoot":"","sources":["../../../src/modifiers/generate/SolidifyModifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAmB,MAAM,OAAO,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAEzD,MAAM,WAAW,uBAAuB;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,MAAM,CAAC,EAAK,MAAM,CAAA;CACnB;AAED;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,YAAY;IAChD,IAAI,IAAI,WAAwB;IAEhC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;gBAEtB,OAAO,GAAE,uBAA4B;IAQjD,KAAK,CAAC,QAAQ,EAAE,cAAc,GAAG,cAAc;CA+DhD"}
@@ -0,0 +1,92 @@
1
+ import { BufferGeometry, BufferAttribute } from 'three';
2
+ import { BaseModifier } from '../../core/BaseModifier.js';
3
+ /**
4
+ * Solidify Modifier — Blender "Solidify" modifier equivalent.
5
+ * Adds thickness to a surface by extruding it along vertex normals.
6
+ * Produces a closed shell: original face + offset face + side walls.
7
+ *
8
+ * parameters.thickness: extrusion distance
9
+ * parameters.offset: -1 (inward) to 1 (outward), 0 = centered
10
+ */
11
+ export class SolidifyModifier extends BaseModifier {
12
+ get name() { return 'Solidify'; }
13
+ constructor(options = {}) {
14
+ super();
15
+ this.parameters = {
16
+ thickness: options.thickness ?? 0.1,
17
+ offset: options.offset ?? -1.0,
18
+ };
19
+ }
20
+ apply(geometry) {
21
+ const thickness = this.parameters.thickness;
22
+ const offset = Math.max(-1, Math.min(1, this.parameters.offset));
23
+ const srcPos = geometry.getAttribute('position');
24
+ const srcNorm = geometry.getAttribute('normal');
25
+ const srcUv = geometry.getAttribute('uv');
26
+ const srcIdx = geometry.getIndex();
27
+ const vCount = srcPos.count;
28
+ // outward shift: offset maps [-1,1] → [0,1] fraction of thickness
29
+ const outerShift = thickness * (1.0 + offset) * 0.5;
30
+ const innerShift = thickness * (1.0 - offset) * 0.5;
31
+ const outPos = [];
32
+ const outNorm = [];
33
+ const outUv = [];
34
+ const outIdx = [];
35
+ // Front face vertices (shifted outward)
36
+ for (let v = 0; v < vCount; v++) {
37
+ const nx = srcNorm ? srcNorm.getX(v) : 0;
38
+ const ny = srcNorm ? srcNorm.getY(v) : 1;
39
+ const nz = srcNorm ? srcNorm.getZ(v) : 0;
40
+ outPos.push(srcPos.getX(v) + nx * outerShift, srcPos.getY(v) + ny * outerShift, srcPos.getZ(v) + nz * outerShift);
41
+ outNorm.push(nx, ny, nz);
42
+ if (srcUv)
43
+ outUv.push(srcUv.getX(v), srcUv.getY(v));
44
+ }
45
+ // Back face vertices (shifted inward, flipped normal)
46
+ for (let v = 0; v < vCount; v++) {
47
+ const nx = srcNorm ? srcNorm.getX(v) : 0;
48
+ const ny = srcNorm ? srcNorm.getY(v) : 1;
49
+ const nz = srcNorm ? srcNorm.getZ(v) : 0;
50
+ outPos.push(srcPos.getX(v) - nx * innerShift, srcPos.getY(v) - ny * innerShift, srcPos.getZ(v) - nz * innerShift);
51
+ outNorm.push(-nx, -ny, -nz);
52
+ if (srcUv)
53
+ outUv.push(srcUv.getX(v), srcUv.getY(v));
54
+ }
55
+ const tris = buildTriList(srcIdx, vCount);
56
+ // Front faces (original winding)
57
+ for (const [a, b, c] of tris)
58
+ outIdx.push(a, b, c);
59
+ // Back faces (reversed winding)
60
+ for (const [a, b, c] of tris)
61
+ outIdx.push(a + vCount, c + vCount, b + vCount);
62
+ // Side walls — connect each edge of each triangle
63
+ for (const [a, b, c] of tris) {
64
+ const edges = [[a, b], [b, c], [c, a]];
65
+ for (const [e0, e1] of edges) {
66
+ outIdx.push(e0, e1, e1 + vCount);
67
+ outIdx.push(e0, e1 + vCount, e0 + vCount);
68
+ }
69
+ }
70
+ const result = new BufferGeometry();
71
+ result.setAttribute('position', new BufferAttribute(new Float32Array(outPos), 3));
72
+ result.setAttribute('normal', new BufferAttribute(new Float32Array(outNorm), 3));
73
+ if (outUv.length)
74
+ result.setAttribute('uv', new BufferAttribute(new Float32Array(outUv), 2));
75
+ result.setIndex(new BufferAttribute(new Uint32Array(outIdx), 1));
76
+ return result;
77
+ }
78
+ }
79
+ function buildTriList(idx, vCount) {
80
+ const tris = [];
81
+ if (idx) {
82
+ const ia = idx.array;
83
+ for (let i = 0; i < ia.length; i += 3)
84
+ tris.push([ia[i], ia[i + 1], ia[i + 2]]);
85
+ }
86
+ else {
87
+ for (let i = 0; i < vCount; i += 3)
88
+ tris.push([i, i + 1, i + 2]);
89
+ }
90
+ return tris;
91
+ }
92
+ //# sourceMappingURL=SolidifyModifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SolidifyModifier.js","sourceRoot":"","sources":["../../../src/modifiers/generate/SolidifyModifier.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,27 @@
1
+ import { BufferGeometry } from 'three';
2
+ import { BaseModifier } from '../../core/BaseModifier.js';
3
+ export interface SubdivisionModifierOptions {
4
+ levels?: number;
5
+ }
6
+ /**
7
+ * Subdivision Modifier — Blender "Subdivision Surface" modifier equivalent.
8
+ * Uses Loop subdivision — the correct algorithm for triangle meshes.
9
+ *
10
+ * Loop subdivision repositions BOTH new edge vertices AND existing vertices
11
+ * using weighted averages of their neighbors, producing smooth organic surfaces
12
+ * identical in character to Blender's Subdivision Surface modifier.
13
+ *
14
+ * New edge vertex: 3/8 * (v1 + v2) + 1/8 * (opposite1 + opposite2)
15
+ * Updated orig vertex: (1 - n*β) * v + β * sum(neighbors)
16
+ * where β = 3/16 for valence 3, else 3/(8n)
17
+ *
18
+ * parameters.levels: 1–4 (each level quadruples triangle count and smooths further)
19
+ */
20
+ export declare class SubdivisionModifier extends BaseModifier {
21
+ get name(): string;
22
+ parameters: Record<string, number>;
23
+ constructor(options?: SubdivisionModifierOptions);
24
+ apply(geometry: BufferGeometry): BufferGeometry;
25
+ private _loopSubdivide;
26
+ }
27
+ //# sourceMappingURL=SubdivisionModifier.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SubdivisionModifier.d.ts","sourceRoot":"","sources":["../../../src/modifiers/generate/SubdivisionModifier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAmB,MAAM,OAAO,CAAA;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAEzD,MAAM,WAAW,0BAA0B;IACzC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED;;;;;;;;;;;;;GAaG;AACH,qBAAa,mBAAoB,SAAQ,YAAY;IACnD,IAAI,IAAI,WAA2B;IAEnC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;gBAEtB,OAAO,GAAE,0BAA+B;IAKpD,KAAK,CAAC,QAAQ,EAAE,cAAc,GAAG,cAAc;IAO/C,OAAO,CAAC,cAAc;CAkKvB"}
@@ -0,0 +1,181 @@
1
+ import { BufferGeometry, BufferAttribute } from 'three';
2
+ import { BaseModifier } from '../../core/BaseModifier.js';
3
+ /**
4
+ * Subdivision Modifier — Blender "Subdivision Surface" modifier equivalent.
5
+ * Uses Loop subdivision — the correct algorithm for triangle meshes.
6
+ *
7
+ * Loop subdivision repositions BOTH new edge vertices AND existing vertices
8
+ * using weighted averages of their neighbors, producing smooth organic surfaces
9
+ * identical in character to Blender's Subdivision Surface modifier.
10
+ *
11
+ * New edge vertex: 3/8 * (v1 + v2) + 1/8 * (opposite1 + opposite2)
12
+ * Updated orig vertex: (1 - n*β) * v + β * sum(neighbors)
13
+ * where β = 3/16 for valence 3, else 3/(8n)
14
+ *
15
+ * parameters.levels: 1–4 (each level quadruples triangle count and smooths further)
16
+ */
17
+ export class SubdivisionModifier extends BaseModifier {
18
+ get name() { return 'Subdivision'; }
19
+ constructor(options = {}) {
20
+ super();
21
+ this.parameters = { levels: Math.round(options.levels ?? 1) };
22
+ }
23
+ apply(geometry) {
24
+ let geo = geometry;
25
+ const levels = Math.max(0, Math.min(4, Math.round(this.parameters.levels)));
26
+ for (let i = 0; i < levels; i++)
27
+ geo = this._loopSubdivide(geo);
28
+ return geo;
29
+ }
30
+ _loopSubdivide(geometry) {
31
+ const pos = geometry.getAttribute('position');
32
+ const uv = geometry.getAttribute('uv');
33
+ const idx = geometry.getIndex();
34
+ const vCount = pos.count;
35
+ // Build flat triangle list
36
+ const tris = [];
37
+ if (idx) {
38
+ const ia = idx.array;
39
+ for (let i = 0; i < ia.length; i += 3)
40
+ tris.push([ia[i], ia[i + 1], ia[i + 2]]);
41
+ }
42
+ else {
43
+ for (let i = 0; i < vCount; i += 3)
44
+ tris.push([i, i + 1, i + 2]);
45
+ }
46
+ // ── Build adjacency ────────────────────────────────────────────────────────
47
+ // For each edge, store the two triangle-opposite vertices
48
+ const edgeOpposites = new Map();
49
+ // For each vertex, store its ring of neighbors
50
+ const vertNeighbors = Array.from({ length: vCount }, () => new Set());
51
+ for (const [a, b, c] of tris) {
52
+ vertNeighbors[a].add(b);
53
+ vertNeighbors[a].add(c);
54
+ vertNeighbors[b].add(a);
55
+ vertNeighbors[b].add(c);
56
+ vertNeighbors[c].add(a);
57
+ vertNeighbors[c].add(b);
58
+ for (const [e0, e1, opp] of [[a, b, c], [b, c, a], [c, a, b]]) {
59
+ const key = e0 < e1 ? `${e0}_${e1}` : `${e1}_${e0}`;
60
+ if (!edgeOpposites.has(key))
61
+ edgeOpposites.set(key, []);
62
+ edgeOpposites.get(key).push(opp);
63
+ }
64
+ }
65
+ // ── New edge midpoint vertices (Loop formula) ──────────────────────────────
66
+ // Interior edge: 3/8*(v1+v2) + 1/8*(opp1+opp2)
67
+ // Boundary edge: 1/2*(v1+v2)
68
+ const edgeMidIndex = new Map();
69
+ const outPos = [];
70
+ const outUv = [];
71
+ const getP = (i) => [pos.getX(i), pos.getY(i), pos.getZ(i)];
72
+ const getU = (i) => uv ? [uv.getX(i), uv.getY(i)] : [0, 0];
73
+ const addVert = (p, u) => {
74
+ const i = outPos.length / 3;
75
+ outPos.push(p[0], p[1], p[2]);
76
+ outUv.push(u[0], u[1]);
77
+ return i;
78
+ };
79
+ // Compute new edge vertices
80
+ for (const [key, opps] of edgeOpposites.entries()) {
81
+ const [ai, bi] = key.split('_').map(Number);
82
+ const pa = getP(ai), pb = getP(bi);
83
+ const ua = getU(ai), ub = getU(bi);
84
+ let np, nu;
85
+ if (opps.length === 2) {
86
+ // Interior edge
87
+ const po1 = getP(opps[0]), po2 = getP(opps[1]);
88
+ const uo1 = getU(opps[0]), uo2 = getU(opps[1]);
89
+ np = [
90
+ 0.375 * (pa[0] + pb[0]) + 0.125 * (po1[0] + po2[0]),
91
+ 0.375 * (pa[1] + pb[1]) + 0.125 * (po1[1] + po2[1]),
92
+ 0.375 * (pa[2] + pb[2]) + 0.125 * (po1[2] + po2[2]),
93
+ ];
94
+ nu = [
95
+ 0.375 * (ua[0] + ub[0]) + 0.125 * (uo1[0] + uo2[0]),
96
+ 0.375 * (ua[1] + ub[1]) + 0.125 * (uo1[1] + uo2[1]),
97
+ ];
98
+ }
99
+ else {
100
+ // Boundary edge
101
+ np = [0.5 * (pa[0] + pb[0]), 0.5 * (pa[1] + pb[1]), 0.5 * (pa[2] + pb[2])];
102
+ nu = [0.5 * (ua[0] + ub[0]), 0.5 * (ua[1] + ub[1])];
103
+ }
104
+ edgeMidIndex.set(key, addVert(np, nu));
105
+ }
106
+ // ── Updated original vertices (Loop formula) ───────────────────────────────
107
+ // Interior vertex: (1 - n*β)*v + β*sum(neighbors)
108
+ // Boundary vertex: 3/4*v + 1/8*(neighbor1 + neighbor2) (only 2 boundary neighbors)
109
+ const origNewIndex = new Array(vCount);
110
+ for (let v = 0; v < vCount; v++) {
111
+ const neighbors = Array.from(vertNeighbors[v]);
112
+ const n = neighbors.length;
113
+ const pv = getP(v);
114
+ const uv_ = getU(v);
115
+ // Determine if boundary vertex (has any boundary edge = edge with only 1 opposite)
116
+ let isBoundary = false;
117
+ const boundaryNeighbors = [];
118
+ for (const nb of neighbors) {
119
+ const key = v < nb ? `${v}_${nb}` : `${nb}_${v}`;
120
+ if ((edgeOpposites.get(key)?.length ?? 0) === 1) {
121
+ isBoundary = true;
122
+ boundaryNeighbors.push(nb);
123
+ }
124
+ }
125
+ let np, nu;
126
+ if (isBoundary && boundaryNeighbors.length >= 2) {
127
+ // Boundary rule: 3/4*v + 1/8*(bn1 + bn2)
128
+ const pn1 = getP(boundaryNeighbors[0]), pn2 = getP(boundaryNeighbors[1]);
129
+ const un1 = getU(boundaryNeighbors[0]), un2 = getU(boundaryNeighbors[1]);
130
+ np = [
131
+ 0.75 * pv[0] + 0.125 * (pn1[0] + pn2[0]),
132
+ 0.75 * pv[1] + 0.125 * (pn1[1] + pn2[1]),
133
+ 0.75 * pv[2] + 0.125 * (pn1[2] + pn2[2]),
134
+ ];
135
+ nu = [
136
+ 0.75 * uv_[0] + 0.125 * (un1[0] + un2[0]),
137
+ 0.75 * uv_[1] + 0.125 * (un1[1] + un2[1]),
138
+ ];
139
+ }
140
+ else {
141
+ // Interior rule
142
+ const beta = n === 3 ? 3 / 16 : 3 / (8 * n);
143
+ const w = 1 - n * beta;
144
+ let sx = 0, sy = 0, sz = 0, su = 0, sv = 0;
145
+ for (const nb of neighbors) {
146
+ const pnb = getP(nb), unb = getU(nb);
147
+ sx += pnb[0];
148
+ sy += pnb[1];
149
+ sz += pnb[2];
150
+ su += unb[0];
151
+ sv += unb[1];
152
+ }
153
+ np = [w * pv[0] + beta * sx, w * pv[1] + beta * sy, w * pv[2] + beta * sz];
154
+ nu = [w * uv_[0] + beta * su, w * uv_[1] + beta * sv];
155
+ }
156
+ origNewIndex[v] = addVert(np, nu);
157
+ }
158
+ // ── Build new index ────────────────────────────────────────────────────────
159
+ const outIdx = [];
160
+ const getMid = (a, b) => {
161
+ const key = a < b ? `${a}_${b}` : `${b}_${a}`;
162
+ return edgeMidIndex.get(key);
163
+ };
164
+ for (const [a, b, c] of tris) {
165
+ const oa = origNewIndex[a], ob = origNewIndex[b], oc = origNewIndex[c];
166
+ const ab = getMid(a, b), bc = getMid(b, c), ca = getMid(c, a);
167
+ outIdx.push(oa, ab, ca);
168
+ outIdx.push(ab, ob, bc);
169
+ outIdx.push(ca, bc, oc);
170
+ outIdx.push(ab, bc, ca);
171
+ }
172
+ const result = new BufferGeometry();
173
+ result.setAttribute('position', new BufferAttribute(new Float32Array(outPos), 3));
174
+ if (uv)
175
+ result.setAttribute('uv', new BufferAttribute(new Float32Array(outUv), 2));
176
+ result.setIndex(new BufferAttribute(new Uint32Array(outIdx), 1));
177
+ result.computeVertexNormals();
178
+ return result;
179
+ }
180
+ }
181
+ //# sourceMappingURL=SubdivisionModifier.js.map