UNPKG

@playcanvas/splat-transform

Version:

Library and CLI tool for 3D Gaussian splat format conversion and transformation

146 lines (145 loc) 6.7 kB
/** * Centralised render-time tunables. Constants that today live as magic * numbers in the project/rasterize WGSL shaders, in `gaussian-aabb.ts`'s * extent computation, and in the orchestrator's far-plane logic. * * Two goals: * * 1. Single source of truth — one place to discover every knob, so the * "reference 3DGS standard" values are documented together rather * than scattered across files. * * 2. A natural switching point for a future "reference" vs "fast" * profile — for now everything is the reference-3DGS value. * * Most of these match the values used by the original INRIA 3DGS CUDA * rasterizer. Touching any of them is an "exceed reference" decision and * needs to be reflected in regenerated golden fixtures. */ /** * Half-pixel² covariance dilation added to the 2D projected covariance's * diagonal before inversion. Reduces aliasing at the cost of inflating * every splat's screen footprint by ≤1 pixel. Matches the INRIA reference. */ export declare const AA_DILATION_COV = 0.3; /** * Maximum tan(half-FOV) factor that the EWA Jacobian's `(cx/cz, cy/cz)` * is clamped to before forming the projection. Splats outside this cone * use a distorted Jacobian. Matches the INRIA reference (`1.3 × half-FOV`). */ export declare const JACOBIAN_LIMIT_FACTOR = 1.3; /** * Per-splat alpha cap. Prevents perfectly opaque splats so the * transmittance chain can't collapse to exactly zero in one step. INRIA * reference. */ export declare const OPACITY_CAP = 0.99; /** * Per-splat alpha cutoff. Contributions below this are dropped — saves * work for splats whose evaluated 2D Gaussian falls below quantization * threshold. INRIA reference. */ export declare const MIN_ALPHA: number; /** * Per-pixel transmittance early-out. Once `T` falls below this the pixel * stops accumulating; remaining ~0.01% of mass is discarded. INRIA * reference. */ export declare const MIN_TRANSMITTANCE = 0.0001; /** * Floor on `½·trace² − det` before sqrt when deriving the projected * covariance's larger eigenvalue. Bounds the radius from below by * `ceil(3·sqrt(½·trace + sqrt(floor)))` ≈ 1 pixel. INRIA reference. */ export declare const DISCRIMINANT_FLOOR = 0.1; /** * Number of standard deviations at which the rendered Gaussian's tail * is truncated. Used for both: * - the AABB half-extents in `computeGaussianExtents` (BVH input) * - the screen-space radius in the project shader (rasterize bbox) * * Keeping them in sync ensures a splat included by the BVH cull is * actually rasterized; lowering this here without also lowering it in * the project shader's `radius = ceil(SIGMA_CUTOFF · sqrt(λmax))` would * cause silently-clipped tails. */ export declare const SIGMA_CUTOFF = 3; /** * Value of the unit gaussian at the truncation radius. Subtracted from * `exp(power)` in the rasterizer so each splat's alpha reaches exactly * 0 at `SIGMA_CUTOFF · σ` instead of clipping at ≈ 1.1% (which would * leave a faint ring at the splat boundary). Matches the PlayCanvas * engine's edge compensation. */ export declare const GAUSSIAN_FLOOR: number; /** * Floor on the far-plane distance, expressed as a multiple of the near * plane. If every scene-AABB corner sits behind the camera the * computed far would otherwise be ≤ near; this prevents a degenerate * frustum. Magic number; not from any reference. */ export declare const FAR_PLANE_NEAR_FACTOR = 100; /** * Tile size in pixels for the rasterize workgroup. Must match the * WGSL shader's hard-coded `workgroup_size(16, 16, 1)`. Changing here * also requires updating the shader templates. */ export declare const TILE_SIZE = 16; /** * Equirect projection pole-exclusion factor. The equirect Jacobian's * latitude derivative diverges as the splat approaches the zenith / * nadir (rxz → 0). We clamp `rxz` from below at `POLE_EPS · r` so the * Jacobian (and hence the projected covariance, screen-space radius, * and per-tile coverage) stays bounded for splats arbitrarily close to * a pole. Splats *exactly* on the pole get a finite (but narrow) screen * footprint at a longitude determined by tiny numerical noise — in * practice this band is rarely visible because polar splats tend to be * far from the camera. Lowering the floor sharpens detail near the * poles at the cost of more aggressive footprint stretching for nearby * splats; 0.005 (~0.29°) is a reasonable balance. */ export declare const POLE_EPS = 0.005; /** * Total GPU memory budget for ALL pair-sized buffers combined: the * tile-key and splat-value buffers the rasterizer owns (2× pairsCap × 4 B) * plus the four internal ping-pong buffers `ComputeRadixSort` allocates * (`_keys0`, `_keys1`, `_values0`, `_values1` — another 4× pairsCap × 4 B). * That's 6 × pairsCap × 4 B = `PAIR_BUFFER_TOTAL_BYTES_PER_ELEMENT × pairsCap`. * * `chunkCap` is sized to keep this total under budget. The radix-sort * scratch is the dominant share; budgeting only the local buffers (as * earlier revisions did) under-counts actual GPU memory by ~3×. */ export declare const PAIR_BUFFER_BUDGET_BYTES: number; /** * Total bytes per pair *element* across all six pair-sized buffers * (4 B × 6 buffers). Used by the orchestrator's chunkCap calculation * so the math reflects actual GPU memory consumed by the sort * pipeline. */ export declare const PAIR_BUFFER_TOTAL_BYTES_PER_ELEMENT: number; /** * Screen-radius fade thresholds, expressed as fractions of image * height. Defends against outlier splats with large world-space scale * or near-camera placement that would otherwise project to a screen- * spanning footprint. * * A hard clamp produces a visible "pop" as the camera approaches a * splat that grows past the cap (the splat suddenly stops getting any * bigger). Instead we *linearly fade out* the splat's alpha between * `RADIUS_FADE_START_FRAC × imageHeight` (alpha × 1) and * `RADIUS_FADE_END_FRAC × imageHeight` (alpha × 0). Beyond the END * threshold the splat is discarded entirely. * * Image-height-relative so the SAME world-space splats fade at every * render resolution — a splat that doesn't fade at 1080p won't get * dropped at 8K just because its pixel radius is 4× bigger. The values * are calibrated so that the original 1080p thresholds (1024 px / * 2048 px) reproduce, while 8K renders fade only the splats that * would also fade at 1080p. * * Inspired by PlayCanvas engine's `min(1024.0, viewport)` axis cap * (see `gsplatCorner.js`), but with the cap softened into a fade. */ export declare const RADIUS_FADE_START_FRAC: number; export declare const RADIUS_FADE_END_FRAC: number;