Measured locally · Apple M5 Pro

3DGS Renderer Bench ThreeJS: Gaussian Splat Lite · Spark · Radix PlayCanvas: PlayCanvas · SuperSplat Viewer Other: Aholo Viewer

Rendering, sorting and memory on matched PLY and SOG inputs, cameras and full models at Retina resolution, with settings aligned as closely as possible. Sorted groups use radial ordering, except Aholo Viewer (view depth only); stochastic groups keep native behavior without temporal accumulation.

3024 × 1964 1512 × 982 CSS px · DPR 2 · No MSAA
M5 Pro · 16 GPU cores 48 GiB unified memory · macOS 26.7

Current scene

ms · Lower is better

Green marks the best value in each group; sorted and raw stochastic are ranked separately, ties shared.

Depth-sorted rendering

Raw stochastic rendering

Native raw sampling, no spatial resolve or temporal accumulation. Gaussian Splat Lite keeps its 16-bit front-to-back sort; PlayCanvas skips sorting. Sampling patterns differ.

Selected metric per run

Depth-sorted rendering

Raw stochastic rendering

One GPU frame in flight: each frame is submitted only after the previous one has finished on the GPU (WebGL2 fence / WebGPU onSubmittedWorkDone). Without this wait the CPU runs ahead, intervals look short and the queued work later shows up as stalls. Each sample is the interval between submissions; FPS = frames / sampled time. Values are medians across runs.

Where sorting runs

Worker sorts run asynchronously; GPU sorts run in the GPU command stream. Async completion covers preparation, transfer, sorting and hand-back. Each run alternates two camera directions: 4 warm-up iterations, 16 samples.

The radix diagnostic measures the first-to-last pass span. Gaussian Splat Lite splits projection and radix only here; Engine, SuperSplat Viewer and Radix GPU use native pass boundaries. Radix CPU waits for one full sort per sample (GPU key readback + Worker sort). Pipelines and active counts differ, so these are not equal-input algorithm comparisons.

Sorting precision, explained

Sorted groups use radial ordering, except Aholo Viewer, which sorts by view depth. Engines encode distance or squared distance, so equal key widths do not mean equal quantization; async results may lag the camera.

Renderer Sort key Execution Precision and trade-off
Spark · WebGL2 32-bit float sort metric, all bits retained GPU key readback → Worker/WASM; 2 × 16-bit radix digits float32 depth key, no extra truncation. GPU readback and Worker transfers add async latency.
PlayCanvas · WebGL2 / WebGPU Log-spaced keys from float32 squared-distance bits. WebGL2: 16 bits; WebGPU: 16–20 bits, rounded to the radix width. WebGL2: JavaScript Worker counting sort. WebGPU: portable 4-bit radix on this Apple GPU. Keys are rescaled over the current distance range; precision depends on the near clip and active scene bounds.
Radix · WebGL2 / WebGPU Default 24-bit radial-distance key; lowest 7 float32 bits removed WebGL2: GPU key readback → JavaScript Worker, 11 + 13-bit radix digits. WebGPU: 3 × 8-bit radix digits. 16 fraction bits (Gaussian Splat Lite default: 15). Both encode camera distance. WebGL2 readback and Worker transfers add async latency.
SuperSplat Viewer · WebGPU Engine WebGPU log-spaced squared-distance keys WebGPU: Engine portable 4-bit radix on this Apple GPU. Same key mapping and precision as PlayCanvas WebGPU; native pass boundaries.
Gaussian Splat Lite · default Upper 24 bits of the float32 key; lowest 8 bits removed WebGL2: Worker/WASM, one counting pass over 23 effective bits (sign bit fixed). WebGPU: 3 × 8-bit radix digits. 15 fraction bits; camera distance on both backends. WebGL2 uses a 32 MiB count table.
Aholo Viewer · WebGL2 32-bit float view-depth key (high precision; the default is 16-bit half float) GPU key pass, fenced readback → Worker; 2 × 16-bit radix digits float32 view depth, no truncation; re-sorts after a 0.1 mm or ~0.16° camera change. Readback and Worker transfers add async latency.

PlayCanvas and SuperSplat Viewer map squared-distance bits from nearClip / 1024 to the scene bound. CPU sorting uses 16-bit keys; GPU sorting picks 16–20 bits by active count, rounded to the radix width (4-bit radix on this Apple GPU).

Nearly coincident splats may share a key, changing alpha blending; sorting is by Gaussian center, not per pixel. Sorted Gaussian Splat Lite uses its default 24-bit sort; Spark uses extended encoding throughout. Raw stochastic Gaussian Splat Lite uses 16-bit axial front-to-back ordering; PlayCanvas stochastic skips sorting.

Spark sort source · PlayCanvas depth keys · Gaussian Splat Lite Worker sort source · Gaussian Splat Lite GPU depth keys

Memory

Per post-GC snapshot: JS heap + ArrayBuffer/external storage + WASM capacity across the main thread and live Workers. Maximum over sorted cases per run, then the median of three runs. GPU allocation is separate; stochastic render targets are excluded. MiB = 2²⁰ bytes.

JS heap + ArrayBuffer + WASM · MiB

Explicit GPU allocation · MiB

An accounting sum (ArrayBuffer includes external-string storage; WASM is live Worker linear-memory capacity), not process RSS or deduplicated physical memory. Native ImageBitmap/codec storage is not included. Components are in harness/results.

GPU allocation counts buffer, texture and renderbuffer capacity, excluding query buffers, driver overhead, alignment and the swapchain. It is allocated capacity, not physical VRAM (Apple uses unified memory). Browser RSS is kept only as raw diagnostics.

Chrome DevTools Protocol · Runtime.getHeapUsage

Image comparison

Fixed matching cameras, 3024 × 1964 captures; click a render for the original. Gaussian Splat Lite WebGPU blends in sRGB to match WebGL. Native SH decoding and projection are unchanged. Raw stochastic captures use no spatial resolve or temporal accumulation.

MAE (RGB 0–255) and PSNR compare each backend with its own sorted capture. They measure image change, not quality or ranking.

Measurement scope

Full inputs, fixed resolution Elevator 2,796,503 · HotelFareza 12,202,010 · WillaGlobalPoland 14,469,103 splats. Full PLY and SOG / SH3, 3024 × 1964 physical pixels, vertical FOV 45°, near 0.1, far 3000, background #101418.

Spark source precision Extended source and accumulator encoding, SH3 retained. Base records are 32 bytes with float32 positions; “extended” does not make every field float32.

Gaussian Splat Lite source and accumulator Published source and accumulator encodings with full input SH. Effective settings and versions are recorded per run.

Three.js versions Gaussian Splat Lite and Spark use Three.js r187; Radix 0.0.1 uses r186 (its WebGPU path is incompatible with r187). Native sorting and caching stay on.

PlayCanvas Engine and rendering settings Engine and SuperSplat Viewer: large work buffers, minPixelSize 2, minContribution 0, alphaClipForward 1/255, antiAlias false, colorUpdateAngle 0, radial sorting. Spark and Radix: radius 2–512. Gaussian Splat Lite: minimum radius 1, no maximum. Native coverage and projection may still differ.

SuperSplat Viewer Created through the public API with the pinned Engine. Sorted rendering, large work buffers, shared camera and resolution; post effects and performance scaling off; model rotation reset to match the input.

Aholo Viewer WebGL2 only; the npm package has no public WebGPU renderer. Compressed source data (float32 position, half-float scale, color and opacity, 32-bit rotation, 10–11-bit SH clamped to ±1), fp32 GPU pack and 32-bit sort keys. preBlur 0.3, focalAdjustment 2, radius ≤ 512; area culling equals radius 2 for an opaque isotropic splat. Fixed 1/255 alpha floor; MSAA, TAA and tone mapping off.

Caching and motion Static tests keep drawing with native caches. Moving tests use the lab's real-time orbit (±45°, 8 s period). Async sorting stays active, so frames may use an earlier order.

Supported features Nine PLY and up to seven SOG backends run sorted rendering; PlayCanvas WebGPU and both Gaussian Splat Lite backends also run raw stochastic. Main and second views are tested static and moving: a closer side view, or the entrance side of WillaGlobalPoland.

Versions, data and sources

SuperSplat Viewer source · Spark renderer · ExtSplats · PlayCanvas source · Gaussian Splat Lite v1.6.2 (PLY) Gaussian Splat Lite v1.7.0 (SOG) · Layout / protocol reference