Nodes/Atlas Camera/Atlas MoGe Normals 🧭
ComfyUI Node

Atlas MoGe Normals 🧭

Keep your good depth, upgrade the normals

By mikejamesvfxΒ·Created 2 months agoΒ·Updated a day agoΒ· 1
Atlas MoGe Normals 🧭
  • depth
  • image
  • solve
  • depth
  • report
β—„normal_modelRuicheng/moge-2-vitl-normalβ–Ί
β—„deviceautoβ–Ί
β—„resolution_level9β–Ί
β—„max_side0β–Ί
β—„checkpoint_pathβ–Ί

Depth models and normal models are not the same animal, and the atlas-camera pack refuses to pretend otherwise. MoGe is the monocular-geometry specialist from Microsoft Research - it predicts a point map and clean, physically-plausible normals from a single image. But its depth behaviour has a blind spot: it masks sky and runs away on wide exteriors. Atlas MoGe Normals exists to let you have both - MoGe's normals, and a depth model of your choice for the depth. It's the 🧭 in Atlas/03 · Depth.

The node's whole reason to exist is in its docstring: it runs a MoGe *-normal model purely for the per-pixel normals, discards MoGe's own depth, and attaches those normals to a copy of whatever ATLAS_DEPTH_MAP you feed it. The clean-plate layer downstream then uses them as its world-normal relight map exactly as if MoGe had been the depth model - so you keep Depth Anything V2 or DA3's far-field depth (which behaves on exteriors where MoGe's runs away) and still get MoGe's cleaner predicted normals for the lighting.

How it works

Wire it between AtlasDepthMap (any model) and AtlasCleanPlateLayer. It takes the input depth plus the original image, runs MoGe's normal prediction, resizes the normals to the input depth's resolution, and hands back the same ATLAS_DEPTH_MAP - with normals attached. The solve is optional but does real work: feeding the solved focal into MoGe as fov_x gives better geometry. The normals get aligned to the recovered world frame downstream regardless, so it's a quality knob, not a correctness requirement.

Inputs and outputs

Required inputs:

  • depth - an ATLAS_DEPTH_MAP from any depth model.
  • image - the original photograph.

Optional inputs:

  • normal_model - which MoGe *-normal checkpoint: vitl (best quality), vitb (lighter GPU), or vits (35M, CPU/MPS-viable). Auto-downloads from HuggingFace.
  • device - auto/cuda/mps/cpu.
  • solve - optional solved focal for fov_x.
  • resolution_level - MoGe's token-budget dial, 0–9; 9 is the default and full detail.
  • max_side - cap the longer edge before inference (0 = off). This only buys VRAM and time: normals come back at source size either way, and because normals are lower-frequency than depth, a downscaled pass costs less quality than a downscaled depth pass.
  • checkpoint_path - a local MoGe model.pt instead of a HF download. Note the tooltip's warning: this is not ComfyUI core's .safetensors format - different container.

Outputs: depth (with normals attached) and report.

Installing it

Requires the [moge] extra (MoGe is GitHub-only):

cd <ComfyUI>/custom_nodes
git clone https://github.com/mikejamesvfx/atlas-camera.git
<ComfyUI>/venv/Scripts/python.exe -m pip install ".[moge]"

MoGe is MIT-licensed (the repo dual-licenses MIT and Apache 2.0), so no licensing caveat here. Into an existing ComfyUI venv, the pack's INSTALL.md recommends the --no-deps route - MoGe's own dependency list pulls gradio/matplotlib/pipeline you don't want.

Common issues

MoGe's sky masking is the thing to remember: it's great on enclosed/interior shots, poor outdoors. That's precisely why this node decouples normals from depth - if you let MoGe be your depth model on an exterior, the sky gets holes. Let it do normals, keep DA-V2-Metric-Outdoor for depth, and the two cover each other's weaknesses. If the normals come back at the wrong resolution, don't panic - resize happens against the input depth map, so feed the same depth map you're using downstream.

CategoryAtlas/03 Β· Depth

Inputs (8)

NameTypeDefaultDescription
depthATLAS_DEPTH_MAPβ€”
imageIMAGEβ€”
normal_modeloptCOMBORuicheng/moge-2-vitl-normalMoGe *-normal checkpoint. vitl=best quality, vitb=lighter GPU, vits=35M CPU/MPS-viable (non-CUDA). Auto-downloads from HuggingFace.
deviceoptCOMBOauto4 options: auto, cuda, mps, cpu
solveoptATLAS_SOLVEOptional β€” feeds the SOLVED focal to MoGe (fov_x) for better geometry; the normals are aligned to the recovered world frame downstream regardless, so this is a minor quality knob.
resolution_leveloptINT90–9MoGe's token-budget dial; 9 is its default and full detail. Lower = faster, coarser normals.
max_sideoptINT00–16384Cap the longer edge before inference (0 = off). Normals come back at SOURCE size either way β€” this only buys VRAM and time. Cheap here: normals are lower-frequency than depth, so a downscaled normal pass costs less quality than a downscaled depth pass.
checkpoint_pathoptSTRINGLocal MoGe `model.pt` instead of a HuggingFace download. NOT ComfyUI core's *.safetensors β€” different container.

Outputs (2)

NameTypeDescription
depthATLAS_DEPTH_MAPβ€”
reportSTRINGβ€”