Pure, dependency-free opacity math for the two orthogonal LOD anti-popping
mechanisms, kept together (and THREE/camera-free) so both are unit-testable
over plain numbers, like lod-freshness.ts / lod-display-gate.ts.
The two mechanisms act on independent axes (a change BETWEEN two levels; the
stream WITHIN one level) and compose by multiplying their opacity factors:
Level dissolve (between levels) — smoothstep. When a
kind=lod group changes its displayed level, the registry dissolves the
outgoing level into the incoming one over config.lod.fadeMs instead of
a hard object.visible swap: the incoming at smoothstep(elapsed/fadeMs),
the outgoing at the complement (the state machine is lod-dissolve.ts).
Brightness across the switch is preserved by the levels' build-time mass
conservation (both integrate to the same DC).
Streaming brightness compensation (within a level) — energyCompensation. As a single level's additive ladder streams in over
time, its rendered energy climbs from e(k)·E toward E (additive/luminous
compositing sums energy; the ladder commits highest-energy splats first),
which reads as a brightening pop. Scaling opacity by 1/e(k) — opacity is a
linear multiplier on summed energy in additive/luminous, and on optical
depth τ in volumetric — holds the total near E throughout. This is a
self-energy heuristic rather than the exact conservation law used by
mechanism 1: e(k) is quadratic in amplitude while additive brightness is
linear, and the approximation becomes exact only when the leaf is complete.
Both mechanisms apply to the modes in BLENDABLE_MODES
(scene/lod-fade.ts) — additive / luminous / volumetric; see that set's doc
for the per-mode exactness argument and the volumetric caveat.
Pure, dependency-free opacity math for the two orthogonal LOD anti-popping mechanisms, kept together (and THREE/camera-free) so both are unit-testable over plain numbers, like
lod-freshness.ts/lod-display-gate.ts.The two mechanisms act on independent axes (a change BETWEEN two levels; the stream WITHIN one level) and compose by multiplying their opacity factors:
Level dissolve (between levels) — smoothstep. When a
kind=lodgroup changes its displayed level, the registry dissolves the outgoing level into the incoming one overconfig.lod.fadeMsinstead of a hardobject.visibleswap: the incoming atsmoothstep(elapsed/fadeMs), the outgoing at the complement (the state machine islod-dissolve.ts). Brightness across the switch is preserved by the levels' build-time mass conservation (both integrate to the same DC).Streaming brightness compensation (within a level) — energyCompensation. As a single level's additive ladder streams in over time, its rendered energy climbs from
e(k)·EtowardE(additive/luminous compositing sums energy; the ladder commits highest-energy splats first), which reads as a brightening pop. Scaling opacity by1/e(k)— opacity is a linear multiplier on summed energy in additive/luminous, and on optical depthτin volumetric — holds the total nearEthroughout. This is a self-energy heuristic rather than the exact conservation law used by mechanism 1:e(k)is quadratic in amplitude while additive brightness is linear, and the approximation becomes exact only when the leaf is complete.Both mechanisms apply to the modes in
BLENDABLE_MODES(scene/lod-fade.ts) — additive / luminous / volumetric; see that set's doc for the per-mode exactness argument and the volumetric caveat.