Nodes/Atlas Camera/Atlas HDR Vertex Transfer πŸŒ—
ComfyUI Node

Atlas HDR Vertex Transfer πŸŒ—

HDR for the side of the object no camera ever saw

By mikejamesvfxΒ·Created 4 months agoΒ·Updated 17 days agoΒ· 3
Atlas HDR Vertex Transfer πŸŒ—
  • solve
  • source_image
  • hdr_image
  • solve
  • report
β—„hdr_exr_pathβ–Ί

Here's a problem you only hit once you've got a generated object sitting inside an HDR plate. You converted the photograph to ACEScg float with the LTX-2.5 SDRβ†’HDR chain. Beautiful. But the object's hidden side - the back you got from Pixal3D - isn't painted by any image at all. It's vertex colour. The SDRβ†’HDR model never sees it, so your sunlit back plate has a generated object whose far side is stuck in display-referred 0–1.

Atlas HDR Vertex Transfer πŸŒ— closes that gap, and it does it by fitting the conversion's own tone curve rather than guessing.

How it works

It takes the pixel-aligned SDR plate and HDR plate pair and fits the model's per-channel tone curve - log-binned, monotone, with the SDR linearised and moved from Rec.709 into ACEScg first (core/hdr_transfer.py). Then it applies that curve to every pixal3d primitive's vertex colours, giving them ACEScg linear values that may legitimately exceed 1.0.

The clever bit is the honesty clause: report tells you how well ONE global curve explains the plate, in residual stops. If your pair is badly mismatched or the model's conversion is non-monotone in some region, you find out from a number instead of from a weird-looking object three tools downstream.

It also tells you where the result can and cannot travel. AtlasSceneTo3D writes the HDR vertex colours as a float-colour binary PLY sidecar, because glTF's COLOR_0 is clamped to 0..1. So the GLB carries the display version and the PLY carries the real one.

Inputs and outputs

Required: solve (the scene, carrying the generated primitives), source_image - the SDR plate the HDR was converted from.

Optional, and only one of these two gets used:

  • hdr_exr_path - the HDR plate EXR from the matrixZone still workflow. Relative to ComfyUI's output or input folder (e.g. atlas/hdr_plate_00001.exr), or absolute inside those folders or $ATLAS_PROJECT_ROOT; other absolute paths are refused unless you set ATLAS_ALLOW_ABSOLUTE_READS=1. Empty means pass-through.
  • hdr_image - a float HDR IMAGE (ACEScg linear) instead, if you already have it on the wire.

There's a caching subtlety in the tooltip worth repeating because it's the kind of thing that costs an hour: a typed path re-runs the node when the file changes on disk, but a linked path re-runs only when the upstream node does. ComfyUI doesn't pass linked values to IS_CHANGED, so a consumed EXR path won't invalidate on its own.

Outputs are just solve and report - the HDR vertex colours ride on the primitives inside the solve, they're not a separate socket.

Install

cd <ComfyUI>/custom_nodes
git clone https://github.com/mikejamesvfx/atlas-camera.git

Or Manager β†’ search atlas-camera (ComfyUI Registry). Restart ComfyUI. No pip step for this node itself - it's pure Python. MIT.

You will need the surrounding lane set up:

  • ComfyUI V135 or later for the Pixal3D core nodes and the LOAD3D_* socket types this chain ends up in.
  • The LTX-2.5 files if you haven't made the HDR plate yet: ltx-2.5-22b-distilled-transformer-bf16.safetensors, ltx-2.5-22b-ic-lora-sdr-to-hdr-1.0.safetensors, the scene-emb variant, and the two VAEs. If the LTXV* nodes load red, install ComfyUI-LTXVideo.
  • Pixal3D model files for the generated object, via the four-file Comfy-Org repack listed in INSTALL.md.

None of this is pip install; it's model files in ComfyUI's model folders, which is why the pack calls these the V135 lane.

Where this bites

Two things bite. Mixed colour encodings - the SDR plate has to be linearised and gamut-shifted before the fit, which the node does for you, but if you feed it a plate that's already been through a look, the fitted curve is that look's curve and your hidden side inherits it. And expectation-setting: highlights above 1.0 here are inferred, not photographed. Same caveat as the HDR plate itself; the far side of the object was never in front of a camera either.

Licence note if you're shipping: Pixal3D's code is MIT but the weights' commercial status hasn't been confirmed upstream. LTX-2.x is free for commercial use by organisations under US$10M annual revenue.

CategoryAtlas/advanced

Inputs (4)

NameTypeDefaultDescription
solveATLAS_SOLVEβ€”
source_imageIMAGEThe SDR plate the HDR was converted from.
hdr_exr_pathoptSTRINGThe HDR plate EXR from the matrixZone still workflow, relative to ComfyUI's output or input folder (e.g. atlas/hdr_plate_00001.exr), or absolute INSIDE the output/input folder or $ATLAS_PROJECT_ROOT; other absolute paths are refused unless ATLAS_ALLOW_ABSOLUTE_READS=1. Empty = pass through. A TYPED path re-runs the node when the file changes on disk; a LINKED path (e.g. from the stitch's exr_path) re-runs only when the upstream node does -- ComfyUI does not pass linked values to IS_CHANGED.
hdr_imageoptIMAGEAlternative to the path: a float HDR IMAGE (ACEScg linear).

Outputs (2)

NameTypeDescription
solveATLAS_SOLVEβ€”
reportSTRINGβ€”