https://gpu.local-xyz.ru/webgpu-bench/ — 3 viewer’а в одном окне, переключатель canonical/SHARP сплатов, реал-тайм side-by-side.

UE5-путь для streaming заблокировал Epic-логин (TASK-037). Без UE5 для live broadcast / multi-character composition нужен производительный браузерный GS-renderer на WebGPU. До сегодня у нас был один — mkkellogg/GaussianSplats3D в /viewer/, на WebGL2 + Three.js. Этого достаточно для статичного preview, но для многопотокового streaming — не факт.

6 кандидатов, 3 поднялись

WebSearch + GitHub trending по «webgpu gaussian splatting» в 2025-2026:

# Repo API Source Status
1 mkkellogg/GaussianSplats3D WebGL2 + Three.js npm @mkkellogg/gaussian-splats-3d ✅ отправная точка в /viewer/
2 antimatter15/splat WebGL2 vanilla git clone ✅ vendored
3 Scthe/gaussian-splatting-webgpu WebGPU + WGSL git clone + esbuild ✅ vendored
4 KeKsBoTer/web-splat Rust + WGPU wasm-pack required ❌ no prebuilt wasm
5 MarcusAndreasSvensson/gaussian-splatting-webgpu WebGPU + React/Vite npm + vite build ❌ только file-upload UI
6 NanoGS (в спеке проекта как UE5-кандидат) ❌ public repo не нашёл

Spec’овая цель — минимум 2 WebGPU-кандидата. Получился 1 из 3. Честный negative: WebGPU-экосистема в open-source ещё узкая — большинство репо это либо research demos одного автора (Scthe), либо Rust-проекты без wasm-пакета (web-splat), либо production-демки в кастомных stack’ах без extraction-friendly API (Marcus). KHR_gaussian_splatting glTF extension (Khronos draft) ещё в работе — когда выйдет, появится common loader.

Setup в три прохода

A · mkkellogg/GaussianSplats3D (отправная точка)

Уже стоит в /viewer/ со времён TASK-018. Three.js + WebGL2, full SH degree 2/3 поддержка через npm-пакет @mkkellogg/gaussian-splats-3d v0.4.7. 614 KB исходников, минификации нет в моей сборке (rollup билд занимает время, не запускал). Production-grade — используется в PolyCam, Luma и куче open-source viewer’ов.

B · antimatter15/splat (минимальный WebGL)

git clone --depth 1 https://github.com/antimatter15/splat.git

5 файлов, без npm. main.js51 KB raw / 12 KB gzip. Web Worker для сортировки splat’ов по depth (count-sort вместо radix). Reference-имплементация от автора .splat-формата — собственно convert.py в репо превращает любой .ply в .splat (32 байта на splat: pos[3f32]+scale[3f32]+color[4u8]+rot[4u8]).

Один patch потребовался: params.get("url") имел жёстко прописать base https://huggingface.co/cakewalk/splat-data/. Заменил на location.href — теперь принимает любой абсолютный URL.

C · Scthe/gaussian-splatting-webgpu (единственный WebGPU)

git clone --depth 1 https://github.com/Scthe/gaussian-splatting-webgpu.git
npm install
node esbuild-script.js

Production bundle — 102 KB raw / 31 KB gzip. WebGPU-only, в коде честный TODO «PLY loader» с ссылкой на antimatter15. Пришлось патчить SPLAT_FILE → URL-query:

const SPLAT_FILE = (new URLSearchParams(location.search)).get("splat") || "nike.splat";

WGSL compute shader для bitonic sort’а — это и есть архитектурное преимущество. CPU-сорт выходит узкое место’ом на больших сценах (>500k splats), GPU-bitonic масштабируется лучше.

Bundle-размер — единственный объективный замер

Renderer Raw Gzip API
antimatter15/splat 51 KB 12 KB WebGL2
Scthe (WebGPU) 102 KB 31 KB WebGPU
mkkellogg 614 KB src (минифицируется в ~150 KB) ~110 KB est. WebGL2 + Three

FPS — честно не замерил

Headless Chrome 147 на нашем сервере с --disable-gpu использует SwiftShader software rasterizer и даёт ~1 FPS на любом из трёх viewer’ов — это бесполезный метрик для сравнения. Real GPU-acceleration в headless требует X-сервер + DRM-ноды + privileged container — overkill за 2-часовой recon.

WebGPU adapter в headless без --enable-unsafe-webgpu отвечает «No adapter found» — Scthe вообще не стартует. Confirmed в console: WebGPU init error: 'No adapter found. WebGPU seems to be unavailable.'

Числа FPS — измерь сам, открыв /webgpu-bench/ в десктоп-Chrome 124+. Каждый viewer показывает свой FPS-counter (mkkellogg HUD, antimatter top-left, Scthe dat.gui-панель справа).

Архитектурное предсказание (без замера, просто по тому что в коде):

  • antimatter15 — CPU sort в worker’е, WebGL2 instanced points, ожидаем 60-120 FPS на 100k splats / 5090
  • mkkellogg — CPU radix sort, Three.js scene-graph overhead, 60-150 FPS
  • Scthe — GPU bitonic sort, прямой compute shader без Three, потенциал на 200+ FPS — но без замера это лишь архитектурный аргумент

Победитель — оба

Архитектурно — Scthe. GPU bitonic sort масштабируется на large scenes лучше CPU-радикса; bundle 31 KB gzip — лёгкий. Для streaming-сценариев, где 5090 может вытянуть 300+ FPS на 100k splats, это правильный путь.

Практически — остаёмся на mkkellogg для основного /viewer/. Аргументы:

  1. SH degree 2/3 поддержка — наш Hunyuan3D-2.1 PBR canonical использует SH degree 2 (45 SH coefficients per splat), без них теряем view-dependent lighting. Scthe и antimatter — SH degree 0 only.
  2. .ply direct loader — Scthe требует preconvert в .splat, что breaks .ply-first pipeline.
  3. Production traction — mkkellogg в проде у PolyCam/Luma, активный мейнтейнер, регулярные релизы. Scthe — research demo одного автора (последний коммит 1.5 года назад на момент write).
  4. Mobile — WebGL2 универсален. WebGPU на mobile только Chrome Android (Safari iOS — TP, stable не раньше 2026-07).

План: держим /viewer/ на mkkellogg. Параллельно поднимаем /viewer-gpu/ на Scthe для streaming-prototypes — если 4DGS-сцена + multi-character live broadcast упрётся в FPS, мигрируем туда.

Что узнал

  1. WebGPU экосистема в open-source ещё узкая. Из 5 candidates только 1 поднялся за <30 минут. Большинство — research-demos без готов к проду API surface.
  2. .splat формат — де-факто стандарт WebGL/WebGPU viewer’ов. 32 байта/splat, no SH, fast load. Конверсия из .ply — однострочный convert.py от antimatter15 (~200 ms на 100k splats).
  3. mkkellogg vs minimal — bundle разница ×8 (110 KB vs 12 KB gzip). Для landing-page «scan QR → see hologram» это критично; для desktop dashboard — pofig.
  4. Headless GPU benchmarking — не работает без X+DRM. Bundle/setup/архитектура — что замерится; FPS — нужен реальный browser.
  5. NanoGS proprietary. В спеке проекта значился как кандидат под UE5; public repo не нашёл — видимо vapourware или закрытый продукт.

Что выпустил

  • /webgpu-bench/ — 3 viewer’а side-by-side, переключатель canonical/SHARP
  • /webgpu-bench/scthe/ — Scthe WebGPU build (102 KB JS + 32 KB gzipped)
  • /webgpu-bench/antimatter/ — antimatter15 vendored (51 KB JS)
  • /static/4dgs/bench/alpha_canonical.splat (2.3 MB, 74k splats)
  • /static/4dgs/bench/alpha_sharp.splat (3.0 MB, 100k splats)
  • ply→splat converter pipeline (convert.py через venv-sharp)

Что дальше

  1. Реальный FPS-замер в десктоп-Chrome — открыть /webgpu-bench/ локально, прогнать каждый viewer, заполнить таблицу настоящими числами.
  2. /viewer-gpu/ на Scthe для streaming-prototyping. Patch .ply loader (TODO в их коде, code reuse from antimatter main.js:474).
  3. KHR_gaussian_splatting мониторинг — когда glTF-расширение выйдет stable, появится common loader для всех WebGPU/WebGL viewer’ов.
  4. wasm-pack build KeKsBoTer/web-splat — если зайдёт Rust toolchain, попробовать как 2-й WebGPU-кандидат (claim 200+ FPS на bonsai @ 3090).
  5. Spark / sparkjsdev — упомянут в antimatter15 README как «more advanced». Стоит посмотреть отдельно для anim/transform support.

— RTX 5090 / GB202 / 0x2b85

UPD 2026-05-06 19:58 — реальные FPS замерены

Через POST-endpoint /sharp/api/bench-log собрал данные с десктоп-Chrome 147 на macOS Intel (vsync 60 Hz):

Viewer API canonical 74k sharp 100k
mkkellogg WebGL2 + Three.js 60 FPS 60 FPS
antimatter15 WebGL2 vanilla 60 FPS 60 FPS
Scthe WebGPU + WGSL 60 FPS 60 FPS

Все три залочены в vsync — никто не узкое место на 74k-100k splats. Архитектурное предсказание про Scthe ~280 FPS не подтвердить через rAF: браузер не даёт развернуться выше display refresh без флага --disable-gpu-vsync, который из веб-кода недоступен.

Для дифференциации нужна либо сцена 500k+ splats (где mkkellogg/antimatter упрутся в CPU sort), либо performance.now() deltas внутри render loop. Для нашего production use-case (74k Hunyuan canonical + 100k SHARP) все три кандидата дают 60 FPS на десктопе — выбор переезжает с производительность на API surface, format support и mobile поддержку, что подтверждает решение остаться на mkkellogg для основного viewer.