Nodes/comfyui-dap/DAP Normal Map
ComfyUI Node

DAP Normal Map

Normals for panoramas, without the seams

By maxious·Created 8 months ago·Updated 8 months ago· 1
DAP Normal Map
  • depth
  • mask
  • normal
normal_standardComfyUI
downsample1

DAP Normal Map turns a DAP depth map into a normal map - surface orientation instead of distance - and it does it in a way that's embarrassingly rare for this ecosystem: it's actually aware that the image is a panorama.

The naive way to derive normals from depth is to take 2D pixel gradients. Slope the pixels, shade accordingly, done. But equirectangular projection distorts space - a straight wall curves, the seam wraps, and the poles squeeze - so 2D gradients give you a normal map full of phantom curvature and a seam right down the middle. This node skips that entirely. It unprojects the depth back onto a sphere (same math as DAP Panoramic Mesh), computes each pixel's normal in true 3D space from its neighbors, and only then encodes the result back into an RGB image. The normals describe the actual geometry, not the projection artifact.

Inputs

  • depth - required; the IMAGE output of DAP Inference. It doesn't have to come from DAP specifically, but feeding it a panorama depth map from any source is where it shines.
  • normal_standard - ComfyUI (default) or DAP. This is the one setting worth understanding. ComfyUI uses the standard RGB convention - the same one ControlNet's normal preprocessors output and that most pipelines expect. DAP switches to the original research format (axis-flipped and channel-swapped, matching the official DAP repo's own depth2normal.py). Keep ComfyUI unless you're replicating the paper's pipeline; a normal ControlNet will read the ComfyUI format correctly.
  • downsample - default 1. Computes normals on a reduced grid for speed, then upsamples back to full resolution. Since the output size stays the same, this is a cheap performance lever rather than a quality tradeoff you'll notice much.
  • mask (optional) - wire in the mask from DAP Inference and it zeroes out normals in the invalid boundary/sky areas, so junk doesn't pollute the result.

Output and wiring

One normal IMAGE out. Standard use: drop it into a normal ControlNet as the conditioning input, where the whole "sphere-aware" thing pays off - a ControlNet trying to reconstruct 3D from a broken seam is going to have a bad time, and this map gives it clean, consistent geometry to work from. You can also just preview it and enjoy the relief effect.

Install and gotchas

Same pack, same drill: install via Manager ("comfyui-dap") or git clone --recursive, then pip install -r requirements.txt in the ComfyUI venv - this node pulls in the same heavy list (open3d, utils3d, xformers, …) as the rest.

Where people trip up:

  • Normals look "wrong" when previewed - RGB normal maps are meant to be consumed, not eyeballed; a purple-ish wash is normal (the neutral vector points out of the screen). Judge it by what the ControlNet produces.
  • Mismatched convention - if you switch normal_standard to DAP and feed it to a normal ControlNet trained on standard RGB, results will look subtly broken. Only use DAP when you know the downstream consumer speaks that dialect.
  • Downsample low-res artifacts - at downsample=4+, the upsampled normals get soft. Fine for speed checks; bump back down for finals.

It's a small node with one genuinely thoughtful idea in it. If you're doing anything normal-map-related with 360° imagery, it's the difference between normals that lie about the geometry and normals that respect it.

CategoryDAP/Geometry

Inputs (4)

NameTypeDefaultDescription
depthIMAGE
normal_standardCOMBOComfyUI2 options: ComfyUI, DAP
downsampleINT11–8
maskoptMASK

Outputs (1)

NameTypeDescription
normalIMAGE