Fable 创建了新型 4D 高斯溅射格式
Fable created novel 4D splat format

原始链接: https://adamraudonis.github.io/splats4D/

**.splat4d** 格式是一种高性能、可流式传输的动态 4D 高斯溅射(Gaussian Splatting)容器,其压缩率比原始文件高出 16–58 倍。通过将静态背景与动态运动分离,并采用 H.265 风格的“闭合 GOP”数据块,它支持通过 HTTP Range 请求直接从标准对象存储(如 S3/GCS)进行即时跳转和低延迟播放。 主要技术特性包括: * **误差界限量化(Error-Bounded Quantization):** 保证点对点的确定性精度(例如位置误差在 ±2mm 以内),确保 Rust 和 JavaScript 解码器在重建时位一致。 * **高效流式传输:** 元数据头允许客户端仅获取必要数据,在约 150 毫秒内渲染关键帧。 * **优化:** 使用 Morton 排序、时间死区跟踪和 Zstd 压缩,以实现接近最优的熵压缩。 * **原生 Web 支持:** 由 WebGPU 渲染器驱动,支持在浏览器中以 60fps 流畅播放复杂的动态场景。 该格式专为易用性设计,无需服务器端逻辑或复杂的清单文件,仅需静态托管即可。它非常适合需要极高压缩率和快速随机访问流式传输的高保真交互式 4D 内容。

抱歉。
相关文章

原文

A streamable 4D gaussian splat format with tunable bounds.

16–58× smaller than raw  ·  14–20× smaller than gzip  ·  encodes at ~640 MB/s  ·  HTTP Range-native streaming & seek

Live preview, streamed and decoded in your browser: a 2-second dynamic scene as one 7.4 MB .splat4d file — 58× smaller than its 427 MB of raw .splat frames. Press Interact to take the camera: drag to orbit, ctrl-scroll to zoom. Needs WebGPU (Chrome 113+, Safari 26+, Firefox 141+ on Windows) — open the full demo for more scenes and live encoding controls.

How it works

Static / dynamic split

In a typical dynamic capture, most splats are background that never moves beyond the bound. They are stored once — the entire background of a 1.6 GB sequence costs a few MB. Classification is exact: a splat is static iff a single quantized value satisfies the bound against its min and max over the whole clip.

Deadband “hold” tracks

A dynamic splat’s stored value changes only when the true value would violate the bound against it. This kills quantization flicker, makes temporal deltas mostly zero, and the check itself enforces the guarantee before every emitted symbol.

H.265-style closed GOPs

Keyframe (absolute quantized values) every N frames, then P-frames of exact integer deltas. Every GOP chunk decodes independently → seeking never touches other chunks. Key streams are laid out before delta streams inside each chunk, so a scrub can fetch ~10% of a chunk and show the keyframe instantly.

Entropy stack

Morton-ordered splats, zigzag-coded integer deltas, byte-plane shuffle (Blosc-style), zstd per stream. Output lands at ≈100% of the order-0 entropy of its own symbol streams.

Inside the file

A .splat4d file has three parts. A small header carries the bounds, the quantization steps, and a chunk index with absolute byte ranges — everything a client needs to plan its fetches. The static section holds the per-splat masks and base values: fetch it once and the complete scene is on screen. The rest is one self-contained GOP chunk per ~1 s of video, with key streams laid out before delta streams.

"SP4D" + header JSON
STATIC section     → full first view
GOP chunk 0        [keys][deltas]
GOP chunk 1        …

Error bounds

Every attribute of every splat in every decoded frame is within a user-chosen bound of the source — not on average, not in PSNR: pointwise and deterministic.

attributebounddefault
position± millimeters, L∞ per axis±2 mm
color RGB± 8-bit levels per channel±4/255
opacity± 8-bit levels±4/255
rotation± quaternion component (units of 1/128, up to sign)exact (±0)
scale± relative %, per axis±2%

Mechanism: SZ/ZFP-style error-bounded quantization (step = 2×bound ⇒ error ≤ bound by construction). After quantization everything is integer math — temporal deltas can never drift, and the Rust and JavaScript decoders reconstruct bit-identical values.

Stream from object store

The format is designed for plain HTTP Range requests against S3 / GCS / R2 / any static host — no server logic, no manifest files, no video container. A client needs exactly:

  • bytes=0-262143 → magic + header JSON (all byte offsets are absolute)
  • one range for the STATIC section (a few MB) → complete first view on screen
  • one range per GOP chunk during playback / prefetch
  • on seek: the chunk-prefix range (TOC + keys) first → keyframe on screen in ~100–150 ms, then the rest of the chunk → exact frame

Object stores support this natively. For browser clients, set CORS to allow the Range header and expose Content-Range:

[{ "AllowedMethods": ["GET", "HEAD"],
   "AllowedOrigins": ["https://your-site"],
   "AllowedHeaders": ["Range"],
   "ExposeHeaders":  ["Content-Range", "Content-Length", "Accept-Ranges"] }]

Payloads are already zstd-compressed inside the container, so store objects with no Content-Encoding — range math stays byte-exact and nothing double-compresses.

Benchmarks

Eight sequences from three independent capture pipelines: Dynamic 3D Gaussians (CMU Panoptic dome — juggle, boxes, softball, tennis), Neu3D cooking scenes via SpacetimeGaussians/splaTV (flame = backyard BBQ, sear = kitchen chef), and Technicolor (birthday party, 659k splats) — all converted to per-frame antimatter15 .splat files (32 B/splat), 20 fps. splat4d encodes use default bounds (±2 mm / ±4 color / exact rot / ±2% scale); gzip is per-frame -9. For context, the best generic lossless baseline (zstd-19 --long over the whole series) reaches only 2.5×. Full methodology and more baselines: BENCHMARKS.md.

loading benchmarks.json…

Viewer

Raw WebGPU, a line-by-line port of the antimatter15/splat renderer, pixel-verified against it.

metriclocalthrottled 50 Mbps
full first view (header + static section)141–157 ms791 ms
scrub into unbuffered region → keyframe visible145 ms
playback60 fps @ 336k splats · worker decode 2.5–27 ms/frame · sort 1–25 ms

Using it

A time series of antimatter15 .splat frames → one small, seekable file:

# Python (pip install splats4d)
splat4d encode -i frames_dir -o out.splat4d
联系我们 contact @ memedata.com