ComfyUI Node
HiRes Composite (8K texture into WAN frames)
A ComfyUI node in SplatKit with 28 inputs and 6 outputs.
HiRes Composite (8K texture into WAN frames)
- panorama
- wan_frames
- semantic_pano
- upscale_model
- moge_model
- hires_dir
- proxy_frames
- gate_masks
- report
- proxy_dir
- hires_manifest
◄rail►
◄set_namehires_composite►
◄traj_index0►
◄output_width8192►
◄base_modegeometry►
◄framesall►
◄proxy_width2048►
◄geom_scale2►
◄moge_level6►
◄merge_long1440►
◄depth_gridgeometry_res►
◄moge_ckpt▾►
◄rho_hi4.0►
◄tone_work1024►
◄prefetchtrue►
◄save_videofalse►
◄debug_saveoff►
◄gate_modehard_soft_edge►
◄tone_modeluma►
◄auto_namefalse►
◄save_proxiestrue►
◄gate_edge0.0►
◄edge_erode0►
CategorySplatKit
Inputs (28)
| Name | Type | Default | Description |
|---|---|---|---|
| panorama | IMAGE | The panorama, at its HIGHEST resolution (e.g. 8192x4096). It plays both roles: every output pixel geometry can explain is read from it (so its detail is the ceiling on the result), AND the MoGe depth / mesh is derived from it (downscaled to the geometry grid internally). This is the same image the Camera Plot / WAN branch was conditioned on -- feed the exact one, not an HDR-tonemapped or re-upscaled copy, or the reprojection stops lining up with what WAN generated. | |
| rail | STRING | Wire the Camera Plot node's rail_json output here -- the exact camera path its WAN clip was flown along. Use rail_json, not condition_dir: several Camera Plot nodes sharing one dataset_dir all write condition/, so only the last one's plain camplot_rail.json survives and the rest are lost for good. rail_json points at that node's own copy, named camplot_rail_<node_id>.json. A folder or file path also works. | |
| set_name | STRING | hires_composite | Folder under ComfyUI/output that collects this scene's composite frames. Give every trajectory of one scene the SAME set_name -- they share one frames/ folder, which is what the dual-res SfM node reads. |
| traj_index | INT | 00–31 | Which trajectory this is (0, 1, 2, ...). Only used to name the files (traj<NN>_frame_*.png). Give each Camera Plot branch a different one; re-running the same index replaces just that trajectory's frames. IGNORED when auto_name is on -- then a unique prefix is derived from the node id instead. |
| output_width | INT | 81921024–16384 | Composite width. Set it to the SOURCE panorama's width: at 8192 one output pixel covers one source pixel, so the 8K is sampled 1:1 through mip 0. Below that the source is minified before it is ever seen (+26% reconstructed detail measured for 8192 over 4096). |
| base_mode | COMBO | geometry | geometry (recommended): the reprojected source IS the image at every frequency, WAN only fills holes, tone-matched. wan: the original behaviour -- WAN is the base and supplies all low frequencies, source detail injected on top where the two agree. Right for a video, wrong for a splat: WAN's low frequencies drift between frames and 3DGS turns that into blur. |
| wan_framesopt | IMAGE | The WAN equirect video for THIS trajectory (same rail, same frame count). Fills the disocclusions. Leave unconnected to extrapolate the holes from the source instead -- seamless but it invents nothing, so big disocclusions smear. | |
| semantic_panoopt | IMAGE | Optional pano-space mask (white = region), e.g. a SAM3 'window'/'mirror' segmentation of the panorama. It is baked into the source panorama's alpha and reprojected along with it (no extra render pass), and wherever it lands the panorama is DROPPED so WAN prevails -- even though geometry could explain those pixels. Use it for glass: the reprojected pano only carries a frozen reflection there, so WAN's moving one should win. Needs wan_frames wired. Inspect the landed region with debug_save=all -> debug/force_wan/. | |
| upscale_modelopt | UPSCALE_MODEL | Optional upscaler for the WAN frames before they are composited (Load Upscale Model -> here). 4x-UltraSharp v1 is the measured default in the research project: ~9x faster than V2 (RRDBNet vs a DAT transformer) for a quality trade, not a loss. In geometry mode it only affects hole pixels. | |
| framesopt | STRING | all | Which frames to composite. 'all', '0-15', '/8' (every 8th), or '0-15,16-/8' -- all of the first 16 then every 8th, which takes 25 of 81 frames. Coverage is highest near the start of a trajectory and decays as the camera leaves the panorama's viewpoint, so spend the budget there. |
| proxy_widthopt | INT | 2048512–4096 | Width of the proxy_frames output (the SfM input). SPHERE poses are angular, so posing gains nothing from 8K -- 2048 finds the same features far cheaper and keeps exhaustive matching affordable. |
| geom_scaleopt | INT | 21–3 | Coordinate-field raster = 2048 x this, wide. 2 rasterises the field at output resolution: sharper silhouettes for ~0.24 GB more VRAM. 1 is the cheap setting. |
| moge_levelopt | INT | 60–9 | MoGe detail level. Keep it at the value Camera Plot used (6) -- that reuses its cached depth AND guarantees the geometry is the one WAN saw. Level 9 measured identical usable area at 3x the cost: a depth discontinuity is a property of the scene, not of depth resolution. |
| merge_longopt | INT | 1440512–4096 | Panorama depth-merge resolution. Keep it matched to Camera Plot (1440) for the same reason as moge_level. |
| depth_gridopt | COMBO | geometry_res | Which grid MoGe estimates on. geometry_res (default) matches the research pipeline exactly -- validated to 56 dB against its reference frame, coverage identical to 4 decimals. conditioning_2k estimates on the 2048x1024 grid Camera Plot already used, so it reuses that cached depth (~30 s faster) at the cost of one extra resample: 0.2% coverage difference measured. The lsmr merge is at merge_long either way, so neither is a better estimate. |
| 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'. | |
| rho_hiopt | FLOAT | 4.01–16 | Minification cut-off: source pixels per output pixel above which the source is dropped in favour of WAN. Raising it keeps more of the frame at grazing angles. Tuned while an 8-bit coordinate bug was active, so it is likely tighter than it needs to be -- a sweep here is the highest-value tuning left. |
| tone_workopt | INT | 10240–8192 | Width the hole-fill tone gain is evaluated at (0 = full output width). The gain is a low-pass by construction, so a 1024 grid is exact to under a quantisation step (max 2/255) and turns 55 s/frame into 0.16 s at 8192. |
| prefetchopt | BOOLEAN | true | Rasterise the next chunk of frames while the current one is still being composited, instead of alternating render-burst and per-frame work. Costs host RAM: it keeps two chunks of render passes, which at geometry_scale 2 is a few GB. Turn OFF if you are short on system memory. |
| save_videoopt | BOOLEAN | false | Also write composite.mp4 next to the frames (h264, crf 14). Handy for eyeballing temporal stability; irrelevant to the dataset. |
| debug_saveopt | COMBO | off | Write the layers each frame is built from into <set_name>/debug/, under the same filenames as frames/, plus a README explaining them. Only the finished blend normally reaches disk, so a soft or discoloured region gives you no way to tell which input it came from. 'all' writes: source (the panorama reprojected into this view), gate (white = panorama, black = hole filled by WAN), and the WAN frame raw / upscaled / tone-matched -- together they reproduce the frame exactly. 'wan' writes only the raw WAN frame, which is small. 'all' is five full-size PNGs per frame (~40 MB each), so pair it with a short frames spec. |
| gate_modeopt | COMBO | hard_soft_edge | How the panorama/WAN decision is shaped. hard_soft_edge (default): every pixel is EITHER the panorama OR the WAN fill, with only the boundary itself faded over a few pixels so the join does not stair-step. hard: the same, with no fade at all. soft_original: the research project's gate untouched -- the boundary is feathered AND the decision is carried over between frames, so whole AREAS sit at part-panorama/part-WAN. The panorama side is a stretched smear wherever geometry ran out, so those areas wash smear over otherwise clean WAN: measured ~21% of it across the disoccluded parts of a long-travel rail, against ~2% either other way. Use soft_original only to reproduce old numbers. |
| tone_modeopt | COMBO | luma | How the hole fill is matched to the surrounding photograph. WAN's exposure drifts frame to frame and the source's does not, so a raw paste seams; this is the correction. luma (default): measure the correction on BRIGHTNESS only and apply it to all three channels -- fixes the seam and leaves WAN's colour untouched. rgb: measure it per channel, which is the research implementation, but a per-channel ratio rewrites HUE as well: a patch of sky ringed by foliage has its blue pulled down and comes out olive (measured 14% harder on blue than red across the garden rail's holes). Use rgb only to reproduce reference numbers. off: paste WAN unmodified and accept the seams. |
| moge_modelopt | MOGE_MODEL | Optional pre-loaded MoGe model (MoGe Model Loader). Note depth is cached on the panorama + params anyway, so wiring the same one Camera Plot used mainly saves a reload. | |
| auto_nameopt | BOOLEAN | false | ON: name this trajectory's files by the node's own id (auto<id>_frame_*.png) instead of traj_index -- so duplicated path branches can never collide in the shared frames/ folder and you never set an index by hand. The SphereSfM nodes read the hires_manifest, so the name itself is irrelevant to them. OFF (default): use traj_index, exactly as before. |
| save_proxiesopt | BOOLEAN | true | Write the downscaled proxy PNGs to <set_name>/proxies/. ON (default, unchanged behaviour): keep them on disk -- handy to eyeball what SfM is posing on. OFF: skip writing them (saves several hundred MB - a few GB per trajectory). Safe either way: the proxy_frames OUTPUT is always populated and is what actually feeds pano_frames_* downstream -- nothing in this pack re-reads proxies/ off disk. |
| gate_edgeopt | FLOAT | 0.00–32 | Only used when gate_mode=hard_soft_edge: sigma (in OUTPUT pixels) of the FEATHER applied to the gate boundary so the photo/WAN join does not stair-step. Default 0 = genuinely BINARY gate: every pixel is either pure panorama or pure WAN fill, no in-between blend band at all (WAN fills the hole, so the feather band tended to add bright/broken pixels for no gain). Set it above 0 to soften the join instead -- e.g. 4.0 for the old shipped feather. This ONLY feathers; it never erodes (see edge_erode for that). |
| edge_erodeopt | INT | 00–32 | Pull the panorama side back this many OUTPUT pixels from the raw gate boundary before any feathering (both hard_gate modes). 0 (default): off, unchanged behaviour. The confidence gate is already eroded upstream, so this is only needed if you still see a bright/broken ring of smeared reprojection right at the seam after setting gate_edge=0 -- try 1-2 first. |
Outputs (6)
| Name | Type | Description |
|---|---|---|
| hires_dir | STRING | — |
| proxy_frames | IMAGE | — |
| gate_masks | IMAGE | — |
| report | STRING | — |
| proxy_dir | STRING | — |
| hires_manifest | STRING | — |