Nodes/ComfyUI-SplatKit/SphereSfM Dataset
ComfyUI Node

SphereSfM Dataset

One 360° panorama in, a trainable 3DGS dataset out — real SfM, not a learned guess

By mickmumpitz·Created about a month ago·Updated about 19 hours ago· 17
SphereSfM Dataset
  • initial_pano
  • pano_frames_1
  • pano_frames_2
  • pano_frames_3
  • pano_frames_4
  • model_dir
  • num_images
  • num_points
output_namespheresfm_dataset
frame_stride1
max_frames0
matcher_typesequential
face_size0
max_num_features8192
peak_threshold0.0066
edge_threshold10
max_num_matches32768
filter_max_reproj_error4.0
filter_min_tri_angle1.5
init_min_tri_angle4.0
init_min_num_inliers30
init_max_forward_motion1.00
modecolmap_now
image_ordercamera_major
initial_pano_modereplace
initial_pano_hirestrue
reuse_solvefalse

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 under ComfyUI/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_mode replace (default) overwrites WAN's frame 0; prepend keeps both.
  • mode - colmap_now (default) runs SfM and writes the cube-face dataset. panorama_only skips 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_angle is 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_stride or raise max_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_sphere binary set via COLMAP_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.

CategorySplatKit

Inputs (24)

NameTypeDefaultDescription
output_nameSTRINGspheresfm_dataset
initial_panooptIMAGEThe 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_1optIMAGEThe (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_2optIMAGEOptional extra WAN pano video (e.g. a second trajectory). Concatenated after pano_frames_1 before SfM runs.
pano_frames_3optIMAGEOptional third WAN pano video; concatenated in order.
pano_frames_4optIMAGEOptional fourth WAN pano video; concatenated in order.
frame_strideoptINT11–100Use every Nth frame. SfM cost grows with frame count; thin long clips but keep enough overlap for matching.
max_framesoptINT00–1000Cap frames after stride (0 = no cap).
matcher_typeoptCOMBOsequentialsequential = ordered video frames (fast, default). exhaustive = match all pairs (slower, for unordered stills).
face_sizeoptINT00–2048Cube-face output resolution (px). 0 = auto (~equirect_w/4). Raise for sharper training images (more disk).
max_num_featuresoptINT81921024–32768
peak_thresholdoptFLOAT0.00660–0.1
edge_thresholdoptFLOAT101–50
max_num_matchesoptINT327684096–131072
filter_max_reproj_erroroptFLOAT4.01–16
filter_min_tri_angleoptFLOAT1.50.1–10
init_min_tri_angleoptFLOAT4.00.5–16Min 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_inliersoptINT3010–200Min verified inliers for the initial image pair (COLMAP default 100).
init_max_forward_motionoptFLOAT1.000.5–1Max 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.
modeoptCOMBOcolmap_nowcolmap_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_orderoptCOMBOcamera_majorOrder 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_modeoptCOMBOreplaceOnly 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_hiresoptBOOLEANtrueKeep 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_solveoptBOOLEANfalseSkip 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)

NameTypeDescription
model_dirSTRING
num_imagesINT
num_pointsINT