Depth To Normals
Turn a depth map into a normal map
- depth
- normals
Depth maps and normal maps look similar - both are grayscale-ish images that encode 3D surface information - but they carry different information and get used differently downstream. A depth map tells you how far away each pixel is; a normal map tells you which direction each surface is facing. This node converts one into the other, which is handy since depth estimators (Depth Anything, MiDaS, and friends) are everywhere in this ecosystem while dedicated normal estimators are comparatively rare.
How the conversion actually works
Surface orientation can be derived mathematically from depth: if you know how depth changes as you move across the image (the gradient), you can work out which way the surface at that point must be tilted to produce that change. That's the core trick - Depth To Normals reads the local gradient of your depth map and encodes the resulting direction as an RGB normal map, the standard way normal maps have been represented in 3D graphics for decades.
Inputs and outputs that matter
depth- your depth map, as an image.scale(0.001–1000, default 1) - how strongly the depth gradient translates into surface tilt. Push it up and flat surfaces start reading as bumpy; too low and real surface detail flattens out. This is the one setting worth actually tuning per-image - depth maps vary a lot in how much their value range corresponds to real depth variation.output_mode-Standard,BAE, orMiDaS. These are different color-space conventions for encoding a normal map - which axis maps to which color channel, and which way is "up" - and they matter because different tools expect different conventions. BAE is the convention the standard ControlNet normal-map preprocessor uses, so if you're feeding this into a ControlNet normal conditioning, that's usually the one to pick.
Output: normals, an IMAGE.
Installing it
Search ComfyUI Image Filters in ComfyUI Manager, or clone it manually:
cd ComfyUI/custom_nodes
git clone https://github.com/spacepxl/ComfyUI-Image-Filters
Restart afterward. No model download for this node specifically - it's a gradient calculation on whatever depth map you feed it, not a neural estimator itself, so it's fast and has no VRAM cost worth mentioning. The pack-wide dependency to watch is opencv: if custom nodes fail to import after installing, it's almost always a version clash with opencv from another pack. The repo's import_error_install.bat fixes it by reinstalling all four opencv variants in matching versions; by hand, uninstall the opencv-* packages and keep only opencv-contrib-python.
Where people get burned
The output quality is entirely a function of your input depth map's quality - this node can't invent geometric detail that isn't in the depth data. A blurry or low-contrast depth map produces a mushy, low-detail normal map no matter what you do with scale. If your normal map looks flat, check the depth map first (Remap Range from this same pack is a reasonable fix if the depth map's contrast is compressed).
The other trap is output_mode mismatches downstream. If you generate a normal map here in Standard mode but feed it into a workflow or ControlNet expecting BAE convention, the lighting/relighting result will look subtly (or not-so-subtly) wrong - surfaces will seem to face the wrong way. If two tools disagree on convention, the pack's Convert Normals node exists specifically to translate between them rather than regenerating the map.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| depth | IMAGE | — | |
| scale | FLOAT | 1.0000.001–1000 | — |
| output_mode | COMBO | 3 options: Standard, BAE, MiDaS |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| normals | IMAGE | — |