Nodes/Atlas Camera/Atlas Viewport 🧊
ComfyUI Node

Atlas Viewport 🧊

The browser 3D view that turns a photo into a scene

By mikejamesvfxΒ·Created 2 months agoΒ·Updated a day agoΒ· 1
Atlas Viewport 🧊
  • solve
  • source_image
  • primary_depth
  • controls
  • shot_cam
  • output_profile
  • debug_matte
  • patch_mask
  • clean_plate
  • shaded
  • depth
  • normal
  • mask
  • path_frames
  • camera_path
  • patch_azimuth_view
  • patch_elevation_view
  • patch_distance
  • patch_prompt
  • patch_exact
  • patch_render_mask
  • solve
  • drawn_mask
  • draw_report
β—„resolution1024β–Ί
β—„client_dataβ–Ί
β—„preview_expand1.00β–Ί
β—„drawn_fill_px96β–Ί
β—„auto_presetoffβ–Ί
β—„auto_frames0β–Ί

Atlas Viewport 🧊 (class AtlasBlockoutViewport) is the node you'll spend the most time staring at. It opens a real-time 3D viewport in the ComfyUI browser, pre-aligned to your recovered camera, so you can actually look through the scene before you export it. It's the pack's review room, blockout tool, camera-path author, and angle-extractor all in one node.

What it does

The pattern mirrors the Yedp Blockout approach: the browser renders, sends base64 JSON to Python, Python decodes it, and out come proxy image outputs. Concretely:

  1. Connect an ATLAS_SOLVE and source_image, queue once.
  2. The Three.js viewport opens, camera locked to the photo.
  3. Place primitive geometry - box, plane, person card - to block out the scene.
  4. Click Render Proxy Passes; it fills client_data and re-queues.
  5. Four proxy/LDR outputs come alive: shaded, depth, normal, mask - wire them into ControlNet or compositing.

resolution sets the long-edge render size (128–8192, default 1024); the short side auto-follows your source image's aspect. You can also drag the node's resize handle. A shot_cam from AtlasDefineShotCam conforms it to a project format instead.

The two features that make it the hub

Camera Path mode. Author a keyframed move in the viewport. "⏺ Bake Full Path" produces path_frames (a proxy image batch - feed it to repair preview or Video Combine) plus camera_path (the raw keyframes, feed it to AtlasExportCameraPathUSD for a real animated camera). "πŸ“· Bake Repair Frame" stores only the final preview frame for path-guided repair. Frames outside the recovered camera's cone show the documented black/undefined regions - expected, not a bug.

Extract Angle πŸ“. This is the multi-angle patch workflow's best friend. Orbit to the view you want a patch generated at, click πŸ“, and the node measures the orbit delta from the recovered camera, snaps it to the Qwen Multiple-Angles LoRA's nearest named views, and outputs four strings: patch_azimuth_view, patch_elevation_view, patch_distance (wire into AtlasAddPatchView's widgets) and patch_prompt (the ready-to-use <sks> [azimuth] [elevation] [distance] LoRA prompt). The delta uses the same pivot the backend uses, so the snapped views round-trip exactly. Until you extract an angle these outputs return an ExecutionBlocker - downstream branches stay paused rather than wasting a generation on a zero-orbit patch.

What else is under the hood

preview_expand dilates geometry for wider orbit coverage - leave it at 1.0 if you use Project mode, or the dilated fringe has no real photo data and renders black. clean_plate projects a background plate through the same registered projector so tears reveal a clean backdrop. drawn_fill_px (default 96) fills drawn shapes by smearing surrounding plate colors - deterministic edge-extend, not an inpaint; set 0 and route drawn_mask to a real inpaint if you prefer. primary_depth powers the ray-traced occlusion-culling (βœ‚ Occlude) toggle. And if the node feels cramped, connect an AtlasViewportControls node to controls to move every button and panel off this one - the link carries no data, it just lets the two frontends find each other.

The node outputs a lot: the four proxy passes, path_frames, camera_path, the four patch strings, patch_render_mask, the pass-through solve, drawn_mask, and draw_report. It's an output node, so it renders even with nothing downstream.

Install is the pack's clone-and-go. The depth-dependent culling wants the [neural] extra, and heavy orbits want a GPU, but the core viewport runs on CPU fine.

CategoryAtlas/08 Β· Look & Render

Inputs (15)

NameTypeDefaultDescription
solveATLAS_SOLVEβ€”
source_imageIMAGEβ€”
resolutionINT1024128–8192Long-edge render resolution; the short side auto-follows the source image aspect (viewport inherits the image's aspect). Also settable by dragging the node's own resize handle.
client_dataSTRINGβ€”
primary_depthoptATLAS_DEPTH_MAPOptional depth map matching the source image AND the depth object used to derive the displayed relief mesh. Do not pair a DCC retopo preview regenerated with another depth model. Used by the viewport to power the ray-traced occlusion culling feature (βœ‚ Occlude).
preview_expandoptFLOAT1.001–5Dilate derived geometry outward from the camera for wider orbit coverage before it disappears into unreconstructed space. 1.0 = off (accurate geometry). Display only β€” never affects DCC exports or measured geometry. CAUTION: values above 1.0 dilate geometry beyond what the camera actually photographed, so with πŸ“½ Project active the dilated fringe has no real photo data and renders as empty/black the moment you orbit off the exact recovered viewpoint β€” leave at 1.0 if you plan to use Project, raise it only for inspecting undressed blockout shapes.
controlsoptATLAS_VIEWPORT_LINKConnect an AtlasViewportControls node here to move all buttons/panels off this node (perspective-only, freely resizable). Carries no real data β€” Python ignores it; the link only lets the two nodes' frontend JS find each other.
shot_camoptATLAS_SHOT_CAMOptional project/shot camera format (AtlasDefineShotCam) β€” conforms the render resolution/aspect and viewing-camera FOV to this format instead of auto-following source_image's own aspect. A direct wire here wins over one attached to `solve` by AtlasMergeGeometry. Never affects how the source photo is projected onto geometry.
output_profileoptATLAS_OUTPUT_PROFILEOptional OCIO-style output/profile metadata from AtlasViewportControls. Browser preview remains display-inferred/proxy; final fidelity belongs to OCIO Write, Nuke, Maya, or Resolve.
debug_matteoptMASK🎭 Optional debug isolate (e.g. a layer's SAM3 mask, source-image space): under πŸ“½ Project the viewport dims everything whose primary-camera projection falls OUTSIDE this matte (🎭 toolbar toggle + dim slider; dim 0 = hard cull). Display-only β€” never affects exports, geometry, or the projection itself.
patch_maskoptMASKSource-image-space created_islands mask from AtlasPlanarHolePatch. Under 🎨 Layers the generated patches receive their own magenta identity color. Render Proxy Passes reprojects the same pixels from the current moved camera and returns patch_render_mask for inpainting.
drawn_fill_pxoptINT960–512Fill drawn surfaces (✏️ Draw / β–£ Box / ● Sphere) by smearing the surrounding plate colours across their footprint, the same deterministic edge-extend the clean-plate path uses. They stand where the camera never saw, so the raw plate would paint them with whatever occluded them. 0 = off (leave the raw projection and route `drawn_mask` to a real inpaint instead).
clean_plateoptIMAGEOptional clean plate β€” the BACKGROUND layer of a layered composite: the projection_backdrop plane and any solve_b geometry merged in by AtlasMergeGeometry project THIS image, so tears in the foreground reveal the clean background through the same registered projector. Drawn/wand fills patch the foreground's own tears and keep the drawn_fill_px smear.
auto_presetoptCOMBOoffAuthor this camera-move preset and BAKE it when the node executes, instead of clicking πŸŽ₯ Camera Path and ⏺ Bake Full Path by hand. NEEDS A BROWSER with this graph open β€” the bake renders in Three.js, so a headless queue produces no frames however this is set. Baking re-queues the prompt, so the frontend fingerprints (solve, preset, frames, resolution) and re-bakes only when one changes; without that guard the re-queue would bake forever.
auto_framesoptINT00–2048Frame count for auto_preset. 0 leaves the preset's own length (100) alone. LTX wants frames % 8 == 1 β€” 81, 97, 121 β€” and a count that violates it bakes fine here and is refused downstream.

Outputs (15)

NameTypeDescription
shadedIMAGEβ€”
depthIMAGEβ€”
normalIMAGEβ€”
maskIMAGEβ€”
path_framesIMAGEβ€”
camera_pathATLAS_CAMERA_PATHβ€”
patch_azimuth_viewSTRINGβ€”
patch_elevation_viewSTRINGβ€”
patch_distanceSTRINGβ€”
patch_promptSTRINGβ€”
patch_exactSTRINGβ€”
patch_render_maskMASKβ€”
solveATLAS_SOLVEβ€”
drawn_maskMASKβ€”
draw_reportSTRINGβ€”