Atlas Plane Mattes π§©
Turn fitted planes into projection layers β pixel by pixel
- solve
- depth
- solve
- report
There's a gap between "a wall exists" and "this wall has pixels." A fitted plane knows its pose and its inlier count, but nothing about which pixels belong to it - so project the plate through a bare plane and it receives everything behind it too, smearing the photo across a few flat rectangles instead of cropping it to the objects those rectangles stand for. AtlasPlaneMattes closes that gap. It's the node that decides, per pixel, which plane owns it, and hands each surviving plane its own layer. Run it and the scene stops being rectangles and starts being a matte painting you can move around.
How it works
The load-bearing property here is exclusivity. The node back-projects the depth map into world space through the recovered camera, then assigns each pixel to the nearest plane that can explain it - nearest-wins, with an explicit unassigned label. Why so strict about exclusivity? Because two planes both claiming a pixel put the same photograph on two surfaces at different depths, which an orbit shows as a doubled, sliding ghost. Contested pixels get one owner, and the report tells you how many there were.
Each surviving plane becomes a ProjectionSource that shares the primary camera, carries that plane as its own geometry, and declares projection_mode: clean_plate - it has no image of its own, so it projects the primary plate. That's the mechanism behind every per-building band and depth-split clean plate in the Atlas demos.
The inputs that matter
solve and depth (an ATLAS_DEPTH_MAP) are both required. The two optional knobs:
tolerance_m(default 0) - how far off a plane a point may sit and still count as on it. 0 = AUTO, which scales the tolerance with the plane's depth. The tooltip is worth quoting: a fixed metric slab is either too tight for a far wall or too loose for a near one. Leave it at 0 until you have a reason not to.min_coverage_px(default 64) - a plane explaining fewer pixels than this gets no layer at all. The reasoning is sound: a layer with a nearly empty matte mattes nothing and still costs the editor a row.
Outputs are solve (with the new layers attached) and report (STRING) - how many layers were made from how many planes, what fraction of pixels got assigned, and whether any were skipped for coverage.
Installing
Pack install, and here's where it gets slightly heavier than the geometry nodes above:
cd <ComfyUI>/custom_nodes
git clone https://github.com/mikejamesvfx/atlas-camera.git
Restart. The node itself is pure NumPy, but the depth input has to come from somewhere - and depth comes from the [neural] tier. That means the Depth Anything / GeoCalib extras need to be present in ComfyUI's Python:
<ComfyUI>/python -m pip install "git+https://github.com/cvg/GeoCalib.git" transformers
Watch the kornia version - the pack pins kornia<0.8.3 because 0.8.3 breaks ComfyUI-LTXVideo's import. If you've already broken it, pip install "kornia==0.8.2" repairs it.
Where people get burned
- "SKIPPED - this solve carries no plane primitives" - you ran it before deriving any planes. It says it in the report: run
AtlasDeriveWalls(or another derive node) upstream first. - "SKIPPED - solve has no usable focal" - the solve didn't recover usable intrinsics; a valid camera solve upstream fixes it.
- A warning that most pixels are contested - your planes are duplicates of each other. Nearest-wins resolved them, but a scene where most pixels are in range of more than one plane has a geometry problem, not a matte problem.
Placement matters: run it after the plane producer and before anything that consumes layers - the occlusion graph, the viewport, or AtlasExportScenePackage, which writes one matte file per layer. It's the quiet node that makes the whole layered projection stack actually work.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| solve | ATLAS_SOLVE | β | |
| depth | ATLAS_DEPTH_MAP | β | |
| tolerance_mopt | FLOAT | 0.000β100 | How far off a plane a point may sit and still count as on it. 0 = AUTO, which scales the tolerance with the plane's DEPTH β a fixed metric slab is either too tight for a far wall or too loose for a near one. |
| min_coverage_pxopt | INT | 640β1000000 | A plane explaining fewer pixels than this gets no layer. A layer with a nearly empty matte mattes nothing and still costs the editor a row. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| solve | ATLAS_SOLVE | β |
| report | STRING | β |