GPU Tensor Ops
One node for exposure, gamma, clamp and normalize
- image
- processed_image
- performance_info
Five single-operation nodes in one, and the reason to have it is that these are the five things you actually reach for when you're steering an HDR image: exposure, gamma, a lift, a normalize, a clamp. Instead of hunting through the pack for each, pick it from a dropdown.
The operations
operation selects one, and value is its only dial:
- Exposure -
x * 2^value, in stops.value: 1doubles,value: -1halves. The physically correct interpretation of "brighter", and the one that doesn't wreck contrast. - Gamma - sign-preserving
x^(1/value). The tooltip is precise about the edge cases: 0 means 2.2, and anything below 0.1 including negatives is treated as 0.1. That 0→2.2 default is a nice touch - dropping the value to 0 gives you a standard gamma decode without knowing that 2.2 is the number. - Lift/Gain - a flat offset. The tooltip says the quiet part out loud: it adds a constant, there's no gain component despite the name.
- Normalize - per-frame min/max to 0–1.
- Clamp - to 0–1.
valueis ignored for these two, so don't sit there turning it and wondering why nothing changes.
Outputs are processed_image and performance_info - a STRING reading something like Device: NVIDIA GeForce RTX 4080 SUPER | Op: Exposure | Time: 3.41ms. It reports the device that actually ran, not the one you asked for, so it's a quick answer to "did this fall back to CPU?" The whole batch is processed in one call, which is the point: this is a tensor op, not a per-frame loop.
CPU/GPU, and why force_gpu doesn't matter
force_gpu (default on) runs on CUDA when there's a CUDA device, and off runs on the CPU unconditionally. The tooltip states plainly: results are the same either way.
That's a good sign, and it's also the honest framing. This is elementwise arithmetic on a tensor; the GPU helps with throughput on big batches and does nothing for correctness. If you're debugging a suspicious result, flip it to CPU - if the image changes, you've found a genuine bug and you should report it rather than paper over it.
Where it fits
Two places.
As the quick trim inside a float chain. Exposure in stops after a decode, a gamma nudge before a preview, a clamp at the very end if something downstream can't take range. Nothing here needs a colour-space conversion or a grade node.
As the viewable-transform helper. Scene-linear images look dark and flat on an sRGB canvas because they are dark and flat to a display. Exposure plus gamma is the crude, fast way to make one viewable - a sort of poor man's tone map. It's not colour management and it isn't accurate, but for a quick look at a float pass it beats wiring up an OCIO transform.
If you want fifty operations with per-channel control and a proper operation order, RadianceFloat32ColorCorrect is that node. Think of this one as the pocket knife.
Install
Part of Radiance (147 nodes across the pack). ComfyUI Manager → search Radiance → install, restart ComfyUI, hard-refresh the browser. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/fxtd-studios/radiance.git
cd radiance
python -m pip install -r requirements.txt
Windows portable users: use ComfyUI's bundled python_embeded\python.exe for the pip line, or the deps land in a Python ComfyUI never imports - the single most common cause of "the pack installed but half the nodes error". Nothing downloads for this node.
Where people get burned
Normalize on a batch. Per-frame min/max means each frame gets its own scale, so a sequence with any exposure drift comes back drift-free. Great for making one still viewable, wrong for a shot.
Clamping too early. It's on the list and it's tempting, but clamping mid-chain deletes the range you were preserving by working in float in the first place. Clamp at the end, or not at all.
Expecting lift to be a lift. It's an offset. A +0.05 lift at the bottom of the range is also a +0.05 lift at the top, which on a float image is a rounding error up there and a visible grey wash down in the shadows. Fine, useful, and not what the name in your head expects.
Inputs (4)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | Image to process, usually linear float. The whole batch is processed. | |
| operation | COMBO | Exposure | Exposure: x * 2^value. Gamma: sign-preserving x^(1/value). Lift/Gain: adds value (an offset only, no gain). Normalize: per-frame min/max to 0-1. Clamp: to 0-1. |
| valueopt | FLOAT | 0.0-10–10 | Exposure: stops. Gamma: gamma (0 means 2.2, anything below 0.1 including negatives is treated as 0.1). Lift/Gain: offset added. Ignored by Normalize and Clamp. |
| force_gpuopt | BOOLEAN | true | Run on CUDA when available. Off always runs on the CPU. Results are the same either way. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| processed_image | IMAGE | — |
| performance_info | STRING | — |