Luxar Viewer API Documentation - v2026.9.22
    Preparing search index...

    Manages HDR post-processing: scene → bloom → mega-shader → (FXAA) → backbuffer. Owns all transient GPU resources and a small amount of persisted state (DPR noise scaling baseline, quality preset, etc.).

    Index
    • Parameters

      • renderer: Renderer
      • capabilities: RendererCapabilities
      • scene: Scene
      • camera: LuxarCamera
      • size: { width: number; height: number }
      • OptionalonResize: (displaySize: { width: number; height: number }, camera: LuxarCamera) => void

        Optional callback invoked with the display size and the manager's current camera after every reallocation of the render-target pyramid (resize, SSAA toggle, MSAA toggle, DPR change). Passing the live camera keeps the hook correct across perspective/orthographic swaps. SceneManager wires this to updateMaterialsForCurrentCamera() so point/line/gsplat shaders pick up the new drawing-buffer size — otherwise their cached uResolution / maxPointSize uniforms go stale on AA toggles and the scene looks subtly wrong until the next window resize.

      Returns PostProcessingManager

    hdrTarget: WebGLRenderTarget
    ldrTarget: WebGLRenderTarget
    bloomChain: BloomChain | null = null
    megaPass: FullscreenPass
    fxaaPass: FxaaPass | null = null
    refractionSplit: DataRefractionSplit | null = null

    The scene-pass split for refract_data glass, both backends (null once disposed).

    fxaaEnabled: boolean = config.renderingControls.defaults.fxaaEnabled
    msaaEnabled: boolean = config.renderingControls.defaults.msaaEnabled
    msaaSamples: number = config.renderingControls.defaults.msaaSamples
    ssaaEnabled: boolean = config.renderingControls.defaults.ssaaEnabled
    ssaaMultiplier: number = config.renderingControls.defaults.ssaaMultiplier
    renderSize: { width: number; height: number }
    baseNoiseSettings: {
        readoutSigma: number;
        photonGain: number;
        fpnSigma: number;
    } = ...

    User-configured noise sigmas (before DPR scaling).

    currentDPRScale: number = 1.0
    bloomLevels: number = config.renderingControls.defaults.bloomLevels
    bloomIntensity: number = config.renderingControls.defaults.bloomStrength
    bloomRadius: number = config.renderingControls.defaults.bloomRadius
    bloomThreshold: number = config.renderingControls.defaults.bloomThreshold
    deferRebuildDepth: number = 0
    disposed: boolean = false
    _previousRenderTimestamp: number = 0
    renderer: Renderer
    capabilities: RendererCapabilities
    scene: Scene
    camera: LuxarCamera
    onResize?: (
        displaySize: { width: number; height: number },
        camera: LuxarCamera,
    ) => void

    Optional callback invoked with the display size and the manager's current camera after every reallocation of the render-target pyramid (resize, SSAA toggle, MSAA toggle, DPR change). Passing the live camera keeps the hook correct across perspective/orthographic swaps. SceneManager wires this to updateMaterialsForCurrentCamera() so point/line/gsplat shaders pick up the new drawing-buffer size — otherwise their cached uResolution / maxPointSize uniforms go stale on AA toggles and the scene looks subtly wrong until the next window resize.

    lastAllocation:
        | {
            displayW: number;
            displayH: number;
            logicalW: number;
            logicalH: number;
            physW: number;
            physH: number;
            msaaSamples: number;
        }
        | null = null

    Memo of the last applied allocation. Every window resize reaches reallocateForSize through TWO paths — the window resize listener (rAF-coalesced via ResizeOrchestrator) AND the canvas-parent ResizeObserver — and the MSAA/SSAA setters call it directly too. Without a guard, each redundant call disposed + recreated the full-screen half-float HDR target. The memo keys on everything that influences the allocation: display (CSS) size, effective logical size (folds in SSAA), physical size (folds in DPR), and the HDR target's MSAA sample count. null forces the next call to reallocate (initial state; reset by rebuildAfterContextRestore).

    wasAllocationLimited: boolean = false
    • Parameters

      • enabled: boolean
      • Optionalstrength: number
      • Optionalradius: number
      • Optionalthreshold: number

      Returns void

    • The display transform the mega-shader applies after the point where an EXR capture is read (hdr-effects-pre-tone bypasses all of it): exposure → offset → gamma → tone mapping → sRGB.

      Exported so the offline EXR path can bundle an ffmpeg recipe that reproduces what the viewer showed, instead of encoding scene-linear floats as if they were already display-referred.

      Returns { toneMapping: ToneMapping; exposure: number; offset: number; gamma: number }

    • Parameters

      • enabled: boolean
      • OptionalreadoutSigma: number
      • OptionalphotonGain: number
      • OptionalfpnSigma: number

      Returns void

    • Parameters

      • params: { readoutSigma?: number; photonGain?: number; fpnSigma?: number }

      Returns void

    • Parameters

      • enabled: boolean
      • OptionaldistortionX: number
      • OptionaldistortionY: number
      • Optionaldispersion: number
      • OptionalprincipalPointX: number
      • OptionalprincipalPointY: number
      • OptionalfocalLengthX: number
      • OptionalfocalLengthY: number
      • Optionalskew: number

      Returns void

    • Returns
          | {
              distortion: Vector2;
              principalPoint: Vector2;
              focalLength: Vector2;
              skew: number;
          }
          | null

    • The SSAA factor sitting between the size passed to resize and the requested render-target size. It EXCLUDES the pixel ratio. A framebuffer-limit clamp may reduce the achieved physical size, but limited allocations are always even in both axes. This keeps the factor sufficient for the recording session's encoder alignment after it forces the pixel ratio to 1.

      Returns number

    • The display (CSS-pixel) size the pipeline is configured for — i.e. exactly what resize was last given, and what it takes back.

      This is NOT renderer.getSize(). reallocateForSize hands the renderer the SSAA-MULTIPLIED size and stamps the display size on the canvas CSS instead, so under SSAA the renderer reports display × ssaaMultiplier. Feeding that back into resize multiplies by the SSAA factor a second time.

      Returns { width: number; height: number }

    • Parameters

      • opts: {
            applyFxaa: boolean;
            finalTarget: WebGLRenderTarget<Texture<unknown, TextureEventMap>> | null;
        }

      Returns void

    • Re-allocate every GPU resource whose size depends on the effective render size. Two unit systems are at play and they must NOT be confused:

      • Logical (CSS) pixels — what renderer.setSize(...) takes. THREE multiplies internally by pixelRatio to derive the canvas backbuffer.
      • Physical pixels — logical × pixelRatio. This is what getDrawingBufferSize() reports to materials, what the canvas backbuffer is, and what our render targets MUST match.

      A call whose full allocation key matches the last applied one is a complete no-op (see lastAllocation).

      Returns void

    • Read raw HDR float pixel data in one of three capture modes:

      • 'hdr-effects-pre-tone' (default): keep HDR-space effects (bloom) but disable tone mapping, EOG, vignette, detector noise, chromatic lens distortion. Linear HDR output — the canonical EXR-export mode. Implemented via the mega-shader's LUXAR_CAPTURE_RAW_HDR early-exit (skips EOG, tone mapping, vignette, sRGB encoding).
      • 'visible-ldr': full pipeline (EOG + tone mapping + every enabled effect), but skip the final sRGB encoding so the captured pixels are linear LDR floats.
      • 'raw-scene-hdr': bypass the mega-shader entirely — render the scene to hdrTarget and read it (no bloom, no effects).

      Returned rows are in canonical top-down order (row 0 = top of the source target) on both backends. Pass opts.flipY = true to receive bottom-up rows instead — only the EXR exporter does this, to preserve the orientation external tools expect.

      Parameters

      • mode: CaptureMode = 'hdr-effects-pre-tone'
      • opts: { flipY?: boolean } = {}

      Returns Promise<{ pixels: Float32Array; width: number; height: number }>