ACES 2.0 CAM DRT Development

I’ve just pushed CAM DRT v042-pex3 to my repo.

v042-pex3 version brings the following changes:

  • New chroma scaling with the exponent suggested by @luke.hellwig.

  • New in-gamut compression algorithm that matches the look of the previous versions. It first expands colorfulness a little bit in the darker colors, and then compresses to create the path to white. The in-gamut compression no longer pushes values outside spectral locus (or is minimal compared to previous versions).

  • New HDR/SDR appearance match technique. The old technique of rescaling the tonescale to bring the chroma scaling ratios closer to 100 nits tonescale is no longer used. Instead, the ratios are used as is and the tonescale is not touched. The match is created by scaling the in-gamut compression parameters automatically by the peak luminance. This is simpler than the previous one.


LUTs and DCTLs are available in my repo for Rec.709, Rec.709 sim and Rec.2100 P3Limited.

Look compared to v035



Effect of in-gamut compression to values close to spectral locus

Input image:

Input chromaticities:

Scaled chromaticities (using the new exponent):

Fully chroma compressed chromaticities:

Then comparing to v035. v035 fully chroma compressed chromaticities:

The last two images show the difference between v042-pex3 and v035, and the problem that the older versions had that @alexfry has been talking about. In v042-pex3 the chromaticities are no longer pushed outward, or is only minimal compared to older versions.


Here are the DCTL versions

Thankyou Anton and Pekka both, but will we be able to have math DCTLs and not just a LUT? Thanks.

I gave a couple reasons in:

I’ve added some new baked variations to the LUT repo:

rev044 - Which is what @priikone showed in the meeting this moring, but with some of my iterative solver fixes merged (not active in this bake though.

rev044_B - Is the identical blink code, but with some different settings one the Nuke node.

  • IterativeGamutCompressor is On.
  • custp to mid blend is set to 0
  • Reach Compression Mode is on, and set to Spectral Locus

Both can also be found in the dev repro:

CAM_DRT_v044.blink is used by both
CAM_DRT_v044.nk and CAM_DRT_v044_B.nk (same code, different settings)

My one BIG caveat, is that the inverse pathway on the iterative gamut compressor isn’t working properly, and I’m not going to be able to sort it before I go away.

The difference between the two variations is pretty negligable when looking at “normal” images, and really only manifests with extreme colours and intensities.


Here is -4 stops with rev044_B Rec709 in Resolve (no RGC)
(I used _B version, as a better one in terms of handling this artifact)

Maybe it’s better to use a synthetic gradient for that? If I turn on RGC, it helps a little bit, but if I also add saturation in ACEScct using old Saturation knob (just a regular CDL-like saturation) from default setting 50 to 60, the transition becomes more visible again. I think, even if you’ll manage to somehow display this particular image without the sharp transition at all exposures, this balance will still be very fragile.

As to ver044 and ver044B there still seems to be some NANs produced with extreme examples. For example when looking at the red diver with torch: some white dots appear in black areas when I am using an exposure DCTL which is basically for linear input rgb = rgb * _exp2f(exposure). And all I need to do is turn that exposure node on and off, even with 0 exposure, and the dots go on and off. This does not happen in typical frames (without extreme colors.) (Only two nodes: a simple exposure DCTL and an ACES Transform with the new versions selected. Set up as documented on ACES Central.)

Also the white dots (NANs?) then go away when I turn on the Gamut Compress in the ACES Transform node, even if those values are minimally set at limits of 1.001 and thresholds of 0.000.

I am using Resolve on a Windows10-64 AMD system with the new rev044 & rev044B LUT based DCTLs and do not know if this might just be due to using the LUTs.

Had a quick look at the LUT-based DRT packages 44 and 44_B.

One thing I noticed is that dark colours swing a bit in an unexpected manner.
If you add a full red ramp in ACEScct through the pipeline, you notice a sudden turn towards orange.

Cyan have less of that effect.

Blues are desaturating more than other colours:

I would do some more testing in cinema environments with very dark shots. Sometimes it is difficult to get a rich, dark image in a cinema; further desaturation at the low end does not help.


I pushed a new version CAM DRT v045-pex to my prototype repo. This version brings the following changes:

  • Introduce “reach mode” chroma compression. The chroma compression space is now used to find out how far to reach out (the limit for chroma expansion/compression). The reach limit is normalized with the cusp of the same space. The primaries of the chroma compression space is changed at the same time. This significantly improves the inverse, as well as guarantees the chroma compression will not expand or compress colorfulness beyond that space. This is using same technique as @alexfry’s reach mode gamut mapping.

  • Make noise reduction optional and disabled by default. The new transforms doesn’t really increase noise anymore so noise reduction may be redundant.

  • Change gamut mapping parameters. Adds also clamp for maximum M that the transform handles. This is 2x the maximum M value for 10000 nit display. That value and any value above that would map only to display white or be always out of gamut even after gamut mapping. This avoids NaNs with the gamut mapper quadratic.

Rec.709 Inverse



Effect of chroma compression to chromaticities

Input chromaticities:

scaled chromaticities:

fully chroma compressed:



I believe the strange behavior @meleshkevich is pointing out is a similar sudden hue direction change in blue/cyan:

blue-cyan_hue_direction_change_v44.nk (298.5 KB)

1 Like

I think the example you posted is caused by the final gamut compression.
In you Nuke Script if you disable apply out of gamut compression the dent goes away.

I am concerned about the deepest shadows.

The good news is that I don’t see the dents in the deepest shadows in the Nuke-based implementation. So it seems that the LUT-based implementation has its difficulties down there.


I think the inability to quite reach the red primary is caused by a combination of the gamut approximation and the cusp smoothing. Looking at a 3D JMh plot around the red primary, setting cusp smoothing to zero, and using the iterative gamut boundary solve, shows the true location of the red primary:

Whereas using the gamut approximation and cusp smoothing the primary is clearly missed:

Note: The version used for this plot is @priikone’s latest, v045-pex, but I believe the same would apply to any recent version.

1 Like

Can you share your Nuke script? I can’t seem to reproduce this using Alex’s visualization Nuke script. Regardless of the approximation or cusp smoothing, neither can reach the red corner in that visualization when I try this (at least when none of the channels are negative). If you plot the actual (not approximation) Rec.709 boundary in JMh, does it reach the red corner?

It’s entirely possible I have done something stupid!

I did assume that since the iterative solve was accurately finding the cusp, what I was seeing was the cusp. But it is just compressed values, so maybe not.

I am not using Alex’s visualiser. I just take the output of the DRT in diagnostic mode 3 (which I believe should be compressed JMh) and run it through a simple polar to rectangular Expression and into a PositionToPoints node. The input is your locus ramps image.

Here is my nuke script:

Pex45_plot.nk (337.8 KB)

The difference is that with diagnostic mode 3 the output hasn’t been clamped yet, while the one I was showing was after the final transform. Without clamp, it extends out more but it still seems like it misses the corner, here for both approximation and iterative, in that order:


Really needs to be looked at from various angles to see it well, and these two pictures weren’t from same angle.

It seems one way to get to the red corner is to change the threshold value from 0.75 to 0.95.

Would that value need to change for each viewing colour space - like P3 or Rec2020?

We certainly don’t want something where a value has to be manually chosen for each target. If a different value is needed, it should be derivable for any arbitrary target by a clearly documented method, even if it cannot be set procedurally within the rendering code.

I don’t actually think that 0.95 would necessarily be good threshold. Might be ok for red but might not be for blue. The threshold defines how far in gamut the out of gamut values are pulled in (so that the compression stops at the 1.0 boundary when the limit is reached). 0.95 doesn’t give much room. Maybe with the reach gamut mapper it should also change the threshold based on the reach limit?

Good day! I am following this thread and others with respect to gamut mapping BT.2020 to smaller gamuts using MadVR renderer for dynamic tone mapping HDR to much lower nit displays such as projectors.

At the moment we are working on Gamut Rolloff over on AVS Forum and your thread has helped us with some ideas and direction in our journey thus far.

I wanted to ask, does anyone here happen to have the ACES test shots in HDR format that we could then use to tone map and gamut map so we would have a point of comparison? Unfortunately I cannot use Nuke and my Resolve skills are limited in this regard to be able to export them on my own, they seem to be exceptional test files particularly the high brightness spheres I keep seeing.

I was able to download the ACES OT Sample frames exr’s but I wondered if anyone would be able to export an HDR Mp4 or the like for 1,000 nits BT2020 at all? Or If there already exists an HDR export would you mind pointing me in the direction of it to download?

Thanks very much sirs and I apologise if this post is considered off topic.