ER Relighting
Drag a light over your render and see it shade — screen-space relighting done right
- images
- depth
- normals
- images
Every AI image is lit the way the model decided to light it - and quite often that's a flat, directionless light. If you've ever wanted to add a rim light, pull a window's glow across a face, or just re-sculpt the light in a render, the honest answer used to be "paint it" or "run it back through an edit model and pray." ER Relighting gives you a third option that's far more controllable: drag actual point lights over the image and let them shade it, in real time, on the GPU.
It's from the ER VFX Nodepack by Héctor Gallego (ER Academy), and it's a screen-space relight - it re-lights the pixels it has, it doesn't re-render geometry. What makes it work is that it shades with real normals, and where do normals come from? Depth. That's the node's core mechanism, and it's worth understanding before you touch a slider.
How the shading works
The pipeline, from the source:
- You optionally connect a depth map (the KB's depth-estimation doc covers the ecosystem: Depth Anything is the standard, white = near). If nothing's connected, the node derives a luminance-based pseudo-depth from the image itself so it works out of the box.
- The depth is pre-smoothed (a triple box blur, radius = the
normal_smoothinput, default 3px) before central-difference gradients are taken, and the gradients are clamped. That preprocessing is the trick that kills the banding and noise you get from raw depth-to-normal conversion. - Result: a normal per pixel. Each of your point lights shades every pixel with Lambertian diffuse lighting and distance attenuation.
If you have a real normal map (NormalCrafter, OpenGL convention), connect it to the normals input and it replaces the depth-derived normals entirely - highest quality path.
The inputs that matter
- images - what you're lighting. The node is required-input heavy for a reason:
- ambient (default 1) - how much of the original lighting survives. Set it to 0 to black out the image and see only your lights; that's the fastest way to tune falloff.
- normal_strength - relief of the depth-derived normals.
- invert_depth - flip on if your depth map is black = near.
- normal_smooth - depth smoothing in px; higher = cleaner, softer relief.
- lights - a string the UI serializes your point lights into (you don't type it).
- Optional depth and normals inputs as above.
Lights are added with + Light (max 4), dragged as markers on the preview, and each has color, intensity, radius (attenuation), and Z (height above the image). A View switch cycles Result / Lights / Depth / Normals - the Lights view shows the pure light contribution on a neutral background, which is ideal for dialing radius without the image confusing you.
Where it fits and its limits
Reach for it when the light is almost right and needs a nudge - a cool rim from the side, a warm practical lamp in the corner - or when you're comping a subject into a background and need to fake a matching light direction. Because it's deterministic and per-frame, it works on video batches too.
The honest limitation: screen-space means it can't re-light what it can't see, and a bad depth map gives bad shading. Feed it a real Depth Anything map rather than trusting the luminance fallback whenever the result matters, and connect a true normal map if you have one. This is the KB's depth lesson in miniature: the quality of the geometry you feed it decides the quality of the light you get back.
Installing
ER Relighting is part of the ER VFX Nodepack. ComfyUI Manager → search "ER VFX Nodepack" → install, or:
cd ComfyUI/custom_nodes
git clone https://github.com/esperandoelrender/ComfyUI-ER-VFX-Nodepack.git
Restart and search "ER" (image/adjust). No extra dependencies or downloads. If you previously installed the standalone er_relighting pack, remove it first to avoid duplicate nodes.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | — | |
| ambient | FLOAT | 1.000–2 | How much of the original lighting remains (0 = only your lights) |
| normal_strength | FLOAT | 1.000–5 | Relief strength of the normals derived from depth |
| invert_depth | BOOLEAN | false | Enable if your depth map is black = near |
| lights | STRING | [] | — |
| normal_smooth | FLOAT | 30–10 | Depth smoothing (px) before deriving normals - higher = cleaner, softer relief |
| depthopt | IMAGE | Depth map (white = near). If not connected, a luminance-based pseudo-depth is used | |
| normalsopt | IMAGE | Optional normal map (OpenGL convention). If connected, it replaces the depth-derived normals |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | — |