Atlas Export Relief Mesh (OBJ) π»
The depth-following mesh as an OBJ or GLB, projection baked into the UVs
- solve
- image
- project
- obj_path
- glb_path
- preview_solve
- report
AtlasExportReliefMesh is where the 2.5D projection stops being a viewport trick and becomes an actual geometry file you can hand to another tool: it writes the depth-following relief mesh as an OBJ or GLB (or both), with the plate's projection baked into the UVs. This is the "give the projection to anyone" export - Blender, Maya, game engines, a texture bake - and it's also the mesh that feeds the Nuke and Maya exporters when you want real derived geometry in those scenes instead of a flat card.
The "relief" part is the whole idea: instead of a flat plane, the mesh follows the monocular depth estimate (fed by the solved focal length, which matters - depth seen through the wrong lens is depth in the wrong place). From the recovered camera's viewpoint the plate reassembles exactly; from anywhere else you get parallax, which is precisely the illusion you're buying.
How it works
Give it the solve, the image (the plate to project), and an output_dir. It writes obj_path and glb_path (with format defaulting to both). The critical default is use_solve_mesh - on, it exports the relief mesh already on the solve (from AtlasInput or the derive nodes) so all of its edge tuning carries over. Turn it off to re-derive the mesh here instead, which unlocks the re-derive-only tuning inputs (max_edge_factor, normal_edge_deg).
A few genuinely useful options:
fill_interior_holes(default off) - an export-only fan-fill of small interior tear holes so the mesh retopologizes and renders cleanly, scoped bymax_hole_edgesand thefill_depth_near_m/fill_depth_far_mband bounds. The live viewport projection mesh is never touched.retopo_method- export-only retopology (off,quad,decimate,voxel_remesh) with a vertex budget, for when the derived mesh is too messy to hand to a real DCC.grid_long_edge(default 128) anddepth_edge_rel- mesh density and the relative depth jump that tears the mesh.
Outputs: obj_path, glb_path, a preview_solve, and report.
Install and gotchas
Part of the pack - ComfyUI Manager β search atlas-camera, or git clone https://github.com/mikejamesvfx/atlas-camera.git into custom_nodes, restart. The exporter itself is lightweight, but the mesh comes from depth: the default Depth Anything V2 backend is transformers-only (no extra install) - the heavier neural/GeoCalib path is only needed if you're re-deriving without an existing solve mesh.
Gotchas: output_dir is relative to ComfyUI's working directory, and the Nuke exporter resolves your obj_path to absolute precisely so the generated scripts stay portable - keep that convention in mind. If the exported mesh comes out "combed" or shredded on deep or interior scenes, that's the world-space edge tear threshold (max_edge_factor) tripping on grazing surfaces; raise it to 40β80, or better, tune it upstream on AtlasInput and let use_solve_mesh carry it through. And remember the OBJ is projected but not textured-on-disk - the plate rides in the UVs and the projection is applied live in the consuming tool. That's the intended pipeline, not a bug.
Inputs (21)
| Name | Type | Default | Description |
|---|---|---|---|
| solve | ATLAS_SOLVE | β | |
| image | IMAGE | β | |
| output_dir | STRING | atlas_exports | β |
| grid_long_edgeopt | INT | 12816β4096 | Mesh density: grid columns along the longest image edge. |
| depth_edge_relopt | FLOAT | 0.500.05β5 | Relative depth jump that tears the mesh (silhouette holes). |
| depth_modelopt | COMBO | depth-anything/Depth-Anything-V2-Metric-Outdoor-Large-hf | 10 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 |
| deviceopt | COMBO | auto | 4 options: auto, cuda, mps, cpu |
| formatopt | COMBO | both | 3 options: both, obj, glb |
| use_solve_meshopt | BOOLEAN | true | Export the relief mesh ALREADY on the solve (from AtlasDeriveReliefMesh / AtlasInput) so ALL its edge tuning β max_edge_factor, normal_edge_deg, the band near-clip, sky_heuristic β carries into the OBJ/GLB exactly, with no widget to re-set. Turn OFF to re-derive from depth at this node's own grid/thresholds below (e.g. to export a HIGHER-resolution mesh than the viewport). Auto-falls-back to re-derive when the solve carries no relief mesh. |
| max_edge_factoropt | FLOAT | 122β200 | Re-derive only (use_solve_mesh off): world-space edge tear threshold. Raise to 40-80 on deep/interior scenes to stop combs. |
| normal_edge_degopt | FLOAT | 00β180 | Re-derive only: 0 = off; tears on surface-normal bend (real creases) while leaving smooth grazing surfaces intact. |
| fill_interior_holesopt | BOOLEAN | false | EXPORT-ONLY (the live viewport projection mesh is never touched). Fan-fill small interior tear holes in the OBJ/GLB so it retopologizes and booleans cleanly in a DCC. Fills ONLY interior enclosed boundary loops β never the outer silhouette/frame boundary β by re-using each hole's existing boundary vertices, so projection-baked UVs stay valid. Off by default: a torn silhouette is the DMP-correct look. |
| max_hole_edgesopt | INT | 643β4096 | A boundary loop is filled only if its edge count is below this. The outer frame is ~the grid perimeter (e.g. ~512 at grid 128), interior tears are ~4-30, so 64 separates them by construction. |
| fill_depth_near_mopt | FLOAT | 0.00β10000 | Band-box spatial scope: only fill loops whose EVERY boundary vertex's forward depth (recovered-camera view space, same axis as AtlasBoundedBand's cutoff) lies within [near, far] metres. Transcribe off a bounded band's near and cutoff_m. 0 = off (edge-count-only mode; the single largest loop is always left open). |
| fill_depth_far_mopt | FLOAT | 0.00β100000 | Band-box far bound (the cutoff). 0 = off (see fill_depth_near_m). |
| retopo_methodopt | COMBO | off | EXPORT-ONLY retopology pass on the OBJ/GLB (the live viewport projection mesh is never touched). off = no change (default, so every saved workflow keeps working). quad = pyinstantmeshes orientation-field quad remesh (cleanest DCC handoff; needs the pyinstantmeshes package). decimate = quadric decimation via fast-simplification (fewer faces, same topology class). smooth = trimesh Taubin relax (topology-preserving, UVs kept). quad/decimate change the vertex count so projection-baked UVs are REGENERATED from the recovered camera (pure numpy) and the retopologized mesh stays textured. Runs AFTER any interior hole-fill. |
| retopo_target_vertex_countopt | INT | 20004β2000000 | Target vertex count for quad / target face count for decimate (decimate targets ~2x this in faces). Ignored by smooth. |
| retopo_smooth_iterationsopt | INT | 00β100 | quad: Instant Meshes post-smooth iterations. smooth: Taubin relax iterations (the actual smoothing strength). decimate: ignored. |
| retopo_crease_angleopt | FLOAT | 300β180 | quad only: crease angle (deg) below which adjacent faces are treated as one smooth surface in the orientation field. |
| retopo_pure_quadopt | BOOLEAN | false | quad only: force a pure-quad output (no triangles). False allows quad-dominant (triangles where the field can't place a quad). |
| projectopt | ATLAS_PROJECT | Optional delivery project from AtlasProject β routes this export into the project tree's geo/ lane and supersedes output_dir. |
Outputs (4)
| Name | Type | Description |
|---|---|---|
| obj_path | STRING | β |
| glb_path | STRING | β |
| preview_solve | ATLAS_SOLVE | β |
| report | STRING | β |