Equirectangular 360 panorama → 3D Gaussian Splat, end-to-end on Apple Silicon (MPS).
A thin pipeline around Apple's ml-sharp that:
- Crops a horizontal ring of perspective faces from an equirectangular image,
- Runs SHARP per-face — each in a fresh subprocess, so MPS GPU memory is
returned to the OS between faces (the trick that sidesteps the
IOGPUDeviceShmemallocation failure you hit on naive multi-face setups), - Rotates each face's splats into a shared world frame (yaw on Y),
- Optionally applies a Voronoi yaw clip to drop face-to-face overlap,
- Concatenates everything into a single
.ply.
No DA360 alignment, no SH rotation, no fancy refinement — just enough to get a viewable 360 splat from a single panorama with a stock M-series Mac.
Existing 360 → splat tools (e.g. SPAG4d) assume CUDA. On Apple Silicon they
either fail to install or hit MPS shared-memory exhaustion the moment SHARP
loads while DA360 is still resident — even after empty_cache. ringsplat keeps
the per-face inference fully isolated as a child process, so the allocator
state is never carried across faces.
- macOS on Apple Silicon (M1/M2/M3/M4) with Metal — also works on Linux/CUDA.
- Python ≥ 3.11.
- Apple ml-sharp installed separately. The
sharpCLI must be invocable (e.g.~/ml-sharp/venv/bin/sharp).
# install ml-sharp (one-time)
git clone https://github.com/apple/ml-sharp.git
cd ml-sharp
python3.11 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
sharp --help # confirmgit clone https://github.com/DECK6/ringsplat.git
cd ringsplat
python3.11 -m venv .venv
source .venv/bin/activate
pip install -e .ringsplat \
--input panorama_2to1.png \
--output scene.ply \
--side-count 6 \
--face-size 512 \
--fov-deg 60 \
--device mps \
--scale-align --anchor-percentile 99 \
--radius-cutoff 99.5 \
--clip-yaw \
--legacy-pointcloud \
--sharp-bin /path/to/ml-sharp/venv/bin/sharpThe flags above are the recommended starting point. side-count=6 × fov=60°
exactly tiles 360° with zero overlap — SHARP's default 30 mm focal
assumption is ~63°, so 60° fits cleanly inside each face and adjacent faces
meet without ghosting. The alignment trio (scale-align + anchor-percentile 99
radius-cutoff 99.5) keeps the merged splat round when seen from above.
| Flag | Default | Notes |
|---|---|---|
--side-count |
8 | 4 / 6 / 8 horizontal faces — 6 recommended |
--face-size |
512 | per-face square resolution |
--fov-deg |
360/side_count * 1.2 |
use 60 with side-count 6 for zero-overlap tiling under SHARP's 30 mm focal |
--device |
mps |
mps / cuda / cpu |
--scale-align |
off | rescale faces to share an anchor radius |
--anchor-percentile |
50 | 50 = median; 99 = outer envelope |
--radius-cutoff |
off | drop splats past this radius percentile (e.g. 99.5) |
--clip-yaw |
off | hard Voronoi yaw clip on overlap |
--legacy-pointcloud |
off | add r/g/b/a + nx/ny/nz so non-GS viewers (TouchDesigner Point File In, MeshLab) show color |
--workdir |
./work_sharp360 |
face crops + per-face plys |
--keep-work |
off | don't delete --workdir after run |
--sharp-bin can also come from RINGSPLAT_SHARP_BIN env var, or any sharp
on PATH.
A single binary little-endian .ply with the SHARP vertex properties:
x, y, z, f_dc_0, f_dc_1, f_dc_2, opacity, scale_0..2, rot_0..3
Drop it into any 3DGS viewer (e.g. SuperSplat, gsplat, TouchDesigner with a GLSL renderer).
| side_count | face_size | total time |
|---|---|---|
| 4 | 512 | ~50 s |
| 6 | 512 | ~95 s (recommended) |
| 8 | 512 | ~120 s |
About 80% of the wall time is SHARP itself; the rest is subprocess startup + crop/merge.
- Horizontal ring only — top/bottom (zenith/nadir) is not covered. Add
pitch ±60°faces in a future version if you need full sphere coverage. - No inter-face depth alignment — each face is metric per SHARP's own
estimate. Visible parallax mismatch can appear on close objects in overlap
regions; raise
--side-countor enable--clip-yawto mitigate. - DC-only color (SHARP outputs
f_dc_*, nof_rest_*), so view-dependent shading is flat — yaw rotation is therefore lossless. - Quaternion rotation is composed correctly for the rotation channel, but SH rotation is not applied (irrelevant while ml-sharp ships SH degree 0).
MIT (this repo).
ml-sharp is governed by Apple's own
license — installing and running it is your responsibility.