Nodes/ComfyUI-DAViD/DAViD Normal to Lighting
ComfyUI Node

DAViD Normal to Lighting

Relight anything with a normal map and one line of text — no diffusion, no VRAM

By AIWarper·Created about a year ago·Updated about a year ago· 6
DAViD Normal to Lighting
  • normal_map
  • shaded_image
light_direction0.5,0.5,1.0
ambient_strength0.30
diffuse_strength0.70

The cheap relight

Take a surface-normal map, point a virtual light at it, and out pops a shaded version of the scene. That's DAViDNormalToLight: no diffusion model, no VRAM spike, instant. Set expectations before you get excited though - this is Lambertian shading in grayscale, not a color relight. It won't re-emit the subject's colors or cast believable shadows onto a new background. What it will do, in milliseconds, is let you preview light directions and produce a clean shading pass.

How it works

A normal map stores each pixel's surface orientation as an (x, y, z) vector. The node un-maps the visualization format back to real normal space (* 2 - 1), re-normalizes every vector, parses your light_direction string into a light vector, then computes the classic Lambertian equation:

shading = ambient_strength + diffuse_strength * max(0, dot(normal, light))

Surfaces facing the light go bright, surfaces facing away go dark, and the ambient term keeps the shadow side from hitting pure black. It's the same math a rasterizer does per pixel, minus the renderer.

The inputs that matter

  • normal_map - feed it the normal_map output of this pack's DAViDMultiTask node and the formats line up by design. You can also feed normals from other sources, but DAViD's own output is what it's tuned for.
  • light_direction - a string like "0.5,0.5,1.0" (default): comma-separated x, y, z, auto-normalized internally. "1,0,0" is hard left, "0,0,1" straight at the camera. Moving this around is the entire fun of the node.
  • ambient_strength (0–1) - the floor light so the unlit side isn't pure black. Default 0.3.
  • diffuse_strength (0–2) - how much punch the directional term has. Crank it for drama, drop it for flat.

One output: shaded_image, a grayscale IMAGE at your input's resolution and batch size.

Where it fits, and where it doesn't

Reach for it to sanity-check a normal map (a wrong map shows up immediately as garbage shading), to experiment with light angles before committing to a real relight, or to generate a shading overlay to composite with. The classic pairing: DAViDMultiTask → DAViDNormalToLight → composite the shaded pass under or over your subject for instant lighting variation.

Don't reach for it when you want believable color relighting - a lit, recolored portrait with proper highlights and contact shadows. That's IC-Light or a modern instruction editor like Qwen Image Edit, which re-emit the whole frame. Those cost a generation step; this costs nothing. It's the free preview that runs before you spend a second of GPU time on the real thing.

Same pack, same install

Another node in AIWarper's ComfyUI-DAViD pack, so it shares the install:

cd ComfyUI/custom_nodes
git clone https://github.com/AIWarper/ComfyUI-DAViD
pip install onnxruntime-gpu

It's pure math on the input tensor, so it needs no model file of its own - but to have a normal map to feed it you'll want the pack's multi-task model in ComfyUI/models/david (download the multitask-vitl16_384.onnx per the pack README). Restart ComfyUI and find it under DAViD/Utils.

Troubleshooting

If the shading looks wrong (subject lit from a weird side, or a flat wash), check two things: the normal map you fed it must be in the [0,1] visualization format, and your light_direction string needs exactly three comma-separated numbers - a typo like "0.5 0.5 1.0" silently falls back to the default direction. And remember the grayscale thing: if you were expecting color, you grabbed the wrong tool.

CategoryDAViD/Utils

Inputs (4)

NameTypeDefaultDescription
normal_mapIMAGE
light_directionSTRING0.5,0.5,1.0
ambient_strengthFLOAT0.300–1
diffuse_strengthFLOAT0.700–2

Outputs (1)

NameTypeDescription
shaded_imageIMAGE