HiRes Pano Fly-Through
Real pinhole views straight from the panorama, no WAN required
- panorama
- moge_model
- frames
- hole_mask
- cameras_json
- splat_mask
The control-video path (Plot Camera → WAN) is about inventing content the panorama never saw. This node is the opposite bet: it takes the real panorama, renders a fly-through through the MoGe mesh at full output resolution, and closes the disocclusion holes itself instead of punching them out for WAN. Geometry and texture resolution are independent here - colour is always sampled from the untouched full-res panorama, so an 8K pano lands every pixel in a 4K render. That's why the pack bills it as the sharpness lever for getting crisp splats.
How it closes holes is the edge_mode menu: layered (default) re-grows a background layer behind each silhouette from the real pano pixels, only push-pull filling what that still misses - slowest, sharpest; fill is fast and soft; stretch never tears but smears; cut leaves the holes for you to do something with. Keep the moves small. The docstring is blunt: this node "cannot invent a whole new viewpoint." movement_scale defaults to 0.15 (a fraction of median scene depth), and scale_mode picks how literal anchors are - auto renormalises the whole path against scene depth with a collision guard; travel sets how far the farthest frame gets from the origin.
Two tricks for more coverage from one pano
directions(default 6): render the same path once per azimuth, fanned 360/N apart (6 → every 60°). Each direction starts at the pano origin and is scaled/collision-guarded independently, so a path that clears a wall one way still clears it the others. Output is one batch ofdirections × lengthframes.spiral_radius: orbit the camera up-left-down-right around its line of sight while it flies (0.02–0.1 is a usable orbit). Sweeps parallax across the frame - good SfM/splat coverage - without ever turning the camera. Withorientation = look_at_pointthe orbit turns into an arc around a fixed spot, like a crane shot.
Inputs and outputs that matter
panorama, anchors, orientation (fixed_forward default = pure dolly, least tearing), length, width/height, fov_deg. Quality knobs: mesh_width (2048; 4096 = 33M triangles for sharp silhouettes at long lenses), edge_rtol (lower = more edges cut, fewer smears), bg_extend_px (raise if holes survive at larger moves), moge_level (defaults to 9 - "this node is about quality").
Outputs: frames, hole_mask, cameras_json (exact intrinsics), and splat_mask (white = real, unstretched pano detail; black = synthesized/stretched or hole). That last one is the training-grade truth: wire frames + cameras_json into Add HiRes Views to Dataset to register these as their own PINHOLE cameras in your dataset, and splat_mask there to write per-view masks that let nerfstudio (--masks-path masks) or Brush exclude the fake pixels from the loss.
Install & gotchas
cd ComfyUI/custom_nodes
git clone https://github.com/mickmumpitz/ComfyUI-SplatKit
python_embeded\python.exe -m pip install -r ComfyUI-SplatKit/requirements.txt
Restart, first run downloads MoGe into ComfyUI/models/MoGe. The classic failure: layered mode still leaves holes because bg_extend_px (24 default) is smaller than the disocclusion width at your movement_scale - raise it or shrink the move. And if you plan to add these views to a dataset, render them from the same panorama the dataset was built from; SfM registers them by image features, and views of a different scene simply won't match.
Inputs (22)
| Name | Type | Default | Description |
|---|---|---|---|
| panorama | IMAGE | — | |
| anchors | STRING | 0, 0, 0 0.15, 0, 0.4 0.3, 0.05, 0.8 | Camera fly-through points, same frame/format as Camera Plot: +Z forward into the pano, +X right, +Y up, origin = start camera. One 'x,y,z' per line or JSON [[x,y,z],...]. Keep the moves SMALL here -- this node closes disocclusions from a single pano, it cannot invent a whole new viewpoint. |
| orientation | COMBO | fixed_forward | fixed_forward = camera keeps the pano's forward heading (pure dolly; least tearing). look_forward = camera turns to face the path tangent. look_at_point = camera stays AIMED at a fixed anchor point picked automatically per direction (where that direction's forward ray hits the scene) -- with a spiral this turns the orbit into an arc AROUND the spot, like a crane shot. |
| length | INT | 491–257 | Frames along the path. 1 = a single still at the first anchor. |
| width | INT | 1920256–8192 | Output width. This is a REAL pinhole render -- unlike the WAN control path (6x512 cube faces), detail here is limited only by the input panorama. |
| height | INT | 1080256–8192 | — |
| fov_deg | FLOAT | 7520–140 | Horizontal field of view of the rendered camera. |
| edge_mode | COMBO | layered | How disocclusions are handled. layered = re-grown background layer behind the holes (sharpest, slowest). fill = push-pull hole fill (fast, soft). stretch = never punch holes at all (rubber-sheet smear). cut = leave the holes (WAN-style mask). |
| movement_scale | FLOAT | 0.150.01–3 | Travel gain. scale_mode=auto: the path's most extreme frame reaches this fraction of the scene depth. absolute: 1 anchor unit = this x median scene depth. travel: the farthest frame sits exactly this fraction of the MEDIAN scene depth from the origin. Small values (0.05-0.3) keep disocclusions small enough to close convincingly. |
| scale_mode | COMBO | auto | auto = renormalise the whole path against the scene depth (collision guard, anchor magnitude ignored). absolute = anchor coords taken literally in units of median scene depth. travel = origin-anchored: movement_scale directly sets how far the path's farthest frame gets from the pano origin, as a fraction of the median scene depth -- predictable travel, same for every direction. No collision guard (a warning prints if the path would cross geometry). |
| mesh_widthopt | COMBO | 2048 | Geometry (depth-grid) resolution. Independent of output resolution -- colour always comes from the full-res panorama. 4096 = 33M triangles: much slower, sharper silhouettes. |
| edge_rtolopt | FLOAT | 0.0500.005–0.5 | Depth-edge sensitivity (relative depth jump that counts as a discontinuity). Lower = more geometry treated as an edge = more holes cut but fewer smears. |
| bg_extend_pxopt | INT | 244–128 | layered mode: how far (in depth-grid pixels) the background is re-grown behind each silhouette. Must exceed the disocclusion width; raise it if holes survive at large movement_scale. |
| moge_levelopt | INT | 90–9 | MoGe detail level. 9 = max (this node is about quality). |
| merge_longopt | INT | 1920512–4096 | Panorama depth-merge resolution (long side). The dominant MoGe cost; 1920x960 is the full-quality setting. |
| moge_ckptopt | COMBO | MoGe checkpoint from ComfyUI/models/MoGe. 'auto (download)' fetches 'Ruicheng/moge-vitl' into that folder on first use (~1.2GB). Drop your own model.pt in models/MoGe to pick it here, or wire a MoGe Model Loader node into 'moge_model'. | |
| moge_modelopt | MOGE_MODEL | Optional: a pre-loaded MoGe model from the MoGe Model Loader node. Overrides moge_ckpt; load once and reuse across nodes. | |
| output_nameopt | STRING | comfy_hires | — |
| directionsopt | INT | 61–36 | Render the SAME path once per azimuth, fanned evenly around the panorama (360/directions apart: 6 -> every 60 deg). The output is one batch of directions x length frames, in order. Each direction starts at the pano origin and is scaled/collision-guarded independently, so a path that clears a wall in one direction still clears it in the others. 1 = single direction. |
| spiral_radiusopt | FLOAT | 0.000–1 | Optional spiral: the camera orbits up-left-down-right around its line of sight while it flies the path (with look_at_point it orbits the anchor spot instead). 0 = off. Units are fractions of the MEDIAN scene depth, applied AFTER path scaling -- the orbit size no longer rides on movement_scale, so raising the travel does not widen the spiral. 0.02-0.1 is a usable orbit. Sweeps parallax across the frame -- good for splat/SfM coverage. |
| spiral_turnsopt | FLOAT | 1.00.1–8 | Full circles the spiral completes over the path's length. |
| spiral_phase_degopt | FLOAT | 00–360 | Which way the spiral sets off from the start point. 0 = up (then left, down, right). 90 = left first, 180 = down first, 270 = right. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| frames | IMAGE | — |
| hole_mask | IMAGE | — |
| cameras_json | STRING | — |
| splat_mask | IMAGE | — |