Nodes/Atlas Camera/Atlas Occlusion Mask πŸ•³
ComfyUI Node

Atlas Occlusion Mask πŸ•³

Know exactly where the primary camera is lying to you

By mikejamesvfxΒ·Created 3 months agoΒ·Updated a day agoΒ· 1
Atlas Occlusion Mask πŸ•³
  • solve
  • target_image
  • primary_depth
  • occlusion_mask
  • coverage_mask
β—„patch_azimuth_viewfront-right quarter viewβ–Ί
β—„patch_elevation_vieweye-level shotβ–Ί
β—„patch_distancemedium shotβ–Ί
β—„source_azimuth_viewfront viewβ–Ί
β—„source_elevation_vieweye-level shotβ–Ί
β—„flip_azimuthfalseβ–Ί
β—„depth_modeldepth-anything/Depth-Anything-V2-Metric-Outdoor-Large-hfβ–Ί
β—„deviceautoβ–Ί
β—„angle_threshold90β–Ί
β—„dilate_px0β–Ί
β—„soft_edge_px0β–Ί
β—„power1.0β–Ί
β—„occlusion_modesimpleβ–Ί
β—„depth_bias0.05β–Ί
β—„patch_view_overrideβ€”β–Ί
β—„exact_view_overrideβ€”β–Ί

The atlas-camera patch pipeline works like this: a novel view (a patch, a LoRA-generated repair) shows you geometry that the primary photo either can't see or only sees at a grazing angle. Before you composite that patch in, you need a mask of exactly where the primary is missing that information. Atlas Occlusion Mask is that mask. White means "the primary camera has no valid coverage here, a patch should fill it"; black means "the primary already has it, head-on." It's the πŸ•³ in Atlas/04 Β· Masks.

It's the phase-gate of the patch path: no mask, no idea whether you're genuinely adding information or smearing a patch over pixels the primary already owns.

How it works

The node places the target/patch camera identically to how AtlasAddPatchView will place it later - same named-view widgets, same orbit construction - so the mask lines up with whatever patch geometry that node derives from the same image. Then it projects the primary's coverage onto the scene and marks the failures:

  • simple mode (default) - Phase-1 tests only: frustum, behind-camera, and out-of-frame failures, plus a facing-angle gate (angle_threshold, default 90Β° = only true "can't see it" failures; lower it and surfaces too grazing to the primary also get masked).
  • depth_shadow mode - adds the real matte-painting trick: a camera-as-light shadow test. Surfaces hidden behind nearer geometry from the primary's view get masked, using primary_depth as the shadow map. This is the true "MPTK-style" test, and it needs primary_depth wired - the shared AtlasDepthMap run on the primary photo. Without it, the mode falls back to simple and the report says so.

The patch_* and source_* dropdowns exist to keep the mask aligned with the LoRA that generated the target image - they describe which azimuth/elevation/distance the target was generated at and which view the source photo already is. The contract is blunt: they must match the values you'll use in AtlasAddPatchView, or the mask and the patch drift. If you'd rather not hand-sync, patch_view_override / exact_view_override accept the snapped or raw orbit strings from AtlasBlockoutViewport.

Inputs and outputs

Required: solve and target_image. Optional: the view dropdowns above, flip_azimuth, depth_model (default DA-V2-Metric-Outdoor), device, angle_threshold, dilate_px (expand the white region), soft_edge_px (feather it), power (gamma remap after blur), occlusion_mode, primary_depth, depth_bias (relative depth tolerance before a point counts as shadowed), and the two view overrides.

Outputs: occlusion_mask (white = missing) and coverage_mask (the inverse view - white = valid primary coverage).

Installing it

Core node; depth_model/primary_depth are inputs, not a dependency of this node:

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

Restart, find it in Atlas/04 Β· Masks (ComfyUI Manager: "atlas-camera").

Common issues

The alignment contract is where people burn time. The patch azimuth/elevation/distance and source view must agree between this mask and the AtlasAddPatchView wiring - if you generate the target at "front-right quarter view" but tell the mask "front view," the mask shows the wrong holes. If that's fiddly, use patch_view_override / exact_view_override from AtlasBlockoutViewport so one string drives both, and the "never-drift" contract holds. For final compositing, set dilate_px and soft_edge_px sensibly - a hair of dilation plus a feather is usually enough; the power knob >1 makes the patch contribution more solid near the feathered edge.

CategoryAtlas/04 Β· Masks

Inputs (19)

NameTypeDefaultDescription
solveATLAS_SOLVEβ€”
target_imageIMAGEβ€”
patch_azimuth_viewoptCOMBOfront-right quarter viewThe LoRA azimuth target_image was generated at β€” should match whatever you'll later pass to AtlasAddPatchView for this image.
patch_elevation_viewoptCOMBOeye-level shotThe LoRA elevation target_image was generated at.
patch_distanceoptCOMBOmedium shotThe LoRA distance target_image was generated at.
source_azimuth_viewoptCOMBOfront viewWhich view your SOURCE photo already is, in the LoRA's absolute frame. Must match the value you'll use in AtlasAddPatchView.
source_elevation_viewoptCOMBOeye-level shotElevation of the SOURCE photo in the LoRA's frame.
flip_azimuthoptBOOLEANfalseMust match the AtlasAddPatchView setting for this patch.
depth_modeloptCOMBOdepth-anything/Depth-Anything-V2-Metric-Outdoor-Large-hf10 options: depth-anything/Depth-Anything-V2-Metric-Outdoor-Large-hf, depth-anything/Depth-Anything-V2-Metric-Indoor-Large-hf, depth-anything/DA3METRIC-LARGE, depth-anything/DA3MONO-LARGE, depth-anything/DA3NESTED-GIANT-LARGE-1.1, Ruicheng/moge-2-vitl-normal, +4
deviceoptCOMBOauto4 options: auto, cuda, mps, cpu
angle_thresholdoptFLOAT900–90Facing-angle gate in degrees for the PRIMARY camera's coverage. 90 (default) = only frustum/behind-camera/out-of-frame failures are masked. Lower values also mask surfaces too grazing to the primary.
dilate_pxoptINT00–200Expand the white (missing) mask region by this many pixels.
soft_edge_pxoptINT00–200Blur the dilated mask edge by this many pixels, for compositing.
poweroptFLOAT1.00.1–8Gamma remap after blur; > 1 makes the patch contribution more solid near the feathered edge.
occlusion_modeoptCOMBOsimplesimple = Phase-1 frustum/frame/facing tests only (unchanged). depth_shadow = additionally detect surfaces hidden behind NEARER geometry from the primary's view (true MPTK camera-as-light shadow test, using primary_depth as the shadow map). Falls back to simple when primary_depth isn't connected.
primary_depthoptATLAS_DEPTH_MAPAtlasDepthMap run on the PRIMARY/source photo β€” the shadow map for depth_shadow mode. Wire the same shared AtlasDepthMap the derive nodes already use.
depth_biasoptFLOAT0.050–1depth_shadow only: relative depth tolerance before a point counts as shadowed β€” guards against monocular depth-precision false positives. 0.05 = must be 5% farther than the stored depth.
patch_view_overrideoptSTRINGOptional: wire AtlasBlockoutViewport's patch_prompt output here β€” overrides the three patch_* dropdowns with πŸ“ Extract Angle's snapped views, keeping this mask aligned with the same AtlasAddPatchView wiring. Errors loudly if unparseable.
exact_view_overrideoptSTRINGOptional: wire AtlasBlockoutViewport's patch_exact output here (πŸ“'s RAW orbit floats) β€” wins over patch_view_override and the dropdowns, flip_azimuth ignored, placing this mask's target camera IDENTICALLY to an AtlasAddPatchView driven by the same string (the shared never-drift contract). Errors loudly if unparseable.

Outputs (2)

NameTypeDescription
occlusion_maskMASKβ€”
coverage_maskMASKβ€”