Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...
    GSPLAT_FRAGMENT_SHADER: "\n precision highp float;\n \n // Refraction split (glass-partition.ts): 0 off, 1 keep behind-or-none, 2 keep front.\n uniform int uGlassPartition;\n // Refracting-glass front-face window depth; the cleared 1.0 means \"no glass here\".\n uniform sampler2D uGlassDepth;\n\n\n // All varyings use flat - no interpolation needed (constant per instance)\n // OPTIMIZATION: flat qualifier skips GPU interpolation hardware\n flat in mediump vec3 vColor;\n flat in mediump float vAmplitude2D;\n flat in mediump float vAlpha;\n // These need highp for screen-space calculations\n // OPTIMIZATION: vL2D stores [1/L00, L10, 1/L11] for MUL instead of DIV\n flat in highp vec3 vL2D; // 2D Cholesky packed as [invL00, L10, invL11]\n flat in highp vec2 vCenterScreen;\n\n uniform mediump float uOpacity;\n // Absorption coefficient κ — only read under LUXAR_VOLUMETRIC\n // (τ = κ·opacity·intensity); highp: τ enters an exp().\n uniform highp float uAbsorption;\n // 1.0 when the dataset's colors carry a per-splat alpha (RGBA), else\n // 0.0. Only the volumetric branch needs the gate: it maps alpha into\n // optical depth (w = −ln(1−a)), and the RGB default alpha of 1.0\n // would otherwise map to w ≈ 6.24 instead of the identity.\n uniform lowp float uHasElementAlpha;\n uniform mediump float uInvGamma; // Pre-computed 1/gamma for performance\n uniform mediump float uIntensity; // Per-node linear color multiplier (gain)\n uniform mediump float uOffset; // Per-node additive brightness shift (black level)\n uniform highp float uShiftC; // Shifted Gaussian: exp(-0.5 * T²)\n uniform highp float uInvOneMinusC; // Shifted Gaussian: 1/(1-C)\n uniform highp float uTruncateSq; // Truncation radius squared (T²)\n\n // GLSL ES 3.0 requires explicit fragment output declaration\n out vec4 fragColor;\n\n void main() {\n \n if (uGlassPartition != 0) {\n float glassDepth = texelFetch(uGlassDepth, ivec2(gl_FragCoord.xy), 0).r;\n bool inFrontOfGlass = glassDepth < 1.0 && gl_FragCoord.z < glassDepth;\n if (uGlassPartition == 1 && inFrontOfGlass) discard;\n if (uGlassPartition == 2 && !inFrontOfGlass) discard;\n }\n\n // Pixel offset from splat center\n vec2 d = gl_FragCoord.xy - vCenterScreen;\n\n // Forward substitution: solve L · y = d\n // OPTIMIZATION: vL2D contains [invL00, L10, invL11] - use MUL instead of DIV\n float y0 = d.x * vL2D.x; // d.x * invL00\n float y1 = (d.y - vL2D.y * y0) * vL2D.z; // (d.y - L10 * y0) * invL11\n\n // Squared Mahalanobis distance\n float mahalSq = y0 * y0 + y1 * y1;\n\n // EARLY DISCARD: Skip pixels beyond truncation radius\n if (mahalSq > uTruncateSq) discard;\n\n // Shifted Gaussian: a·scale·max(0, exp(-½·r²) - C)\n // Ensures C⁰ continuity at truncation boundary (no discontinuity)\n float intensity = vAmplitude2D * uInvOneMinusC * max(exp(-0.5 * mahalSq) - uShiftC, 0.0);\n\n // Per-splat opacity (color alpha channel; 1.0 for RGB datasets).\n // Every mode scales its contribution linearly by a; volumetric\n // instead maps a into optical DENSITY, w = −ln(1 − a), so a\n // splat's peak rendered alpha reproduces a exactly (3DGS-faithful;\n // clamp = ALPHA_CLAMP from ../_shared/volumetric, mirrors Python's 1 − 1/512).\n // Dilute limit: w ≈ a, so the modes agree as a → 0; at large a\n // volumetric is intentionally denser (optical-depth semantics —\n // see spec §5.4).\n #ifdef LUXAR_VOLUMETRIC\n intensity *= mix(1.0, -log(1.0 - min(vAlpha, 0.998046875)), uHasElementAlpha);\n #else\n intensity *= vAlpha;\n #endif\n\n // Early discard for negligible contribution (raised threshold for\n // performance). Alpha is already folded in, so a ~zero-alpha splat\n // discards here in every mode (it neither emits nor absorbs).\n // GAIN-AWARE: the emitted brightness is intensity * uIntensity *\n // color, so the visibility test must include the gain — a flat\n // 1e-4 gate discarded dim splats that a high gain (dim\n // fluorescence channels) would have lifted well above the ~1/255\n // floor (hard clipped rims + vanishing splats at gain >~ 40).\n // max(uIntensity, 1.0) keeps gain <= 1 EXACTLY at the historical\n // threshold (no overdraw change for default renders).\n if (intensity * max(uIntensity, 1.0) < 1e-4) discard;\n\n // Per-node GOG (Gain-Offset-Gamma) color adjustment. uIntensity (gain)\n // and uOffset apply in BOTH modes so the layer intensity/offset controls\n // work for a colormapped gsplat too. Colormap (LUT) mode: gamma + the\n // display-range window already shaped the scalar VALUE (amplitude) before\n // the LUT lookup, so only gain/offset apply post-LUT (no extra gamma).\n // Direct-color mode: full GOG on the raw color.\n // When the wrapper knows intensity==1 && offset==0 (the default), the\n // mul/add/clamp chain is identity for the common non-negative vColor\n // range; the wrapper stamps LUXAR_NO_GOG to skip it (mirrors the line\n // shader). The gain-aware discard above KEEPS reading uIntensity —\n // under NO_GOG uIntensity == 1 so max(uIntensity, 1.0) == 1.0 anyway.\n #ifdef LUXAR_NO_GOG\n vec3 adjusted = vColor;\n #else\n vec3 adjusted = max(vColor * uIntensity + uOffset, vec3(0.0));\n #endif\n\n #ifdef LUXAR_VOLUMETRIC\n // Volumetric optical depth: tau = kappa*opacity*intensity, where\n // intensity is the PRE-GOG density scalar (sum-projected ray\n // mass incl. rayIntegrationBoost + nearFade — a near-fading splat\n // loses emission and absorption together) and opacity scales\n // density (VOLUMETRIC_BLENDING_SPEC.md §3.1). GOG gain/offset/\n // gamma shape emission COLOR only, never tau.\n float tau = uAbsorption * uOpacity * intensity;\n // τ is color-independent — a black splat still absorbs (a\n // pure-ink occluder via gain→0 must keep its optical depth), so\n // the zero-color discard only fires when τ is negligible too.\n // (The earlier intensity<1e-4 discard bounds any lost τ at\n // κ·opacity·1e-4 per fragment — invisible at slider range.)\n if (max(adjusted.r, max(adjusted.g, adjusted.b)) < 1e-4 && tau < 1e-4) discard;\n #else\n // Early discard for zero-contribution fragments after offset\n if (max(adjusted.r, max(adjusted.g, adjusted.b)) < 1e-4) discard;\n #endif\n\n // LUXAR_GAMMA_ONE (gamma == 1.0) skips the per-fragment pow() —\n // pow(x, 1) == x — same fast path the colormap branch already takes.\n #if defined(USE_COLORMAP) || defined(LUXAR_GAMMA_ONE)\n vec3 gammaColor = adjusted;\n #else\n vec3 gammaColor = pow(adjusted, vec3(uInvGamma));\n #endif\n\n // HDR color output for linear additive blending\n // With OneFactor blending (additive/luminous/max modes), alpha is ignored,\n // so apply opacity to RGB directly. This gives correct LINEAR sum projection\n // without the intensity-squaring bug that AdditiveBlending (SrcAlpha) would cause.\n vec3 finalColor = gammaColor * intensity * uOpacity;\n\n #ifdef LUXAR_NORMAL_PREMULT\n // 'normal' mode: premultiplied alpha-over. RGB already carries the\n // full (unclamped, HDR) contribution; alpha carries a CLAMPED\n // coverage term so the One / OneMinusSrcAlpha framebuffer state\n // (see blending-state.ts getGSplatNormalBlendingState) attenuates\n // the destination without ever over-subtracting. Dim splats\n // (intensity·opacity << 1) occlude proportionally little — an\n // emitter-with-occlusion model, deliberate for HDR scientific data.\n float coverage = clamp(intensity * uOpacity, 0.0, 1.0);\n fragColor = vec4(finalColor, coverage);\n #elif defined(LUXAR_VOLUMETRIC)\n // 'volumetric' mode: emission–absorption (Max 1995). RGB carries\n // the self-screened emission (the splat's front absorbs its own\n // back: S(τ) = (1−e^(−τ))/τ, the exact closed form for emission ∝\n // density — what makes split-splat compositing exact); alpha is\n // the physical absorption 1 − e^(−τ) for the One /\n // OneMinusSrcAlpha state. κ = 0 ⇒ α = 0, S = 1 — bit-identical\n // framebuffer RGB arithmetic to additive (dst-alpha differs;\n // invisible on the alpha:false canvas). Series for τ < 1e-3 keeps\n // S well-conditioned through τ → 0 (rel. err < 1e-10 at cutoff).\n float alpha = 1.0 - exp(-tau);\n // Divisor guarded: GPU ternaries/selects evaluate both lanes, and\n // the TSL twin's .select does too — max() keeps the unselected\n // lane NaN-free at tau = 0 (identical in the selected regime).\n float screen = (tau < 0.001) ? 1.0 - 0.5 * tau + tau * tau / 6.0\n : alpha / max(tau, 1e-20);\n fragColor = vec4(finalColor * screen, alpha);\n #else\n // All other modes keep the alpha=1.0 contract: additive/luminous\n // rely on SrcAlpha being the identity factor (what makes the\n // shared AdditiveBlending state equal the linear One+One sum),\n // and max compares premultiplied RGB contributions directly.\n fragColor = vec4(finalColor, 1.0);\n #endif\n }\n " = ...

    Fragment shader for standard Gaussian splat rendering.

    Uses the 2D Cholesky factor passed from vertex shader to compute Mahalanobis distance, then applies shifted Gaussian falloff. The picking system uses a different fragment shader (see picking/gsplat-picking-material.ts).