Nodes/DiffusionLight-ComfyUI/PercentileToPixelValueTonemap
ComfyUI Node

PercentileToPixelValueTonemap

Your HDR preview is a white blob. This is the fix.

By DiffusionLight·Created about a year ago·Updated about a year ago· 23
PercentileToPixelValueTonemap
  • images
  • IMAGE
percentile90.00
pixel_value0.9000
gamma2.40

If you've run a DiffusionLight workflow and stared at a featureless white rectangle where your environment map should be, you've hit the exact problem this node exists to solve. An HDR image carries brightness values above 1.0 - that's the whole point of it, the sun in a light probe is legitimately 20× brighter than the sky. But your monitor, your browser preview, and PreviewImage all assume 0-to-1. Feed them an HDR and they just clamp everything to white.

PercentileToPixelValueTonemap squashes the HDR down into a range you can actually look at, and it does it intelligently - by anchoring on a percentile rather than a fixed maximum.

How it works

The code is short enough to read in one go, and it's worth it because this is the one place in the pack where the math is doing something you might not expect:

  1. Gamma decode. If gamma isn't 1.0, it raises the image to 1/gamma. The default 2.4 is the display-gamma assumption, converting the sRGB-ish output back toward linear light. Set gamma to 1.0 to skip this entirely.
  2. Find the anchor. It computes the percentile value across all pixels of each image - default 90, so it finds the pixel brightness below which 90% of the image sits. This is torch.quantile over the flattened image, computed per image in the batch.
  3. Normalize. Divide the whole image by that percentile value and multiply by pixel_value (default 0.9). Net effect: the 90th percentile of your image lands at 0.9, everything brighter rolls off above it, everything darker sits proportionally below.

The result is a tonemapped IMAGE in roughly 0–1 that PreviewImage can display and that an SDR node downstream can process.

The inputs you'll actually touch

  • percentile (default 90) - the anchor point. Raise it toward 100 to preserve more highlight detail at the cost of a darker overall image; lower it for a brighter, punchier preview.
  • pixel_value (default 0.9) - what that percentile maps to. Combined with percentile it's your exposure knob.
  • gamma (default 2.4) - set 1.0 to skip gamma correction if you're feeding linear data or want a straight normalized view.

Where it fits (and where it doesn't)

Honest note: this node is not in the stock diffusionlight-workflow.json. The shipped workflow previews the three exposure brackets as ordinary SDR images instead, and saves the HDR straight to disk. So don't go hunting for a missing connection - you add this node yourself when you want to look at the HDR you just built, or when you want a tonemapped version to feed into another SDR pipeline. It's a helper, and a genuinely useful one.

The one real gotcha is that normalization is per-image in the batch. If you feed it a batch of different exposures, each one gets its own percentile anchor, so relative brightness between frames isn't preserved. That's usually what you want for previews; just know it's not a global exposure operator.

Installing it

Standard for the pack: ComfyUI Manager → search "DiffusionLight-ComfyUI", or:

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

Then restart. This node needs no extra models - it's pure torch math on the tensors already in your graph, so you can drop it into any existing workflow that produces an IMAGE.

It's not a glamorous node, but it's the one that turns an invisible result into something you can check with your own eyes before you commit it to a 3D render. That's worth a place in your graph.

Categorysd

Inputs (4)

NameTypeDefaultDescription
imagesIMAGE
percentileFLOAT90.000–100
pixel_valueFLOAT0.90000–1
gammaFLOAT2.40-1000–1000

Outputs (1)

NameTypeDescription
IMAGEIMAGE