Nodes/Atlas Camera/Atlas Solve Patch Views ⌖
ComfyUI Node

Atlas Solve Patch Views ⌖

Atlas Solve Patch Views ⌖ — which camera angle actually sees the hole?

By mikejamesvfx·Created 2 months ago·Updated a day ago· 1
Atlas Solve Patch Views ⌖
  • solve
  • hole_mask
  • exclude_mask
  • patch_view_override
  • patch_prompt
  • view_plan
  • report
source_azimuth_viewfront view
source_elevation_vieweye-level shot
flip_azimuthfalse
search_distancesfalse
resolution384
min_visible_pixels32
max_views3
max_hole_fraction0.350
normal_tolerance_deg30
max_plane_error_m0.45

AtlasSolvePatchViews answers a deceptively practical question for the patch-repair pipeline: if you're going to photograph or render the missing bit of the scene, from where? You know the hole exists, you know its pixels, and you know the geometry around it. This node rasterizes a grid of candidate camera views (32 by default, 96 if you turn on search_distances) and ranks them by how much of the hole is actually visible from each - then hands you the winner as a plain-text view description.

That "view description" format is the quietly important part. The output isn't a matrix or a latent - it's a patch_view_override string in human language like "front-right quarter view, eye-level shot", exactly the vocabulary a shot list or a photographer understands. There's also a patch_prompt (ready to feed an image model or an agent) and a view_plan string carrying the top-N ranked views for multi-angle or agent use.

How it works

For each candidate view it rasterizes the projection scene - a pure-numpy renderer, O(faces × pixels) - and counts how many hole pixels that view actually sees. Below min_visible_pixels an island counts as unseen; a few grazing pixels is not a patch. Two of the tooltips deserve quoting because they're the kind of hard-won detail you only get from shipping:

  • max_hole_fraction defaults to 0.35, and the tooltip explains why it is not the repair module's 0.04: that's tuned for small planar patches, and at 0.04 a normal tear (43% of frame, measured) fits nothing, so every angle scores zero - which reads as "the model can't see it" when nothing was ever fitted to look at.
  • search_distances - "Distance changes visibility far less than angle does, and every candidate is a rasterize," so it stays off by default and triples your candidate count to 96 when on.

source_azimuth_view and source_elevation_view let you bias the search toward a known-good shooting position, and flip_azimuth mirrors it. resolution is the expensive knob - it runs once per candidate, so keep it moderate (384 default) until the final pass.

Where it fits

Wire its output strings into your patch pipeline - patch_view_override feeds the shoot list or a view-generating model, and the geometry-aware exclude_mask (typically sky already carried by a dome) keeps excluded pixels from distorting the ranking. The README's patch workflows use this to register photographed hole patches: you go shoot the winning view, then register the result back into the project.

Install

Core node, no dependencies:

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

Restart or use ComfyUI Manager ("atlas-camera"). It's in Atlas/06 · Patch & Repair. If every view comes back scoring zero, check max_hole_fraction before you blame the rasterizer.

CategoryAtlas/06 · Patch & Repair

Inputs (13)

NameTypeDefaultDescription
solveATLAS_SOLVE
hole_maskMASK
source_azimuth_viewoptCOMBOfront view8 options: front view, front-right quarter view, right side view, back-right quarter view, back view, back-left quarter view, +2
source_elevation_viewoptCOMBOeye-level shot4 options: low-angle shot, eye-level shot, elevated shot, high-angle shot
flip_azimuthoptBOOLEANfalse
search_distancesoptBOOLEANfalseAlso try close-up/wide (96 candidates instead of 32). Distance changes visibility far less than angle does, and every candidate is a rasterize.
resolutionoptINT384128–1536Rasterize size per candidate. Runs ONCE PER CANDIDATE VIEW and the rasterizer is pure-numpy O(faces x pixels) — this is the expensive knob.
min_visible_pixelsoptINT321–100000Below this an island counts as unseen from that view. A few grazing pixels is not a patch.
max_viewsoptINT31–32How many ranked views go into view_plan. The override output always carries the single best; the plan is for multi-angle and agent use.
exclude_maskoptMASKHole pixels to ignore — typically sky already carried by a dome. Excluded pixels leave the ranking entirely.
max_hole_fractionoptFLOAT0.3500.001–1Largest island, as a fraction of frame, that a fill plane may be fitted to. NOT the repair module's 0.04 default: that is tuned for small planar patches, and at 0.04 a normal tear (43% of frame, measured) fits NOTHING and every angle scores zero — which reads as 'Qwen cannot see it' when nothing was ever fitted to look at.
normal_tolerance_degoptFLOAT301–89How much the hole's surrounding normals may disagree before it is judged non-planar.
max_plane_error_moptFLOAT0.450.001–100Plane-fit residual cap, metres. Only meaningful when the solve's metric scale is trusted.

Outputs (4)

NameTypeDescription
patch_view_overrideSTRING
patch_promptSTRING
view_planSTRING
reportSTRING