@voluma/vlam 0.2.1 → 0.2.3

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/README.md CHANGED
@@ -16,9 +16,7 @@ Local site and generated API: `npm run dev` (http://localhost:5170, viewer at `/
16
16
  > Package `@voluma/vlam`, public **0.2.0**. APIs may still move before 1.0.
17
17
 
18
18
  ## Important notice!
19
- This is a pre-release. The API can still change in breaking ways before v1.0. Great for prototypes and experiments, not yet recommended for production.
20
-
21
- Phones and laptops with integrated graphics, like a MacBook Air, still need a lot of testing and tuning. Frame rate and image quality on those devices are not final.
19
+ This is a pre-release not yet recommended for production. The API can still change in breaking ways before v1.0.
22
20
 
23
21
 
24
22
  ## Install
package/dist/effects.d.ts CHANGED
@@ -15,6 +15,12 @@
15
15
  * tiles (or raw geometries) for PlayCanvas-style {@link SplatMesh.setRelighting}.
16
16
  * - {@link createRelightingShadowFactorMaterial}: writes a shadow **multiplier**
17
17
  * (1 = lit, <1 = umbra) so coverage does not statically tint splats.
18
+ * Accepts one light or {@link RelightingLightContribution}[] with intensity
19
+ * weights. Optional `color` / `diffuse` / `direction` add a Lambert boost on
20
+ * top of that identity (RGB may exceed 1 on a HalfFloat lighting RT).
21
+ * - {@link renderRelightingFactorMap}: host-safe lighting pass. Isolates
22
+ * `autoClear`, shadow maps, and swaps a passthrough `contextNode` so the
23
+ * example works on an existing `WebGPURenderer`, not only `createSplatRenderer`.
18
24
  * - {@link worldWarpPreset}: camera-centered sphere wrap (planet / bowl).
19
25
  * - {@link depthOfFieldPreset}: stylized modifier-based depth-of-field (M13).
20
26
  * For physically-modeled camera DoF prefer the core
@@ -262,6 +268,7 @@ export declare function worldWarpPreset(options?: {
262
268
  intensity?: number;
263
269
  radius?: number;
264
270
  }): WorldWarpPreset;
271
+ export { renderRelightingFactorMap, type RelightingFactorRenderer } from './relighting-pass';
265
272
  /** Handle returned by {@link createRelightingProxy}. */
266
273
  export interface RelightingProxy {
267
274
  /** World-space group of lit proxy meshes (hide from the main splat scene). */
@@ -274,14 +281,68 @@ export interface RelightingProxy {
274
281
  /** Disposes geometries and the default material owned by this helper. */
275
282
  dispose(): void;
276
283
  }
284
+ /** One independent shadow-casting light for {@link createRelightingShadowFactorMaterial}. */
285
+ export type RelightingLightContribution = {
286
+ light: THREE.Light;
287
+ /** Relative umbra weight. Default `1`. Values `<= 0` are skipped. */
288
+ intensity?: number;
289
+ };
290
+ /** Options for {@link createRelightingShadowFactorMaterial}. */
291
+ export type RelightingShadowFactorOptions = {
292
+ umbra?: number;
293
+ receiveUpMin?: number;
294
+ color?: THREE.Color;
295
+ diffuse?: number;
296
+ direction?: THREE.Vector3;
297
+ /**
298
+ * How independent contributions combine into one multiplier.
299
+ * - `average` (default): intensity-weighted mean of shadows (fill lights).
300
+ * - `min`: union of umbras — each caster keeps its own silhouette. Contribution
301
+ * `intensity` scales umbra depth: `0` → none, `1` → default `umbra`,
302
+ * `>1` → darker than default (`umbra_i = clamp(1 - I*(1-umbra), 0, 1)`).
303
+ */
304
+ combine?: 'average' | 'min';
305
+ midLight?: THREE.Light;
306
+ midRadius?: number;
307
+ outerLight?: THREE.Light;
308
+ outerRadius?: number;
309
+ farLight?: THREE.Light;
310
+ nearRadius?: number;
311
+ };
312
+ /**
313
+ * Cap on independent shadow lights (cascades of the first directional do not
314
+ * count). Extra contributions are ignored. The compiled graph unrolls only
315
+ * the live contribution count, not a padded 32-wide loop.
316
+ */
317
+ export declare const MAX_RELIGHTING_SHADOW_LIGHTS = 32;
277
318
  /**
278
319
  * Node material for a **shadow-factor** lighting RT used with
279
320
  * {@link SplatMesh.setRelighting}.
280
321
  *
281
- * Fragment output is `vec4(vec3(mix(umbra, 1, shadow(light))), 1)`:
322
+ * Fragment output is `vec4(vec3(mix(umbra, 1, shadow)) + boost, 1)`:
282
323
  * - covered + lit → RGB ≈ 1 (identity modulate when brightness/background are 1)
283
324
  * - covered + umbra → RGB ≈ `umbra` (soft darken; never pure black)
284
325
  * - uncovered stays clear-alpha 0 from the RT clear
326
+ * - with `diffuse` &gt; 0, facing surfaces add `color * NdotL * diffuse`
327
+ * (RGB may exceed 1; use a HalfFloat lighting RT)
328
+ *
329
+ * Pass one {@link THREE.Light} (demo / single-sun) or an array of
330
+ * {@link RelightingLightContribution} so independent lights share one
331
+ * multiplier. Default combine is intensity-weighted average
332
+ * (`illum = sum(I_i * shadow_i) / sum(I_i)`); pass `combine: 'min'` for a
333
+ * union of umbras so each caster keeps its silhouette. Spot / point lights
334
+ * with `distance &gt; 0` fade their umbra to lit via a Frostbite cutoff window
335
+ * (steepened by `decay`) so the shadow map far plane is not a hard cliff.
336
+ * Cascades (`midLight` / `outerLight` / `farLight`) still attach to the
337
+ * **first** directional only. At most {@link MAX_RELIGHTING_SHADOW_LIGHTS}
338
+ * independent lights are used; extras are ignored. Graph size follows the
339
+ * live contribution count (not a padded loop of that width).
340
+ *
341
+ * By default, only **upward** proxy faces receive (`receiveUpMin`). Vertical
342
+ * and noisy foliage triangles still **cast**, but they do not self-shadow —
343
+ * that PCF acne reads as per-frame sparkle in trees. Pass `receiveUpMin: 0`
344
+ * to receive on every face. The Lambert term uses the same slope gate, so
345
+ * steep foliage does not pick up a noisy tint.
285
346
  *
286
347
  * Clear the lighting RT to **RGB 1, A 0** (not black). Softness / bilinear
287
348
  * samples at coverage edges otherwise pull in black and draw a dark outline
@@ -292,12 +353,36 @@ export interface RelightingProxy {
292
353
  * Assign to proxy meshes with `castShadow` and `receiveShadow` both true; the
293
354
  * umbra shape follows those triangles (splat foliage cannot cast).
294
355
  *
295
- * @param light - Shadow-casting light (typically a {@link THREE.DirectionalLight}).
356
+ * @param lights - Shadow-casting light, or intensity-weighted contributions.
357
+ * The first entry is the innermost cascade when `midLight` / `outerLight` /
358
+ * `farLight` are set.
296
359
  * @param options.umbra - Multiplier in full shadow, in `[0, 1]`. Default `0.45`.
360
+ * @param options.receiveUpMin - World-up `normal.y` below which the face does
361
+ * not receive. Default `0.25`. `0` disables the slope gate.
362
+ * @param options.color - Light tint for the optional Lambert boost. Mutate
363
+ * in place; the material holds this object. Default white.
364
+ * @param options.diffuse - Lambert boost on top of identity. Default `0`
365
+ * (shadow multiplier only). Facing, unshadowed coverage becomes
366
+ * `1 + color * NdotL * diffuse`.
367
+ * @param options.direction - World-space direction **toward** the light.
368
+ * Mutate in place each frame as the sun moves. Default `(0, 1, 0)`.
369
+ * @param options.midLight - Optional mid cascade (demo: ~50 m). Blend from
370
+ * the first light over `nearRadius`.
371
+ * @param options.midRadius - World metres where the mid cascade yields to
372
+ * `outerLight` (or `farLight`). Default `50`.
373
+ * @param options.outerLight - Optional outer cascade (demo: ~160 m) between
374
+ * mid and scene-sized far. Blend from mid over `midRadius`, then to
375
+ * `farLight` over `outerRadius`.
376
+ * @param options.outerRadius - World metres where the outer cascade yields to
377
+ * `farLight`. Default `160`. Ignored without `outerLight` and `farLight`.
378
+ * @param options.farLight - Optional scene-sized cascade. Out-of-frustum
379
+ * `shadow()` is 1 (lit), so inner maps can stay tight without clipping
380
+ * distant umbras. Blend by camera distance.
381
+ * @param options.nearRadius - World metres where the inner cascade yields to
382
+ * `midLight` (or to `farLight` if there is no mid). Default `20` with
383
+ * `midLight`, else `100`.
297
384
  */
298
- export declare function createRelightingShadowFactorMaterial(light: THREE.Light, options?: {
299
- umbra?: number;
300
- }): THREE.MeshStandardNodeMaterial;
385
+ export declare function createRelightingShadowFactorMaterial(lights: THREE.Light | RelightingLightContribution[], options?: RelightingShadowFactorOptions): THREE.MeshStandardNodeMaterial;
301
386
  /**
302
387
  * Builds a PlayCanvas-style relighting **proxy** from collision tiles or raw
303
388
  * geometries. The host places {@link RelightingProxy.group} on a dedicated
package/dist/effects.js CHANGED
@@ -1,87 +1,100 @@
1
- import * as g from "three/webgpu";
2
- import { shadow as te, mix as x, float as i, vec4 as O, vec3 as h, uniform as C, wgslFn as se, uniformArray as ne, smoothstep as X, int as oe, mat3 as re, modelViewMatrix as ae, vec2 as ce } from "three/tsl";
3
- import { w as ie } from "./logging-BfPdd7NJ.js";
4
- const Q = 5, le = { tint: 0, desaturate: 1, hide: 2, rim: 3 }, de = [0, 0, 0], ue = [1, 1, 1], fe = [0, 0, 0, 1];
5
- function ye(o = [], n = {}) {
6
- const r = Math.max(1, Math.floor(n.maxShapes ?? 32)), t = [];
7
- for (let e = 0; e < r * Q; e++) t.push(new g.Vector4());
8
- const d = ne(t, "vec4"), f = C(0, "int");
9
- let u = !1;
10
- const l = (e) => {
11
- const m = Math.min(e.length, r);
12
- e.length > r && !u && (u = !0, ie(
13
- `sdfEffects: ${e.length} shapes exceeds maxShapes=${r}; extra shapes are ignored. Raise maxShapes if you need more.`
1
+ import * as p from "three/webgpu";
2
+ import { context as ct, positionWorld as et, cameraPosition as rt, smoothstep as O, float as a, normalWorld as Z, mix as b, min as lt, uniform as C, vec4 as A, vec3 as M, wgslFn as ut, uniformArray as dt, shadow as S, int as ft, mat3 as mt, modelViewMatrix as ht, vec2 as gt } from "three/tsl";
3
+ import { w as xt } from "./logging-BfPdd7NJ.js";
4
+ const J = new p.Vector2(), tt = new p.Color(), bt = ct({
5
+ getOutput: (t) => t
6
+ });
7
+ function Nt(t, e, r, i) {
8
+ t.getDrawingBufferSize(J), i.setSize(Math.max(1, J.x), Math.max(1, J.y));
9
+ const f = t.getRenderTarget(), u = t.getActiveCubeFace(), d = t.getActiveMipmapLevel(), n = t.getMRT(), h = t.getClearAlpha(), s = t.autoClear, m = t.shadowMap.enabled, l = t.shadowMap.autoUpdate, o = t.contextNode;
10
+ t.getClearColor(tt);
11
+ try {
12
+ t.contextNode = bt, t.autoClear = !0, t.shadowMap.enabled = !0, l === !1 && (t.shadowMap.autoUpdate = !0), t.setMRT(null), t.setRenderTarget(i), t.setClearColor(16777215, 0), t.clear(), t.render(e, r);
13
+ } finally {
14
+ t.setRenderTarget(f, u, d), t.setMRT(n), t.setClearColor(tt, h), t.autoClear = s, t.shadowMap.enabled = m, l !== void 0 && (t.shadowMap.autoUpdate = l), t.contextNode = o;
15
+ }
16
+ }
17
+ const K = 5, pt = { tint: 0, desaturate: 1, hide: 2, rim: 3 }, wt = [0, 0, 0], Mt = [1, 1, 1], yt = [0, 0, 0, 1];
18
+ function Ft(t = [], e = {}) {
19
+ const r = Math.max(1, Math.floor(e.maxShapes ?? 32)), i = [];
20
+ for (let s = 0; s < r * K; s++) i.push(new p.Vector4());
21
+ const f = dt(i, "vec4"), u = C(0, "int");
22
+ let d = !1;
23
+ const n = (s) => {
24
+ const m = Math.min(s.length, r);
25
+ s.length > r && !d && (d = !0, xt(
26
+ `sdfEffects: ${s.length} shapes exceeds maxShapes=${r}; extra shapes are ignored. Raise maxShapes if you need more.`
14
27
  ));
15
- for (let c = 0; c < m; c++) {
16
- const s = e[c];
17
- if (s.kind === "box") {
18
- const a = s.halfExtents;
19
- if (!a || !(a[0] > 0) || !(a[1] > 0) || !(a[2] > 0))
28
+ for (let l = 0; l < m; l++) {
29
+ const o = s[l];
30
+ if (o.kind === "box") {
31
+ const c = o.halfExtents;
32
+ if (!c || !(c[0] > 0) || !(c[1] > 0) || !(c[2] > 0))
20
33
  throw new Error(
21
- `sdfEffects.setShapes: shape ${c} is a box and requires halfExtents with three positive components (got ${a ? `[${a.join(", ")}]` : "undefined"}).`
34
+ `sdfEffects.setShapes: shape ${l} is a box and requires halfExtents with three positive components (got ${c ? `[${c.join(", ")}]` : "undefined"}).`
22
35
  );
23
- } else if (typeof s.radius == "number" && s.radius > 0) {
24
- if (s.kind === "cylinder" && !(typeof s.height == "number" && s.height > 0))
36
+ } else if (typeof o.radius == "number" && o.radius > 0) {
37
+ if (o.kind === "cylinder" && !(typeof o.height == "number" && o.height > 0))
25
38
  throw new Error(
26
- `sdfEffects.setShapes: shape ${c} is a cylinder and requires a positive height (got ${String(s.height)}).`
39
+ `sdfEffects.setShapes: shape ${l} is a cylinder and requires a positive height (got ${String(o.height)}).`
27
40
  );
28
41
  } else throw new Error(
29
- `sdfEffects.setShapes: shape ${c} is a ${s.kind} and requires a positive radius (got ${String(s.radius)}).`
42
+ `sdfEffects.setShapes: shape ${l} is a ${o.kind} and requires a positive radius (got ${String(o.radius)}).`
30
43
  );
31
44
  }
32
- for (let c = 0; c < m; c++) {
33
- const s = e[c], a = c * Q, w = s.center ?? de, p = s.color ?? ue, y = s.rotation ?? fe, E = s.kind === "box" ? 1 : s.kind === "cylinder" ? 2 : 0;
34
- if (t[a + 0].set(w[0], w[1], w[2], E), s.kind === "box") {
35
- const v = s.halfExtents;
36
- t[a + 1].set(v[0], v[1], v[2], s.falloff ?? 0);
37
- } else s.kind === "cylinder" ? t[a + 1].set(
38
- s.radius,
39
- s.height / 2,
45
+ for (let l = 0; l < m; l++) {
46
+ const o = s[l], c = l * K, x = o.center ?? wt, g = o.color ?? Mt, w = o.rotation ?? yt, v = o.kind === "box" ? 1 : o.kind === "cylinder" ? 2 : 0;
47
+ if (i[c + 0].set(x[0], x[1], x[2], v), o.kind === "box") {
48
+ const y = o.halfExtents;
49
+ i[c + 1].set(y[0], y[1], y[2], o.falloff ?? 0);
50
+ } else o.kind === "cylinder" ? i[c + 1].set(
51
+ o.radius,
52
+ o.height / 2,
40
53
  0,
41
- s.falloff ?? 0
42
- ) : t[a + 1].set(s.radius, 0, 0, s.falloff ?? 0);
43
- t[a + 2].set(p[0], p[1], p[2], le[s.mode]), t[a + 3].set(y[0], y[1], y[2], y[3]), t[a + 4].set(s.invert ? 1 : 0, s.strength ?? 1, 0, 0);
54
+ o.falloff ?? 0
55
+ ) : i[c + 1].set(o.radius, 0, 0, o.falloff ?? 0);
56
+ i[c + 2].set(g[0], g[1], g[2], pt[o.mode]), i[c + 3].set(w[0], w[1], w[2], w[3]), i[c + 4].set(o.invert ? 1 : 0, o.strength ?? 1, 0, 0);
44
57
  }
45
- f.value = m;
58
+ u.value = m;
46
59
  };
47
- return l(o), { modifier: (e) => {
48
- const m = e.localCenter;
49
- let c = e.color.rgb, s = i(1);
50
- for (let a = 0; a < r; a++) {
51
- const w = a * Q, p = (ee) => d.element(w + ee), y = p(0), E = p(1), v = p(2), R = p(3), D = p(4), U = y.xyz, P = y.w, T = E.xyz, $ = E.w.max(1e-4), B = v.xyz, M = v.w, L = D.x, N = D.y, V = oe(a).lessThan(f).select(i(1), i(0)), I = m.sub(U), z = xe(R, I), A = z.length().sub(T.x), k = me(z, T), q = he(z, T.x, T.y), F = P.greaterThan(0.5).and(P.lessThan(1.5)).select(i(1), i(0)), G = P.greaterThan(1.5).select(i(1), i(0)), W = x(x(A, k, F), q, G), _ = x(W, W.negate(), L), S = i(1).sub(X(0, $, _)).mul(N).mul(V), j = i(1).sub(X(0, $, _.abs())).mul(N).mul(V), H = M.lessThan(0.5).select(i(1), i(0)), J = M.greaterThan(0.5).and(M.lessThan(1.5)).select(i(1), i(0)), K = M.greaterThan(1.5).and(M.lessThan(2.5)).select(i(1), i(0)), Y = M.greaterThan(2.5).select(i(1), i(0)), Z = c.dot(h(0.2126, 0.7152, 0.0722));
52
- c = x(c, B, S.mul(H)), c = x(c, h(Z), S.mul(J)), c = x(c, B, j.mul(Y)), s = s.mul(i(1).sub(S.mul(K)));
60
+ return n(t), { modifier: (s) => {
61
+ const m = s.localCenter;
62
+ let l = s.color.rgb, o = a(1);
63
+ for (let c = 0; c < r; c++) {
64
+ const x = c * K, g = (it) => f.element(x + it), w = g(0), v = g(1), y = g(2), L = g(3), N = g(4), j = w.xyz, F = w.w, k = v.xyz, U = v.w.max(1e-4), _ = y.xyz, T = y.w, X = N.x, I = N.y, B = ft(c).lessThan(u).select(a(1), a(0)), G = m.sub(j), z = Tt(L, G), D = z.length().sub(k.x), R = vt(z, k), V = Ct(z, k.x, k.y), P = F.greaterThan(0.5).and(F.lessThan(1.5)).select(a(1), a(0)), W = F.greaterThan(1.5).select(a(1), a(0)), $ = b(b(D, R, P), V, W), q = b($, $.negate(), X), E = a(1).sub(O(0, U, q)).mul(I).mul(B), H = a(1).sub(O(0, U, q.abs())).mul(I).mul(B), Q = T.lessThan(0.5).select(a(1), a(0)), ot = T.greaterThan(0.5).and(T.lessThan(1.5)).select(a(1), a(0)), st = T.greaterThan(1.5).and(T.lessThan(2.5)).select(a(1), a(0)), nt = T.greaterThan(2.5).select(a(1), a(0)), at = l.dot(M(0.2126, 0.7152, 0.0722));
65
+ l = b(l, _, E.mul(Q)), l = b(l, M(at), E.mul(ot)), l = b(l, _, H.mul(nt)), o = o.mul(a(1).sub(E.mul(st)));
53
66
  }
54
- return { color: O(c, e.color.a.mul(s)) };
55
- }, setShapes: l, maxShapes: r, _uniforms: { slots: t, count: f } };
67
+ return { color: A(l, s.color.a.mul(o)) };
68
+ }, setShapes: n, maxShapes: r, _uniforms: { slots: i, count: u } };
56
69
  }
57
- function me(o, n) {
58
- const r = o.abs().sub(n), t = r.max(h(0, 0, 0)).length(), d = r.x.max(r.y.max(r.z)).min(0);
59
- return t.add(d);
70
+ function vt(t, e) {
71
+ const r = t.abs().sub(e), i = r.max(M(0, 0, 0)).length(), f = r.x.max(r.y.max(r.z)).min(0);
72
+ return i.add(f);
60
73
  }
61
- function he(o, n, r) {
62
- const t = o.xz.length().sub(n), d = o.y.abs().sub(r), f = ce(t.max(0), d.max(0)).length(), u = t.max(d).min(0);
63
- return f.add(u);
74
+ function Ct(t, e, r) {
75
+ const i = t.xz.length().sub(e), f = t.y.abs().sub(r), u = gt(i.max(0), f.max(0)).length(), d = i.max(f).min(0);
76
+ return u.add(d);
64
77
  }
65
- function xe(o, n) {
66
- const r = o.xyz, t = o.w, d = r.cross(n).mul(2);
67
- return n.sub(d.mul(t)).add(r.cross(d));
78
+ function Tt(t, e) {
79
+ const r = t.xyz, i = t.w, f = r.cross(e).mul(2);
80
+ return e.sub(f.mul(i)).add(r.cross(f));
68
81
  }
69
- function we(o = {}) {
70
- const n = new g.Vector3(...o.direction ?? [0.3, 1, 0.6]).normalize(), r = C(n), t = i(o.ambient ?? 0.35), d = i(o.diffuse ?? 0.75);
71
- return { modifier: (u) => {
72
- const l = u.normal.dot(r.normalize()).max(0), b = t.add(l.mul(d));
73
- return { color: O(u.color.rgb.mul(b), u.color.a) };
82
+ function Dt(t = {}) {
83
+ const e = new p.Vector3(...t.direction ?? [0.3, 1, 0.6]).normalize(), r = C(e), i = a(t.ambient ?? 0.35), f = a(t.diffuse ?? 0.75);
84
+ return { modifier: (d) => {
85
+ const n = d.normal.dot(r.normalize()).max(0), h = i.add(n.mul(f));
86
+ return { color: A(d.color.rgb.mul(h), d.color.a) };
74
87
  }, direction: r };
75
88
  }
76
- function ve(o = {}) {
77
- const n = C(Math.max(1e-4, o.focusDistance ?? 10)), r = C(Math.max(0, o.aperture ?? 0.5)), t = i(Math.max(0, o.maxBlur ?? 6));
78
- return { modifier: (f) => {
79
- const u = f.viewCenter.z.negate().max(1e-4), l = n.max(1e-4), b = u.sub(l).abs().div(l).mul(r).min(t), e = i(1).add(b), m = f.color.a.div(e.mul(e));
80
- return { scale: f.scale.mul(e), color: O(f.color.rgb, m) };
81
- }, focusDistance: n, aperture: r };
89
+ function Pt(t = {}) {
90
+ const e = C(Math.max(1e-4, t.focusDistance ?? 10)), r = C(Math.max(0, t.aperture ?? 0.5)), i = a(Math.max(0, t.maxBlur ?? 6));
91
+ return { modifier: (u) => {
92
+ const d = u.viewCenter.z.negate().max(1e-4), n = e.max(1e-4), h = d.sub(n).abs().div(n).mul(r).min(i), s = a(1).add(h), m = u.color.a.div(s.mul(s));
93
+ return { scale: u.scale.mul(s), color: A(u.color.rgb, m) };
94
+ }, focusDistance: e, aperture: r };
82
95
  }
83
- function Me(o = {}) {
84
- const n = C(0), r = o.frequency ?? 3, t = Math.min(Math.max(o.edge ?? 0.08, 0), 0.5), d = se(
96
+ function Ot(t = {}) {
97
+ const e = C(0), r = t.frequency ?? 3, i = Math.min(Math.max(t.edge ?? 0.08, 0), 0.5), f = ut(
85
98
  /* wgsl */
86
99
  `
87
100
  fn vnoise( x: vec3<f32> ) -> f32 {
@@ -108,73 +121,129 @@ function Me(o = {}) {
108
121
  }
109
122
  `
110
123
  );
111
- return { modifier: (u) => {
112
- const l = d({ x: u.localCenter.mul(r) }), b = l.mul(1 - 2 * t).add(t), e = X(b.sub(t), b.add(t), n), m = n.greaterThan(b.sub(t));
113
- return { color: O(u.color.rgb, u.color.a.mul(e)), visible: m };
114
- }, progress: n };
115
- }
116
- function ke(o = {}) {
117
- const n = C(Math.min(1, Math.max(-1, o.intensity ?? 0))), r = C(Math.max(1e-4, o.radius ?? 1));
118
124
  return { modifier: (d) => {
119
- const f = n.clamp(-1, 1), u = r.max(1e-4), l = d.viewCenter, b = f.max(0), e = f.negate().max(0), m = l.z.negate().max(0), c = m.div(u).atan().mul(i(Math.PI * 0.5)), s = c.cos(), a = c.sin(), w = a.negate(), p = h(l.x, l.y.mul(s).sub(l.z.mul(a)), l.y.mul(a).add(l.z.mul(s))), y = h(l.x, l.y.mul(s).sub(l.z.mul(w)), l.y.mul(w).add(l.z.mul(s))), E = x(x(l, p, e), y, b), v = i(Math.PI * 0.5).mul(u), R = l.z.lessThan(0).select(v.negate().div(m.mul(m).add(u.mul(u))), i(0)), D = R.negate(), U = h(1, 0, 0), P = h(0, s, a), T = h(0, a.negate().sub(p.z.mul(R)), s.add(p.y.mul(R))), $ = h(1, 0, 0), B = h(0, s, w), M = h(
125
+ const n = f({ x: d.localCenter.mul(r) }), h = n.mul(1 - 2 * i).add(i), s = O(h.sub(i), h.add(i), e), m = e.greaterThan(h.sub(i));
126
+ return { color: A(d.color.rgb, d.color.a.mul(s)), visible: m };
127
+ }, progress: e };
128
+ }
129
+ function Ut(t = {}) {
130
+ const e = C(Math.min(1, Math.max(-1, t.intensity ?? 0))), r = C(Math.max(1e-4, t.radius ?? 1));
131
+ return { modifier: (f) => {
132
+ const u = e.clamp(-1, 1), d = r.max(1e-4), n = f.viewCenter, h = u.max(0), s = u.negate().max(0), m = n.z.negate().max(0), l = m.div(d).atan().mul(a(Math.PI * 0.5)), o = l.cos(), c = l.sin(), x = c.negate(), g = M(n.x, n.y.mul(o).sub(n.z.mul(c)), n.y.mul(c).add(n.z.mul(o))), w = M(n.x, n.y.mul(o).sub(n.z.mul(x)), n.y.mul(x).add(n.z.mul(o))), v = b(b(n, g, s), w, h), y = a(Math.PI * 0.5).mul(d), L = n.z.lessThan(0).select(y.negate().div(m.mul(m).add(d.mul(d))), a(0)), N = L.negate(), j = M(1, 0, 0), F = M(0, o, c), k = M(0, c.negate().sub(g.z.mul(L)), o.add(g.y.mul(L))), U = M(1, 0, 0), _ = M(0, o, x), T = M(
120
133
  0,
121
- w.negate().sub(y.z.mul(D)),
122
- s.add(y.y.mul(D))
123
- ), L = h(1, 0, 0), N = h(0, 1, 0), V = h(0, 0, 1), I = x(x(L, U, e), $, b), z = x(x(N, P, e), B, b), A = x(x(V, T, e), M, b), k = I.div(I.length().max(1e-6)), q = z.sub(k.mul(k.dot(z))), F = q.div(q.length().max(1e-6)), G = A.sub(k.mul(k.dot(A))).sub(F.mul(F.dot(A))), W = G.div(G.length().max(1e-6)), _ = re(k, F, W), S = ae.toMat3(), j = S.transpose(), H = j.mul(_).mul(S);
134
+ x.negate().sub(w.z.mul(N)),
135
+ o.add(w.y.mul(N))
136
+ ), X = M(1, 0, 0), I = M(0, 1, 0), B = M(0, 0, 1), G = b(b(X, j, s), U, h), z = b(b(I, F, s), _, h), D = b(b(B, k, s), T, h), R = G.div(G.length().max(1e-6)), V = z.sub(R.mul(R.dot(z))), P = V.div(V.length().max(1e-6)), W = D.sub(R.mul(R.dot(D))).sub(P.mul(P.dot(D))), $ = W.div(W.length().max(1e-6)), q = mt(R, P, $), E = ht.toMat3(), H = E.transpose(), Q = H.mul(q).mul(E);
124
137
  return {
125
- offset: d.offset.add(j.mul(E.sub(l))),
126
- rotation: H.mul(d.rotation)
138
+ offset: f.offset.add(H.mul(v.sub(n))),
139
+ rotation: Q.mul(f.rotation)
127
140
  };
128
- }, intensity: n, radius: r };
141
+ }, intensity: e, radius: r };
129
142
  }
130
- function Ce(o, n = {}) {
131
- const r = Number.isFinite(n.umbra) ? Math.min(1, Math.max(0, n.umbra)) : 0.45, t = new g.MeshStandardNodeMaterial();
132
- t.side = g.DoubleSide, t.color = new g.Color(1, 1, 1), t.roughness = 1, t.metalness = 0, t.transparent = !1, t.depthWrite = !0, t.polygonOffset = !0, t.polygonOffsetFactor = 1, t.polygonOffsetUnits = 1;
133
- const d = te(o), f = x(i(r), i(1), d);
134
- return t.outputNode = O(h(f), i(1)), t;
143
+ const Rt = 32, Y = (t) => {
144
+ const e = t.intensity;
145
+ return Number.isFinite(e) ? Math.max(0, e) : 1;
146
+ }, St = (t) => {
147
+ const e = t;
148
+ if (!(e.isSpotLight === !0 || e.isPointLight === !0)) return a(1);
149
+ const i = Number(e.distance);
150
+ if (!(i > 0)) return a(1);
151
+ const f = Math.max(Number(e.decay) || 1, 0.01), u = et.distance(C(e.position)), d = u.div(a(i)).pow4().oneMinus().clamp().pow2();
152
+ return d.pow(a(f));
153
+ }, kt = (t) => {
154
+ const e = Array.isArray(t) ? t : [{ light: t, intensity: 1 }], r = [];
155
+ for (const i of e) {
156
+ if (r.length >= Rt) break;
157
+ Y(i) <= 0 || r.push(i);
158
+ }
159
+ return r;
160
+ }, zt = (t, e, r) => {
161
+ const i = Number.isFinite(e.nearRadius) ? Math.max(1, e.nearRadius) : e.midLight ? 20 : 100, f = Number.isFinite(e.midRadius) ? Math.max(i, e.midRadius) : 50, u = Number.isFinite(e.outerRadius) ? Math.max(f, e.outerRadius) : 160, d = (h, s, m) => b(h, s, O(a(m * 0.7), a(m * 0.95), r));
162
+ let n = S(t);
163
+ return e.midLight ? (n = d(n, S(e.midLight), i), e.outerLight ? (n = d(n, S(e.outerLight), f), e.farLight && (n = d(n, S(e.farLight), u))) : e.farLight && (n = d(n, S(e.farLight), f))) : e.farLight && (n = d(n, S(e.farLight), i)), n;
164
+ };
165
+ function _t(t, e = {}) {
166
+ const r = Number.isFinite(e.umbra) ? Math.min(1, Math.max(0, e.umbra)) : 0.45, i = Number.isFinite(e.receiveUpMin) ? Math.min(0.95, Math.max(0, e.receiveUpMin)) : 0.25, f = Number.isFinite(e.diffuse) ? Math.max(0, e.diffuse) : 0, u = new p.MeshStandardNodeMaterial();
167
+ u.side = p.DoubleSide, u.color = new p.Color(1, 1, 1), u.roughness = 1, u.metalness = 0, u.transparent = !1, u.depthWrite = !0, u.polygonOffset = !0, u.polygonOffsetFactor = 2, u.polygonOffsetUnits = 2;
168
+ const d = et.distance(rt), n = kt(t), h = i > 0 ? O(a(i), a(i + 0.3), Z.y) : a(1), s = (o, c) => {
169
+ const x = o === 0 ? zt(c, e, d) : S(c);
170
+ return b(a(1), x, St(c));
171
+ };
172
+ let m, l = a(1);
173
+ if (e.combine === "min" && n.length > 0) {
174
+ let o = a(1);
175
+ for (let c = 0; c < n.length; c++) {
176
+ const x = n[c], g = Y(x), w = Math.min(1, Math.max(0, 1 - g * (1 - r))), v = s(c, x.light), y = b(a(w), a(1), v);
177
+ o = lt(o, y);
178
+ }
179
+ l = o, m = b(a(1), o, h);
180
+ } else {
181
+ if (n.length === 1)
182
+ l = s(0, n[0].light);
183
+ else if (n.length > 1) {
184
+ let c = a(0), x = 0;
185
+ for (let g = 0; g < n.length; g++) {
186
+ const w = n[g], v = Y(w);
187
+ x += v;
188
+ const y = s(g, w.light);
189
+ c = c.add(a(v).mul(y));
190
+ }
191
+ l = x > 0 ? c.div(a(x)) : a(1);
192
+ }
193
+ const o = b(a(1), l, h);
194
+ m = b(a(r), a(1), o);
195
+ }
196
+ if (f > 0) {
197
+ const o = C(e.color ?? new p.Color(1, 1, 1)), c = C(e.direction ?? new p.Vector3(0, 1, 0)), x = Z.dot(c.normalize()).max(0), g = o.mul(x).mul(a(f)).mul(h).mul(l);
198
+ u.outputNode = A(M(m).add(g), a(1));
199
+ } else
200
+ u.outputNode = A(M(m), a(1));
201
+ return u;
135
202
  }
136
- function ge(o) {
137
- const n = new g.BufferGeometry();
138
- return n.setAttribute("position", new g.BufferAttribute(o.positions.slice(), 3)), n.setIndex(new g.BufferAttribute(o.indices.slice(), 1)), n;
203
+ function Et(t) {
204
+ const e = new p.BufferGeometry();
205
+ return e.setAttribute("position", new p.BufferAttribute(t.positions.slice(), 3)), e.setIndex(new p.BufferAttribute(t.indices.slice(), 1)), e;
139
206
  }
140
- function Ee(o = {}) {
141
- const n = o.albedo ?? 0.5, r = new g.Group(), t = o.matrixWorld ?? null, d = [], f = new g.MeshStandardMaterial({
142
- color: new g.Color(n, n, n),
207
+ function It(t = {}) {
208
+ const e = t.albedo ?? 0.5, r = new p.Group(), i = t.matrixWorld ?? null, f = [], u = new p.MeshStandardMaterial({
209
+ color: new p.Color(e, e, e),
143
210
  roughness: 1,
144
211
  metalness: 0,
145
- side: g.DoubleSide
146
- }), u = (e) => {
147
- t && e.applyMatrix4(t);
148
- }, l = (e, m) => {
149
- let c = e, s = m;
150
- t && !m && (c = e.clone(), s = !0), u(c), c.computeVertexNormals(), s && d.push(c);
151
- const a = new g.Mesh(c, f);
152
- a.castShadow = !0, a.receiveShadow = !0, a.raycast = () => {
153
- }, r.add(a);
212
+ side: p.DoubleSide
213
+ }), d = (s) => {
214
+ i && s.applyMatrix4(i);
215
+ }, n = (s, m) => {
216
+ let l = s, o = m;
217
+ i && !m && (l = s.clone(), o = !0), d(l), l.computeVertexNormals(), o && f.push(l);
218
+ const c = new p.Mesh(l, u);
219
+ c.castShadow = !0, c.receiveShadow = !0, c.raycast = () => {
220
+ }, r.add(c);
154
221
  };
155
- for (const e of o.tiles ?? [])
156
- l(ge(e.data), !0);
157
- for (const e of o.geometries ?? [])
158
- l(e, !1);
222
+ for (const s of t.tiles ?? [])
223
+ n(Et(s.data), !0);
224
+ for (const s of t.geometries ?? [])
225
+ n(s, !1);
159
226
  return {
160
227
  group: r,
161
- configureMaterial: (e) => {
162
- e.side = g.DoubleSide, e.transparent = !1, e.opacity = 1, "color" in e && e.color instanceof g.Color && e.color.setRGB(n, n, n), "roughness" in e && typeof e.roughness == "number" && (e.roughness = 1), "metalness" in e && typeof e.metalness == "number" && (e.metalness = 0);
228
+ configureMaterial: (s) => {
229
+ s.side = p.DoubleSide, s.transparent = !1, s.opacity = 1, "color" in s && s.color instanceof p.Color && s.color.setRGB(e, e, e), "roughness" in s && typeof s.roughness == "number" && (s.roughness = 1), "metalness" in s && typeof s.metalness == "number" && (s.metalness = 0);
163
230
  },
164
231
  dispose: () => {
165
- f.dispose();
166
- for (const e of d) e.dispose();
232
+ u.dispose();
233
+ for (const s of f) s.dispose();
167
234
  r.clear();
168
235
  }
169
236
  };
170
237
  }
171
238
  export {
172
- Ee as createRelightingProxy,
173
- Ce as createRelightingShadowFactorMaterial,
174
- ve as depthOfFieldPreset,
175
- we as lightingPreset,
176
- Me as revealPreset,
177
- ye as sdfEffects,
178
- ke as worldWarpPreset
239
+ Rt as MAX_RELIGHTING_SHADOW_LIGHTS,
240
+ It as createRelightingProxy,
241
+ _t as createRelightingShadowFactorMaterial,
242
+ Pt as depthOfFieldPreset,
243
+ Dt as lightingPreset,
244
+ Nt as renderRelightingFactorMap,
245
+ Ot as revealPreset,
246
+ Ft as sdfEffects,
247
+ Ut as worldWarpPreset
179
248
  };
180
249
  //# sourceMappingURL=effects.js.map