Nodes/radiance/GPU Tensor Ops
ComfyUI Node

GPU Tensor Ops

One node for exposure, gamma, clamp and normalize

By FXTD-Studios·Created 8 months ago·Updated about 18 hours ago· 246
GPU Tensor Ops
  • image
  • processed_image
  • performance_info
◄operationExposure►
◄value0.0►
◄force_gputrue►

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: 1 doubles, value: -1 halves. 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. value is 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.

CategoryFXTD STUDIOS/Radiance/HDR

Inputs (4)

NameTypeDefaultDescription
imageIMAGEImage to process, usually linear float. The whole batch is processed.
operationCOMBOExposureExposure: 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.
valueoptFLOAT0.0-10–10Exposure: 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_gpuoptBOOLEANtrueRun on CUDA when available. Off always runs on the CPU. Results are the same either way.

Outputs (2)

NameTypeDescription
processed_imageIMAGE—
performance_infoSTRING—