SphereSfM Dataset
One 360° panorama in, a trainable 3DGS dataset out — real SfM, not a learned guess
- initial_pano
- pano_frames_1
- pano_frames_2
- pano_frames_3
- pano_frames_4
- model_dir
- num_images
- num_points
This is the node the whole SplatKit pack is built around. Feed it a WAN-generated equirectangular fly-through video and it hands you a COLMAP dataset - images/ + sparse/0 plus a sparse point cloud - that trains straight away in any COLMAP-compatible 3D Gaussian Splatting trainer. No external venv, nothing to compile, no nvdiffrast. Just one catch that shapes everything else: you're building a trainable scene out of a single panorama.
That's the whole trick worth understanding first. One equirect image is a single viewpoint, and one viewpoint can't constrain a 3D scene. So SplatKit invents the missing viewpoints: MoGe estimates depth from your pano and turns it into a mesh, you draw a camera path through that mesh, WAN fills the holes the pano never saw, and this node runs classical structure-from-motion over the result. The SfM stage is what most people miss - this isn't a feed-forward model guessing poses (the VGGT/WorldMirror crowd), it's geometry actually solved from the imagery. Real poses and real matches, at the price of needing actual parallax in the clip.
How it works
The node shells out to colmap_sphere.exe, a CUDA build of SphereSfM - a spherical-camera fork of COLMAP 3.8 that adds a SPHERE camera model. It runs SIFT feature extraction, matching, and spherical bundle adjustment directly on the equirectangular frames, then sphere_cubic_reprojecer converts the SPHERE reconstruction into six pinhole (SIMPLE_PINHOLE, 90°) cube faces per frame. Ordinary pinhole cameras - so no trainer needs special equirect/unscented projection support. The binary auto-downloads into the pack's bin/ on first run (~37 MB, SHA-256 verified); nothing to install by hand.
Inputs that matter
Only output_name is required; everything else is optional. The ones a beginner actually touches:
output_name- the dataset folder underComfyUI/output/. Your COLMAP dataset lands in<output_name>/images/+sparse/0/.pano_frames_1- the WAN equirect video. "Optional" is a lie; SfM needs frames. Wire it.initial_pano- the pristine source panorama WAN was conditioned on. It lands at frame 0000, anchoring the solve on the clean original instead of WAN's drifted first frame.initial_pano_modereplace(default) overwrites WAN's frame 0;prependkeeps both.mode-colmap_now(default) runs SfM and writes the cube-face dataset.panorama_onlyskips SfM and saves the raw equirects, so you can upscale the coherent video first and run SfM on the upscaled panoramas - the best-quality path.init_min_tri_angle- the one you'll actually fiddle with when SfM refuses to start (see below).frame_stride/max_frames- thin long clips to keep SfM fast; keep enough overlap to still match.face_size- cube-face output resolution.0= auto (~equirect width / 4). Raise it for sharper images, more disk.
The rest (max_num_features, peak_threshold, edge_threshold, max_num_matches) are real COLMAP flags exposed as widgets, and you'll basically never touch them. matcher_type is sequential by default because your frames are ordered video - flip to exhaustive only for unordered stills.
Outputs
model_dir (the COLMAP dataset folder - feed it to your 3DGS trainer or the upscale workflow), plus num_images and num_points to sanity-check that SfM actually reconstructed something. Wire extra WAN clips into pano_frames_2/3/4 to concatenate multiple trajectories into one reconstruction.
Install
The whole pack installs together (all nodes live under the SplatKit category in ComfyUI):
cd ComfyUI/custom_nodes
git clone https://github.com/mickmumpitz/ComfyUI-SplatKit
python_embeded\python.exe -m pip install -r ComfyUI-SplatKit/requirements.txt
Non-portable install: python -m pip install -r ComfyUI-SplatKit/requirements.txt, then restart. You supply a WAN 2.1 i2v checkpoint and the Matrix-3D pano LoRA, converted with tools/convert_pano_lora.py into your loras folder. First run pulls the MoGe checkpoint into ComfyUI/models/MoGe.
Common issues
- "No good initial image pair found." This is the classic. COLMAP's default
init_min_tri_angleis 16°, tuned for wide-baseline photos; WAN/orbit clips have modest parallax (~4–15°), so SplatKit defaults to 4 - lower it further if SfM still won't start. - A static pan won't triangulate. This node needs real camera movement/parallax and a textured scene. Slow orbit = sparse cloud; no motion = nothing.
- "Need at least 3 frames" - lower
frame_strideor raisemax_frames. - GPU requirements. The CUDA build needs an NVIDIA Turing or newer for GPU matching; without one you fall back to CPU (slower, same result). macOS needs a self-built
colmap_spherebinary set viaCOLMAP_SPHERE_EXE. - The prompt matters. It must describe the actual scene - a wrong prompt visibly degrades what WAN paints into the holes, and bad holes mean bad SfM matches.
There's also reuse_solve: leave it off for the first build, turn it on when re-running the same clip - it skips the expensive solve and just re-renders the cube faces, guarded by a fingerprint that silently re-solves if anything changed.
Inputs (24)
| Name | Type | Default | Description |
|---|---|---|---|
| output_name | STRING | spheresfm_dataset | — |
| initial_panoopt | IMAGE | The pristine SOURCE equirect panorama (the still image WAN was conditioned on). Placed at frame 0000 of the SfM sequence and reprojected into cube faces like every other frame, so the reconstruction is anchored on the clean original instead of WAN's (often slightly drifted/degraded) first generated frame. Auto-resized to the WAN frame resolution (SphereSfM needs one camera size). See initial_pano_mode for replace-vs-prepend. | |
| pano_frames_1opt | IMAGE | The (first) WAN equirect pano video. Required in practice -- SfM needs frames -- but declared optional so it can sit below initial_pano in the input list. | |
| pano_frames_2opt | IMAGE | Optional extra WAN pano video (e.g. a second trajectory). Concatenated after pano_frames_1 before SfM runs. | |
| pano_frames_3opt | IMAGE | Optional third WAN pano video; concatenated in order. | |
| pano_frames_4opt | IMAGE | Optional fourth WAN pano video; concatenated in order. | |
| frame_strideopt | INT | 11–100 | Use every Nth frame. SfM cost grows with frame count; thin long clips but keep enough overlap for matching. |
| max_framesopt | INT | 00–1000 | Cap frames after stride (0 = no cap). |
| matcher_typeopt | COMBO | sequential | sequential = ordered video frames (fast, default). exhaustive = match all pairs (slower, for unordered stills). |
| face_sizeopt | INT | 00–2048 | Cube-face output resolution (px). 0 = auto (~equirect_w/4). Raise for sharper training images (more disk). |
| max_num_featuresopt | INT | 81921024–32768 | — |
| peak_thresholdopt | FLOAT | 0.00660–0.1 | — |
| edge_thresholdopt | FLOAT | 101–50 | — |
| max_num_matchesopt | INT | 327684096–131072 | — |
| filter_max_reproj_erroropt | FLOAT | 4.01–16 | — |
| filter_min_tri_angleopt | FLOAT | 1.50.1–10 | — |
| init_min_tri_angleopt | FLOAT | 4.00.5–16 | Min triangulation angle (deg) for the INITIAL image pair. COLMAP's default is 16, tuned for wide-baseline photos; WAN/orbit clips have modest parallax (~4-15 deg), so 16 causes 'No good initial image pair found'. Lower if SfM won't start; raise for a sturdier init. |
| init_min_num_inliersopt | INT | 3010–200 | Min verified inliers for the initial image pair (COLMAP default 100). |
| init_max_forward_motionopt | FLOAT | 1.000.5–1 | Max forward-motion ratio allowed for the initial pair (COLMAP default 0.95). Spherical cameras still get parallax under forward/push-in motion, so 1.0 lets push-in trajectories initialize. |
| modeopt | COMBO | colmap_now | colmap_now = run SfM now and output a cube-face COLMAP dataset (then upscale it in place with the camera-sorted upscale workflow). panorama_only = SKIP SfM and just save the raw equirect panoramas; the panorama upscale workflow then upscales the coherent equirect video and runs SphereSfM on the UPSCALED panoramas (best quality). |
| image_orderopt | COMBO | camera_major | Order recorded in the dataset marker for upscaling (COLMAP files are left untouched either way). camera_major groups each cube face into a coherent per-view sub-video so a temporal upscaler keeps fixed context; frame_major keeps the plain lexical (frame-by-frame) order. |
| initial_pano_modeopt | COMBO | replace | Only used when initial_pano is connected. replace = overwrite WAN's frame 0 with the pristine initial pano (they depict the same view, so this avoids a near-duplicate frame -- recommended). prepend = keep WAN's frame 0 and insert the initial pano just before it (adds one extra frame; use if WAN's first frame already drifted to a slightly different view). |
| initial_pano_hiresopt | BOOLEAN | true | Keep the initial_pano at its NATIVE (higher) resolution instead of downscaling it to the WAN frame size. ON (recommended if your pano is hi-res): the pano is registered as its own SPHERE camera, so its 6 cube faces are reprojected from the sharp original (set face_size high to keep that detail). OFF: resize the pano down to the WAN resolution (one shared camera) -- use as a fallback if your colmap_sphere build rejects the multi-camera path. |
| reuse_solveopt | BOOLEAN | false | Skip the SfM solve when this dataset's _spheresfm_work already holds one built from EXACTLY these frames and these SfM settings. Only the cube faces are re-rendered, so changing face_size or image_order costs seconds instead of a full feature/matching/bundle-adjustment pass. NO precision trade: the reused poses and sparse cloud are the identical files a fresh run would produce. If anything the solve depends on changed (frames, stride, initial_pano, any SIFT/mapper knob) it re-solves automatically and prints why. Leave OFF for a first build; turn ON when re-running the same clip. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| model_dir | STRING | — |
| num_images | INT | — |
| num_points | INT | — |