ComfyUI Node

Exposure to HDR

Three Exposures, One Real HDR Light Probe

By kijai·Created 2 years ago·Updated 2 years ago· 74
Exposure to HDR
  • images
  • hrd_image
  • ldr_image
gamma2.40

The output of chrome_ball_to_envmap is not actually usable yet. It's a flat, low-dynamic-range image, and relighting wants linear radiance - a real HDR map, not a JPEG that happens to be shaped like a sky. That's the job of exposure_to_hdr: it takes the last step of kijai's DiffusionLight pack, the one that turns your painted chrome ball into something a relighter or a 3D renderer will actually believe.

What it actually does

In the pack's example workflow, the pipeline is: SDXL plus the bundled DiffusionLight LoRA paints a chrome ball that reflects the scene's lighting → chrome_ball_to_envmap unwraps it into an equirectangular environment map → this node converts that envmap into HDR → a second SDXL pass (guided by GeoWizard depth and ControlNet) relights the original photo using the probe as the lighting reference.

The node takes a batch of images and fuses them into one high-dynamic-range image. It also hands you back a tone-mapped LDR version so you can actually look at it on a normal monitor - HDR values live way outside the 0–1 range you can display.

How it works

The clever (and slightly blunt) part is in the source: the three exposure values are hard-coded to [0.0, -2.5, -5.0]. It assumes your batch has exactly three frames that are three exposures of the same scene. Each is linearized with pow(image, gamma), the luminance of each is computed, and the frames are merged darkest-first with a soft mask so highlights that are blown out in one exposure get replaced by the next one down. The result is an HDR radiance map with the exposure headroom a real one needs. It then runs TonemapHDR (percentile 99, max mapping 0.9) over it to produce the LDR preview.

So no, this isn't a fancy learned HDR model - it's exposure fusion, the same family of trick your phone's night mode uses. For a synthetic chrome ball it's plenty, because the three "exposures" you feed it are cheap to generate.

The inputs and outputs that matter

  • images (IMAGE): a batch of exactly three. Wire in the envmaps from chrome_ball_to_envmap.
  • gamma (FLOAT, default 2.4): the display gamma used to linearize the inputs and tone-map the output. 2.4 is the sRGB-ish standard; you'll rarely touch it.

Outputs:

  • hrd_image: the linear HDR map - the one you wire into your relighting pass or save to EXR (the example uses a SaveImageOpenEXR node from another pack).
  • ldr_image: the tone-mapped preview, safe to throw at a PreviewImage.

One detail worth knowing before you hunt for a bug: the output socket is literally named hrd_image - that typo is in the author's code, not your workflow.

Installing it

This ships with the rest of the pack, so install once. In ComfyUI Manager, search for "DiffusionLight" and install kijai/ComfyUI-DiffusionLight, or:

cd ComfyUI/custom_nodes
git clone https://github.com/kijai/ComfyUI-DiffusionLight

Then restart ComfyUI. There's no requirements.txt - it only uses torch and numpy, both already in ComfyUI, so no dependency roulette. The one extra file is the LoRA, diffusion_light_sdxl_lora_comfy.safetensors, which lives in the pack and must go in ComfyUI/loras (it's already converted to Comfy format; the original diffusers LoRA will not load).

Where people get burned

  • Feed it one image and it errors. The node indexes images[0], images[1], images[2] unconditionally. The example workflow manufactures three frames via VHS_DuplicateLatents (multiply by 3) plus a BatchPromptSchedule from the KJNodes pack - if you're building your own graph, remember the batch of three is a hard requirement.
  • HDR is invisible until you save it. Previewing hrd_image with a normal SaveImage clips everything. Use the ldr_image output for looking, the hrd_image for working.
  • It's an SDXL affair. The LoRA is SDXL-only, so you need an SDXL checkpoint (the example uses juggernautXL). Pointing it at Flux or SD 1.5 gets you nothing.

kijai is the community's go-to wrapper author - the same person behind WanVideoWrapper and DepthAnythingV2 - so the code is compact and stable, if not heavily documented. For a narrow, opinionated little job, this node does exactly what it says, in the exact order the pack needs.

CategoryDiffusionLight

Inputs (2)

NameTypeDefaultDescription
imagesIMAGE
gammaFLOAT2.401–30

Outputs (2)

NameTypeDescription
hrd_imageIMAGE
ldr_imageIMAGE