LC Lighting Control π¦
Relight a finished image without regenerating a single pixel
- image
- normal_map
- depth_map
- mask
- image
- debug_mask
The scenario: you generated a portrait, and the light is boring. Flat, even, no drama. Your options used to be IC-Light (a whole diffusion model, a re-generation, a seed lottery) or a color overlay that looks painted-on. LC Lighting Control is the third way: a deterministic post-process that relights the pixels you already have using a normal map and a depth map. Same image, new shadows, zero re-generation.
It's the headline node of the LC123 pack, and it deserves the spot. You feed it your image, a normal map, a depth map (and optionally a subject mask), then aim up to two lights and watch the on-node preview. The math is plain 3D lighting: each pixel is multiplied by how much light hits it based on its surface normal, with depth deciding how far into the beam it falls and an ambient floor keeping shadows from crushing to black. No diffusion, no color tint - it's a render, not a filter.
The inputs that matter
The three images come first, and the maps are the difference between "looks right" and "looks inside-out":
- image - the photo or render to relight.
- normal_map - surface facing. The README recommends BAE or DSINE output.
- depth_map - near vs far; Depth Anything V2 is the suggestion. If bright = near and the lighting looks inverted, invert the depth.
- mask (optional) - a subject matte, only used when
mask_enabledis on.
Then the light rig: each light has X (+X = from the right of frame), Y (+Y = from above), Z (0 = side plane, 1 = front), intensity (0 = that light is off), and size (cone width: small = spot, large = flood). ambient_light is the shadow floor, depth_scale controls how far pixels fall off inside the beam. cast_shadows, shadow_strength, and shadow_softness handle the screen-space shadow march.
Where people get burned
- Grey fringe around the subject. That's
mask_blendtoo high - the README suggests ~0.2β0.45 or just leave the mask off. High blend is the classic first-mistake. - Depth backwards. Bright-as-near makes the light look like it's coming from behind. Flip the depth.
- Normal maps with inverted X. The node accounts for DirectX-style normal maps (it negates X in the NΒ·L term), but if your preprocessor stores things oddly, compare against a known-good map.
The light stage under the sliders is worth knowing: white orb is light 1, red is light 2; drag for XY, shift+drag or wheel for Z. There's an example workflow at workflows/LC Lighting Control (BETA).json in the repo.
Install
Part of LC123 - ComfyUI Manager (search "LC123") or:
cd ComfyUI/custom_nodes
git clone https://github.com/lonecatone23/ComfyUI_LC123_nodes
Restart after. The pack itself needs no extra packages, but the maps are another story: Depth Anything V2, a normal-map preprocessor (BAE/DSINE), and optionally remBG for the mask are all separate installs, per the README. Cloud-hosted ComfyUI won't have LC123 until requested, so plan for local or a pack request.
Outputs are image (the relit frame) and debug_mask (ignore it - it's for troubleshooting the subject mask). Start at intensity ~1.0β1.3, ambient ~0.25β0.4, shadow strength ~0.4, and you're in the ballpark.
Inputs (22)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | β | |
| normal_map | IMAGE | Normal map (RGB). Same subject framing as the image. | |
| depth_map | IMAGE | Depth map. Same subject framing as the image. | |
| ambient_light | FLOAT | 0.250β1.5 | Shadow floor. 0 = pure key. |
| depth_scale | FLOAT | 0.500β2 | Far pixels fall off inside the beam (0 = no depth falloff). |
| light1_x | FLOAT | 0.00-1β1 | +X = from the right of the frame. |
| light1_y | FLOAT | 0.50-1β1 | +Y = from above. |
| light1_z | FLOAT | 0.900β1 | 0 = side plane, 1 = front. Negative is ignored. |
| light1_intensity | FLOAT | 1.000β4 | β |
| light1_size | FLOAT | 1.000.05β1.5 | Cone width: small = spot, large = flood. |
| enable_light_2 | BOOLEAN | false | β |
| light2_x | FLOAT | -1.00-1β1 | β |
| light2_y | FLOAT | 0.00-1β1 | β |
| light2_z | FLOAT | 0.500β1 | β |
| light2_intensity | FLOAT | 1.000β4 | β |
| light2_size | FLOAT | 0.500.05β1.5 | β |
| cast_shadows | BOOLEAN | true | β |
| shadow_strength | FLOAT | 0.500β1 | β |
| shadow_softness | FLOAT | 0.300β1 | β |
| mask_enabled | BOOLEAN | true | β |
| mask_blend | FLOAT | 0.450β1 | β |
| maskopt | MASK | Optional subject mask. Enables virtual-dome normals when mask_enabled. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | β |
| debug_mask | MASK | β |