Advanced Relight Node
Drag a light around your photo — Advanced Relight Node, explained
- image
- normal_map
- depth_map
- mask
- IMAGE
Advanced Relight Node (RelightNode) is the no-diffusion way to relight an image in ComfyUI. No model weights, no API key, no regenerating the frame. You hand it your image, a normal map, and a depth map, and it computes a lighting pass on the fly - up to two lights (point or neon) - with a slider you drag to reposition them live. It's deterministic, runs in milliseconds, and never alters your pixels.
That last point is the whole reason to reach for it. The diffusion route (IC-Light and friends) re-emits the entire frame to match your lighting prompt, so logos, stitching and label text come back close but not identical - a real problem for product shots and batch work. This node is the opposite: it modifies illumination only, like a classic photometric render, so a whole catalogue keeps every detail pixel-identical and only the light changes. It won't give you the global-illumination magic of a trained model, but for "consistent studio light on this object" it's fast and repeatable.
How it works
The math is basic Lambertian diffuse lighting - point a light vector at each pixel's surface normal and read the dot product:
- The normal map becomes per-pixel surface direction vectors, while the depth map builds a fake 3D surface:
depth_scalepushes pixels back in Z, so near parts react differently than far parts to a moving light. That's the parallax. - Each light's vector (a point position, or the nearest point on a line segment for a neon) is dotted with the surface normal, then gamma-compressed. Higher
gamma= sharper, focused highlights; lower = softer, broader light. - The light map is optionally blended with a "virtual dome" from a mask (below), median-smoothed, offset by ambient, tinted by light color, and - with
preserve_coloron (the default) - applied only to the HLS lightness channel, leaving hue and saturation alone.
The inputs that matter
Three required inputs, one optional: image, normal_map, and depth_map are IMAGE tensors; leave mask disconnected unless you want the shape trick below. The bundled example workflow shows the wiring: load an image, remove the background, grab a normal map and a Depth Anything V2 depth map, feed all three in - both preprocessors are standard.
The controls you'll actually touch:
light_x_1/light_y_1/light_z_1- light position. X/Y are normalized 0–1 across the image; Z is distance from the surface - lower = closer = smaller, sharper highlights.intensity_1- brightness (0–50, default 7).point_size_1softens a point light; withlight_type_1onNeon,neon_length_1andneon_angle_1size and rotate the bar.ambient_light- base level for the whole scene. The default is negative (−0.2), which deliberately darkens shadows instead of just adding light. Crank it positive for a brighter fill.preserve_color- leave it on unless you want the light to re-tint the image;light_coloris a hex string like#FFFFFF.
The single output is one IMAGE - wire it to a preview, save, or the next compositing step. Use debug_view to peek at the stages when something looks off.
The mask trick
Feed a mask and tick mask_enabled, and the node treats it as a 3D bump - a "virtual dome" - and lights it like a shape, then blends that with the main lighting using brush_intensity (blend strength) and brush_softness (edge feathering). That's how you get a directional gradient without it looking flat. It's also the only feature with an extra dependency: the dome needs SciPy's distance transform, and the pack ships no requirements.txt, so ComfyUI Manager won't install SciPy for you. If it's missing, the node's inputs are replaced by an error widget (in French) telling you to pip install scipy and restart. Skip masks and you don't need it at all.
Install and gotchas
cd ComfyUI/custom_nodes
git clone https://github.com/tritant/ComfyUI_Relight_Img
…or search Advanced_Relight_Img in ComfyUI Manager, then restart. No models to fetch.
Three gotchas worth knowing before you hit them:
- The slider preview shows nothing until you run the workflow once. That's by design (the README says so): the node starts a tiny local server on
127.0.0.1:8189to serve the preview, because the standard ComfyUI preview API is flaky in some environments. It serves exactly one temp image and can't list directories, but if another process owns port 8189, the preview won't load. debug_view→Light Shape Vizcurrently outputs a black frame - listed in the dropdown but not wired up in the code. Use the other four.- SciPy - the one real dependency, only for the mask feature, and not auto-installed. See above.
Is it a one-node pack? Yes - a single, fiddly node with a lot of sliders. But once you've gotten the hang of the drag-to-place preview, it's the fastest consistent-relight tool going: overkill for cinematic relighting, exactly right when you want controlled, repeatable light without ever regenerating a pixel.
Inputs (37)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| normal_map | IMAGE | — | |
| depth_map | IMAGE | — | |
| debug_view | COMBO | 5 options: Final Image, Lighting Map Only, Mask Lighting Only, Mask Virtual Normals, Light Shape Viz | |
| preserve_color | BOOLEAN | true | — |
| ambient_light | FLOAT | -0.20-1–1 | — |
| gamma | FLOAT | 5.50.1–20 | — |
| light_color | STRING | #FFFFFF | — |
| depth_scale | FLOAT | 1500–1000 | — |
| median_filter_size | INT | 311–31 | — |
| dithering_strength | FLOAT | 0.10–5 | — |
| spacer_1 | STRING | — | |
| mask_enabled | BOOLEAN | true | — |
| brush_intensity | FLOAT | 0.700–1 | — |
| brush_softness | FLOAT | 2.00–20 | — |
| mask_intensity_mult | FLOAT | 0.200–2 | — |
| mask_gamma_mult | FLOAT | 0.140–2 | — |
| spacer_2 | STRING | — | |
| light_type_1 | COMBO | Point | 2 options: Point, Neon |
| light_x_1 | FLOAT | 0.350–1 | — |
| light_y_1 | FLOAT | 0.500–1 | — |
| light_z_1 | FLOAT | 0.350–1 | — |
| intensity_1 | FLOAT | 7.00–50 | — |
| point_size_1 | FLOAT | 0.500–1 | — |
| neon_length_1 | FLOAT | 0.770–2 | — |
| neon_angle_1 | FLOAT | 900–360 | — |
| ui_anchor | STRING | — | |
| enable_light_2 | BOOLEAN | false | — |
| light_type_2 | COMBO | Point | 2 options: Point, Neon |
| light_x_2 | FLOAT | 0.650–1 | — |
| light_y_2 | FLOAT | 0.500–1 | — |
| light_z_2 | FLOAT | 0.100–1 | — |
| intensity_2 | FLOAT | 5.00–50 | — |
| point_size_2 | FLOAT | 0.100–1 | — |
| neon_length_2 | FLOAT | 0.770–2 | — |
| neon_angle_2 | FLOAT | 900–360 | — |
| maskopt | MASK | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| IMAGE | IMAGE | — |