Atlas Input π¬
Photo in, solved camera and projection out
- image
- raw_meta
- solve
- image
- depth
- sky_mask
- report
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). Needscomfyui-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
reportabout 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.
Inputs (29)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | β | |
| layersopt | INT | 00β4 | 0 = 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). |
| meshopt | COMBO | relief | layers=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_resolutionopt | INT | 512128β2048 | Relief 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_vlmopt | BOOLEAN | false | Run 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_provideropt | COMBO | lmstudio | 4 options: ollama, lmstudio, llamacpp, openai |
| vlm_modelopt | STRING | Blank = the provider's default model. | |
| skyopt | BOOLEAN | false | SAM-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_promptopt | STRING | sky | Manual sky segmentation prompt; the VLM's wins when use_vlm. |
| scope_promptsopt | STRING | Manual 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. | |
| inpaintopt | BOOLEAN | false | Build 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_modelopt | STRING | Optional 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_pxopt | INT | 240β256 | Behind-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_factoropt | FLOAT | 122β200 | World-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_heuristicopt | BOOLEAN | true | layers=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_degopt | FLOAT | 00β180 | 0 = 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_modelopt | COMBO | depth-anything/Depth-Anything-V2-Metric-Outdoor-Large-hf | Monocular 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_scopeopt | BOOLEAN | true | When 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_modeopt | COMBO | lama | How 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_pxopt | INT | 320β128 | Mask dilation before LaMa sky inpaint. Larger = more aggressive removal of foreground silhouettes from the sky plate. |
| sky_sdxl_checkpointopt | STRING | SDXL/sd_xl_base_1.0.safetensors | SDXL checkpoint filename in models/checkpoints when sky_inpaint_mode=sdxl. |
| sky_sdxl_positiveopt | STRING | clear seamless sky, high detail, no buildings, no trees, no roofs | Positive prompt for SDXL sky inpaint. |
| sky_sdxl_negativeopt | STRING | building, tree, roof, person, vehicle, text, watermark, blurry | Negative prompt for SDXL sky inpaint. |
| sky_sdxl_seedopt | INT | 00β18446744073709550000 | Seed for SDXL sky inpaint. 0 = deterministic default behavior of the sampler node. |
| retopo_methodopt | COMBO | off | Retopologize 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_countopt | INT | 2000100β200000 | Per-mesh vertex budget for quad/decimate (ignored by voxel_remesh). |
| boundary_smooth_iterationsopt | INT | 00β50 | Taubin-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_boundaryopt | BOOLEAN | false | layers=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_metaopt | ATLAS_RAW_META | β |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| solve | ATLAS_SOLVE | β |
| image | IMAGE | β |
| depth | ATLAS_DEPTH_MAP | β |
| sky_mask | MASK | β |
| report | STRING | β |