๐ผ> Normal Map Lighting
Relight an image with a virtual light source, game-engine style
- diffuse_map
- normal_map
- specular_map
- mask
- IMAGE
This node borrows a technique straight out of 3D rendering and game engines: if you have a diffuse (base color) map, a normal map (surface direction per pixel), and a specular map (shininess/reflectivity per pixel), you can compute how light would actually fall across that surface from any direction - without re-rendering anything, just math on the three maps. Normal Map Lighting brings that into ComfyUI, letting you reposition a virtual light source over an image and get a relit result back.
It's the odd one out in the pack in that it assumes you already have (or can generate) a proper normal and specular map for your subject - this isn't extracting lighting info from a flat photo, it's compositing lighting from maps you supply. The author has a dedicated YouTube tutorial on the workflow, which is the better starting point than the node's parameter list alone if you're new to normal-map-based relighting.
How it works
For every pixel, it reads the surface direction from normal_map and the shininess from specular_map, then computes standard diffuse + specular lighting math against a virtual light positioned by light_yaw and light_pitch, applied on top of the base colors in diffuse_map. ambient_light adds a flat fill so surfaces facing away from the light aren't pure black. The various strength/gain parameters let you push the diffuse response, the specular highlights, and the overall output brightness independently.
The inputs and outputs that matter
diffuse_map,normal_map,specular_map(all IMAGE, required) - the three source maps. All three are required; there's no fallback for a missing one.light_yaw(default45, โ180 to 180) andlight_pitch(default30, โ90 to 90) - the light's horizontal and vertical position. These are the two you'll actually move around to "aim" the light.specular_power(default32, 1โ200) - controls how tight and bright the specular highlight is; higher values give a smaller, sharper glint (like a glossier surface), lower values spread it out softer.ambient_light(default0.5, 0โ1) - the fill light level for surfaces not facing the main light.NormalDiffuseStrength,SpecularHighlightsStrength,TotalGain- independent intensity multipliers for the diffuse response, the specular highlights, and the overall result respectively. Useful for toning down an overly dramatic effect without changing the light's position.color(default16777215, i.e. pure white as a packed RGB integer) - the light's color.mask(optional) - restrict the relighting effect to a masked region rather than the whole image.
One output: IMAGE, the relit result.
How to install it
Via ComfyUI Manager: search "yanc" or "YANC - Yet Another Node Collection," install, restart. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/ALatentPlace/ComfyUI_yanc
then restart. No extra dependencies to install - it's image-tensor math, though getting good input maps in the first place may involve a separate normal-map estimation node elsewhere in your graph if you're not sourcing them from a 3D asset.
Common issues & troubleshooting
Result looks flat or has no visible highlight. Check specular_map actually has meaningful variation - a flat gray or black specular map gives the node nothing to compute a highlight from, so a shiny-looking result depends on that map having real shininess data, not just being any IMAGE-shaped placeholder.
Everything looks blown out or the highlight is a huge white blob. Try lowering TotalGain or SpecularHighlightsStrength first before touching light position - a too-high gain or a very low specular_power (a wide, soft highlight) both commonly read as "overexposed."
Not sure where to get a normal map from a regular photo. This node consumes normal maps, it doesn't generate them - if you're starting from a flat photo rather than 3D-rendered maps, you'll need a normal-map estimation node/model earlier in the graph to produce one first; this node's job starts after that.
Inputs (12)
| Name | Type | Default | Description |
|---|---|---|---|
| diffuse_map | IMAGE | โ | |
| normal_map | IMAGE | โ | |
| specular_map | IMAGE | โ | |
| light_yaw | FLOAT | 45-180โ180 | โ |
| light_pitch | FLOAT | 30-90โ90 | โ |
| specular_power | FLOAT | 321โ200 | โ |
| ambient_light | FLOAT | 0.500โ1 | โ |
| NormalDiffuseStrength | FLOAT | 1.000โ5 | โ |
| SpecularHighlightsStrength | FLOAT | 1.000โ5 | โ |
| TotalGain | FLOAT | 1.000โ2 | โ |
| color | INT | 167772150โ16777215 | โ |
| maskopt | MASK | โ |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | โ |