DAViD Normal to Lighting
Relight anything with a normal map and one line of text — no diffusion, no VRAM
- normal_map
- shaded_image
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 thenormal_mapoutput of this pack'sDAViDMultiTasknode 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.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| normal_map | IMAGE | — | |
| light_direction | STRING | 0.5,0.5,1.0 | — |
| ambient_strength | FLOAT | 0.300–1 | — |
| diffuse_strength | FLOAT | 0.700–2 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| shaded_image | IMAGE | — |