Nodes/Atlas Camera/Atlas Input 🎬
ComfyUI Node

Atlas Input 🎬

Photo in, solved camera and projection out

By mikejamesvfxΒ·Created 3 months agoΒ·Updated a day agoΒ· 1
Atlas Input 🎬
  • image
  • raw_meta
  • solve
  • image
  • depth
  • sky_mask
  • report
β—„layers0β–Ί
β—„meshreliefβ–Ί
β—„mesh_resolution512β–Ί
β—„use_vlmfalseβ–Ί
β—„vlm_providerlmstudioβ–Ί
β—„vlm_modelβ–Ί
β—„skyfalseβ–Ί
β—„sky_promptskyβ–Ί
β—„scope_promptsβ–Ί
β—„inpaintfalseβ–Ί
β—„upscale_modelβ–Ί
β—„edge_extend_px24β–Ί
β—„max_edge_factor12β–Ί
β—„sky_heuristictrueβ–Ί
β—„normal_edge_deg0β–Ί
β—„depth_modeldepth-anything/Depth-Anything-V2-Metric-Outdoor-Large-hfβ–Ί
β—„vlm_scopetrueβ–Ί
β—„sky_inpaint_modelamaβ–Ί
β—„sky_lama_grow_px32β–Ί
β—„sky_sdxl_checkpointSDXL/sd_xl_base_1.0.safetensorsβ–Ί
β—„sky_sdxl_positiveclear seamless sky, high detail, no buildings, no trees, no roofsβ–Ί
β—„sky_sdxl_negativebuilding, tree, roof, person, vehicle, text, watermark, blurryβ–Ί
β—„sky_sdxl_seed0β–Ί
β—„retopo_methodoffβ–Ί
β—„retopo_target_vertex_count2000β–Ί
β—„boundary_smooth_iterations0β–Ί
β—„sub_quad_boundaryfalseβ–Ί

AtlasInput is the front door to the whole atlas-camera pack, and it's the one node most people should start with and never leave. Wire a photograph into it and you get a metric pinhole camera solve, projection geometry, a depth map and a report - the entire "photo β†’ 2.5D projection scene" chain collapsed into a single node with sensible defaults. If you've ever tried to fake a dolly move on a still and ended up with smeared texture instead of parallax, this is the tool that makes the difference explicit: it recovers a real camera first, then projects the photo onto derived geometry from that camera's viewpoint. From where the camera actually stood, the plate reassembles exactly; scale error only shows up as parallax on a move, never as stretched pixels.

How it works

One photograph in. The solve recovers focal length, orientation and horizon - either from a deterministic geometric solve (vanishing points, straight lines) or, for harder frames, from a learned single-image prior called GeoCalib. You've probably already met GeoCalib's results without knowing the name: it's the same estimator people use to pull camera intrinsics off a video frame for 360Β° panorama projection. Monocular depth (Depth Anything V2 Metric-Outdoor by default) then turns that camera into a relief mesh, and the plate gets cast back through it.

Under the hood the node doesn't actually do all that in one Python function - it expands into a real mini-graph of the pack's inner nodes at execution, so every step keeps its own cache and missing optional packs degrade to a note in the report output instead of killing your queue. That's worth knowing when something's slow: the pieces are all individually tunable if you later decide AtlasInput isn't enough.

The inputs that matter

The required input is just image - any tensor ComfyUI can produce. Almost everything else has a default that's right for a first run:

  • layers (default 0) - the single biggest knob. 0 gives one full-range relief mesh, instant. Set it to 2–4 and you get depth-band clean-plate layers (the splits are proven: 2β†’0.55, 3β†’0.2/0.65, 4β†’0.3/0.6/0.8) that are watertight by construction. That's the 2.5D matte-painting stack.
  • mesh_resolution (default 512) - relief grid cells along the long edge. 512 is a fine default for a 4K plate; drop it for quick previews.
  • sky (default off) - SAM-segments the sky onto its own flat card and feeds the mask into every mesh. Big for outdoor plates.
  • inpaint (default off) - builds each occluded band's clean plate (occlusion mask β†’ expand β†’ crop β†’ LaMa β†’ stitch). Needs comfyui-inpaint-nodes + big-lama.pt; if they're absent it's skipped and noted, not fatal.
  • use_vlm (default off) - an advisory VLM pass that wires segmentation prompts and per-band geometry into the inner nodes. This is where the pack gets clever, but it's strictly optional and only if you have a local VLM server.

The outputs are solve (the recovered camera - feed this to export or viewport nodes), image (the processed plate), depth, sky_mask, and report (a plain-text run-down of what actually happened).

Install

Install the pack once and every Atlas node comes with it - search atlas-camera in ComfyUI Manager, or:

cd <ComfyUI>/custom_nodes
git clone https://github.com/mikejamesvfx/atlas-camera.git

Restart ComfyUI. The core solve is pure Python with no dependencies; the learned depth backend needs transformers (ComfyUI already ships torch), and GeoCalib installs separately if you want the neural solve for hard frames. A GPU only matters for the neural parts - the deterministic solve runs on a potato.

Troubleshooting

  • First queue is slow. It's loading the depth model for the first time; that's a one-off.
  • Relief mesh looks "combed" or shredded - that's the world-space edge tear threshold (max_edge_factor, default 12) being tripped by grazing walls or receding floors. Raise it to 40–80; the tooltip is unusually honest about this.
  • Interior plates punch big holes in walls/ceilings. sky_heuristic (default on) is eating far regions as sky. Turn it off indoors.
  • A note in report about a skipped stage (LaMa, SAM3) means an optional extra isn't installed - check the README's dependency tiers before blaming the node.

AtlasInput is the pack's whole thesis in one node. Outgrow it and the rest of the Atlas menu takes over individual stages - but most people won't need to.

CategoryAtlas/01 Β· Input & Camera

Inputs (29)

NameTypeDefaultDescription
imageIMAGEβ€”
layersoptINT00–40 = one full-range mesh (instant relief). 2/3/4 = depth-band clean-plate layers on the proven splits (2β†’0.55; 3β†’0.2/0.65; 4β†’0.3/0.6/0.8), watertight by construction. 1 = one full-range clean-plate layer (useful with mesh=card/ground).
meshoptCOMBOrelieflayers=0: relief = depth-following mesh; card/ground = ONE flat plane (band-median card / analytic ground). layers>0: the DEFAULT band geometry β€” the VLM's per-band call wins when use_vlm is on.
mesh_resolutionoptINT512128–2048Relief grid (long-edge cells). Internal tear threshold pairs automatically: 0.5 for the single full-range mesh, 1.5 for band-clipped layers (the calibrated pairings).
use_vlmoptBOOLEANfalseRun the 🧭 VLM assessment first (advisory β€” never blocks; VRAM offloaded after) and wire its SAM prompts, per-band geometry, and band boundaries into the inner nodes. With layers>0 this forces the 4-band plan (the VLM's plan has 5 fixed slots).
vlm_provideroptCOMBOlmstudio4 options: ollama, lmstudio, llamacpp, openai
vlm_modeloptSTRINGBlank = the provider's default model.
skyoptBOOLEANfalseSAM-segment the sky onto its own flat card, and feed the mask into every mesh's exclude_mask + band_ref_mask. Uses native SAM3 (transformers>=5.5.4, [sam3] extra) or falls back to AtlasSemanticMask β€” skipped + noted if neither is available.
sky_promptoptSTRINGskyManual sky segmentation prompt; the VLM's wins when use_vlm.
scope_promptsoptSTRINGManual per-band SAM scoping, ONE PROMPT PER LINE far→near (line 1 = farthest band). Blank line = that band stays band-only. Self-disarming: a no-match segment falls back to band-only automatically. The VLM's prompts win when use_vlm. Uses native SAM3 ([sam3] extra) or AtlasSemanticMask.
inpaintoptBOOLEANfalseBuild each occluded band's clean plate: occlusion mask β†’ expand β†’ βœ‚crop β†’ LaMa β†’ βœ‚stitch (the 256Β²-bottleneck fix). Needs comfyui-inpaint-nodes + big-lama.pt β€” skipped + noted if absent. Off = bands project the original photo (honest holes on reveal).
upscale_modeloptSTRINGOptional upscale model FILENAME (models/upscale_models) fed to the inner LaMa nodes β€” e.g. 4xRealWebPhoto_v4_dat2.safetensors. Measured 6.5Γ— fill detail vs legacy. Blank = off.
edge_extend_pxoptINT240–256Behind-band edge-extend (layers>0): how far plate colours smear PAST each silhouette to hide grid-step tears β€” the frontmost band always keeps a clean 0 cut. Was baked at 64 (tuned for smooth ridgelines); lower it for high-frequency content like foliage, which 64 shreds into halos. 0 = clean cut on every band.
max_edge_factoroptFLOAT122–200World-space edge tear threshold (layers=0 relief AND layers>0 bands), SEPARATE from depth_edge_rel and often the DOMINANT tear cause on deep / narrow-FOV / interior scenes β€” grazing walls and receding floors trip the default 12x even where continuous, shredding the mesh into 'combs'. Raise to 40-80 to close them; >80 rubber-sheets real foreground silhouettes onto the background.
sky_heuristicoptBOOLEANtruelayers=0 relief mesh: exclude above-horizon far/rough regions as sky before triangulation. Correct OUTDOORS; turn OFF for INTERIORS (it eats the ceiling / vault / far wall as 'sky', punching large holes). Ignored when sky (the SAM card) is on β€” that mask governs. (layers>0 bands: sky handled per-band via exclude/scope instead.)
normal_edge_degoptFLOAT00–1800 = off. A THIRD tear test on surface-normal BEND (layers=0 relief AND layers>0 bands): tears real creases / occlusion silhouettes while leaving smoothly-receding walls and floors intact (unlike max_edge_factor, which trips on any grazing surface). Pair with a HIGHER max_edge_factor: raise mef to stop comb-tearing continuous grazing surfaces, then set ~40-70 here to keep genuine edges torn.
depth_modeloptCOMBOdepth-anything/Depth-Anything-V2-Metric-Outdoor-Large-hfMonocular depth backend (fed the solved focal). V2-Metric-Outdoor (DEFAULT) = Apache, transformers-only (NO extra install), best all-round on OUTDOOR/sky scenes; V2-Metric-Indoor is its interior twin. MoGe-2 (Ruicheng/moge-*) = MIT, cleanest on ENCLOSED/INTERIOR shots but masks sky (poor outdoors) β€” needs [moge]. DA3* (EXPERIMENTAL) = strong metric, heavy deps, DA3NESTED is non-commercial CC BY-NC β€” needs [neural-da3]. Pick per shot: outdoor->V2-Outdoor, interior->MoGe or V2-Indoor. (A/B 2026-07-13.)
vlm_scopeoptBOOLEANtrueWhen use_vlm: also SCOPE each band by the VLM's SAM prompt (band ∩ segment). A PARTIAL segment match legitimately keeps the scope and can cut real band geometry β€” found live on the ghost-town plate, where the mid band's 4.6% segment left the rest of the band exposing the behind-band's fill smear. OFF = VLM still drives bands/geometry, layers stay band-only (robust full coverage β€” best for camera moves).
sky_inpaint_modeoptCOMBOlamaHow to build the sky card's clean plate: lama = fast deterministic edge-fill (needs comfyui-inpaint-nodes), sdxl = generative SDXL inpaint (needs a checkpoint).
sky_lama_grow_pxoptINT320–128Mask dilation before LaMa sky inpaint. Larger = more aggressive removal of foreground silhouettes from the sky plate.
sky_sdxl_checkpointoptSTRINGSDXL/sd_xl_base_1.0.safetensorsSDXL checkpoint filename in models/checkpoints when sky_inpaint_mode=sdxl.
sky_sdxl_positiveoptSTRINGclear seamless sky, high detail, no buildings, no trees, no roofsPositive prompt for SDXL sky inpaint.
sky_sdxl_negativeoptSTRINGbuilding, tree, roof, person, vehicle, text, watermark, blurryNegative prompt for SDXL sky inpaint.
sky_sdxl_seedoptINT00–18446744073709550000Seed for SDXL sky inpaint. 0 = deterministic default behavior of the sampler node.
retopo_methodoptCOMBOoffRetopologize every relief mesh (single mesh or all bands) via ONE AtlasRetopologizeLayer πŸ”· (layer='*') at the end of the chain β€” the sky dome is never touched. off (DEFAULT) = free; quad/decimate reduce to the vertex budget; voxel_remesh closes interior tears watertight. For `smooth` (interior Taubin) use the standalone πŸ”· node β€” here boundary_smooth_iterations covers the silhouette-rounding case.
retopo_target_vertex_countoptINT2000100–200000Per-mesh vertex budget for quad/decimate (ignored by voxel_remesh).
boundary_smooth_iterationsoptINT00–50Taubin-relax every open boundary loop AFTER retopo β€” rounds lattice-staircase silhouette jaggies; projective UVs regenerated per layer camera. Works with retopo_method=off ('just round the silhouette'). 0 = off. Pair with sub_quad_boundary: smoothing ROUNDS a staircase, the cut RELOCATES it (measured 5.67 -> 1.43px alone, 1.35px together).
sub_quad_boundaryoptBOOLEANfalselayers=0 relief mesh: cut a torn cell AT the depth cliff instead of deleting the whole cell. Tearing is per grid cell, so a silhouette turns only in whole-cell steps AND a cell of real surface is lost on both sides of every cliff - measured 5.67px mean boundary error at grid 128 on a 1024px plate (step 8px), WORSE than the 4px quantization bound. Reads the cliff out of the full-resolution depth and rebuilds both sides up to it, never joining them: 5.67 -> 1.43px, camera coverage 97.8 -> 100%, ~5% more vertices. Same thresholds, same cells torn - the tear is untouched. Ignored when layers>0 (bands build their own meshes).
raw_metaoptATLAS_RAW_METAβ€”

Outputs (5)

NameTypeDescription
solveATLAS_SOLVEβ€”
imageIMAGEβ€”
depthATLAS_DEPTH_MAPβ€”
sky_maskMASKβ€”
reportSTRINGβ€”