Nodes/ComfyUI-TextureAlchemy/Normal Map Relighter (IBL)
ComfyUI Node

Normal Map Relighter (IBL)

Relight From an Environment Map

By amtarr·Created 9 months ago·Updated 4 months ago· 58
Normal Map Relighter (IBL)
  • image
  • normal_map
  • environment_map
  • relit_image
  • diffuse_lighting
  • specular_lighting
environment_rotation0
diffuse_intensity1.0
specular_intensity1.0
specular_power32
ambient_light0.10
normal_formatOpenGL

Here's the one that feels like cheating: you can relight an image from an equirectangular HDRI environment map, entirely in ComfyUI, no 3D renderer, no diffusion model, no sampling. Normal Map Relighter (IBL) does image-based lighting with your normal map as the geometry and your environment map as the sky.

The directional relighters are one light. This one is a whole scene. The environment map provides both the diffuse color that wraps around the surface and the specular reflections that slide across it as the surface angles change - which is the thing that makes materials look real instead of just lit. If you've got a glossy surface in a brick or fabric PBR set and want to see it under actual studio lighting before you ship it, this is the preview node.

How it works

Image-based lighting in miniature. The node:

  1. Decodes your normal map to vectors (with the OpenGL/DirectX green-flip handled by normal_format).
  2. Converts each pixel's normal direction into an equirectangular UV coordinate and samples the environment map with bilinear interpolation - that's the diffuse lighting, so the "sky" colors wrap correctly around the surface.
  3. Computes a reflection vector R = 2(N·V)N − V for each pixel, samples the environment at that reflected direction, and applies a Fresnel-style falloff (more reflection at grazing angles) - that's the specular.

Both passes come out separately: diffuse_lighting, specular_lighting, and the combined relit_image. Because the environment drives both, rotating the scene is as simple as dragging environment_rotation (−180 to 180) instead of re-aiming a light.

The inputs that actually matter

  • image and normal_map - the flat albedo/color and the normals.
  • environment_map - your HDRI. Equirectangular (2:1) images work directly; anything else gets sampled based on its own dimensions, so a 1:1 or non-equirect image will look wrong.
  • diffuse_intensity / specular_intensity (0-10) - how much of each pass.
  • specular_power (1-128) - and here's a fun quirk: the tooltip calls it "blur amount - lower = blurrier." Lower values give broad, soft reflections (rough-looking), higher values give sharp, mirror-like ones. That's the roughness knob in disguise.
  • ambient_light (0-1) - a brightness floor so shadows don't crush to black.

Installing it

Part of TextureAlchemy. ComfyUI Manager (search "TextureAlchemy"), or:

cd ComfyUI/custom_nodes
git clone https://github.com/amtarr/ComfyUI-TextureAlchemy

Restart, and find it under Texture Alchemist → Lighting. No model downloads, no pip dependencies - you're just feeding images in.

Gotchas

Honest caveats, because this is a simplified IBL: the specular is a softened sample rather than a true prefiltered mipmap, so don't expect renderer-grade roughness response. And if your relit result looks flat, your normal map is probably weak - IBL is brutally honest about that. The biggest practical trap is feeding it a normal map in the wrong format; a DirectX map decoded as OpenGL (or vice versa) makes reflections sit in the wrong places. When in doubt, check normal_format before you start blaming the HDRI. If you want roughness and metallic maps wired in for a proper PBR pass, that's the IBL + PBR sibling node's job.

CategoryTexture Alchemist/Lighting

Inputs (9)

NameTypeDefaultDescription
imageIMAGE
normal_mapIMAGE
environment_mapIMAGE
environment_rotationFLOAT0-180–180Rotate environment map (degrees)
diffuse_intensityFLOAT1.00–10Diffuse lighting intensity
specular_intensityFLOAT1.00–10Specular reflection intensity
specular_powerFLOAT321–128Specular power (blur amount - lower = blurrier)
ambient_lightFLOAT0.100–1Ambient light level
normal_formatCOMBOOpenGLNormal map format

Outputs (3)

NameTypeDescription
relit_imageIMAGE
diffuse_lightingIMAGE
specular_lightingIMAGE