Nodes/ComfyUI-SplatKit/HiRes Composite (8K texture into WAN frames)
ComfyUI Node

HiRes Composite (8K texture into WAN frames)

A ComfyUI node in SplatKit with 28 inputs and 6 outputs.

By mickmumpitz·Created 19 days ago·Updated a day ago· 0
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)

NameTypeDefaultDescription
panoramaIMAGEThe 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.
railSTRINGWire 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_nameSTRINGhires_compositeFolder 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_indexINT00–31Which 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_widthINT81921024–16384Composite 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_modeCOMBOgeometrygeometry (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_framesoptIMAGEThe 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_panooptIMAGEOptional 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_modeloptUPSCALE_MODELOptional 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.
framesoptSTRINGallWhich 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_widthoptINT2048512–4096Width 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_scaleoptINT21–3Coordinate-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_leveloptINT60–9MoGe 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_longoptINT1440512–4096Panorama depth-merge resolution. Keep it matched to Camera Plot (1440) for the same reason as moge_level.
depth_gridoptCOMBOgeometry_resWhich 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_ckptoptCOMBOMoGe 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_hioptFLOAT4.01–16Minification 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_workoptINT10240–8192Width 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.
prefetchoptBOOLEANtrueRasterise 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_videooptBOOLEANfalseAlso write composite.mp4 next to the frames (h264, crf 14). Handy for eyeballing temporal stability; irrelevant to the dataset.
debug_saveoptCOMBOoffWrite 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_modeoptCOMBOhard_soft_edgeHow 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_modeoptCOMBOlumaHow 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_modeloptMOGE_MODELOptional 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_nameoptBOOLEANfalseON: 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_proxiesoptBOOLEANtrueWrite 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_edgeoptFLOAT0.00–32Only 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_erodeoptINT00–32Pull 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)

NameTypeDescription
hires_dirSTRING
proxy_framesIMAGE
gate_masksIMAGE
reportSTRING
proxy_dirSTRING
hires_manifestSTRING