Even if, is there something we can do about it? As you say, we don’t change the hue, so whatever RGB changes happen by changing J and M are driven by the model. All operations, in-gamut compression included, happen in JMh.
The compress mode, though, happens in LMS, in order to avoid negative values in LMS.
When M is also zero, the value of h is not relevant. It cancels out. This part of the code is creating an achromatic colour with the same J value as the original, in order to run that backwards through the model to find the corresponding Y value and tone map that, because the tone mapping curve used operates in the linear luminance domain. The tone mapped value is then run forwards through the model, and the original M and h values “put back”. Ideally we would just apply a tone mapping curve to J, without the need for this back and forth. But we don’t have a version of the tone mapper that works in the ZCAM / Hellwig J domain.
The hellwig_ach Blink version here is a simplified version of the back and forth, which removes all the elements unnecessary for achromatic values. This is for Hellwig, but you could probably do something similar for ZCAM.
I have found that the SDR image sometimes looks brighter / more saturated than the HDR image. It looks even brighter / more saturated than the original linear rgb input. Then I remembered that DCamProf’s neutral tone reproduction operator was very good at matching the tone-mapped image with the linear image perceptually. So, I’ve looked into it and found that it uses mainly the luminance from a pure rgb curve for tone mapping. Only for more saturated colors the tone curve is applied on the input luminance and then used for the tone mapping:
Luminance is the same as a DCP tone curve applied in linear ProPhoto space
This means that the contrast and brightening will be the same as a standard DCP/RGB curve, so you can use the same curve shape.
Exception: for high saturation colors (flowers etc) a pure luminance curve is blended in, as it has better tonality.
Tonecurve applied on the input luminance, which is then used for the tone mapping
Luminance derived from a pure rgb curve, which is then used for tone mapping
I personally do prefer the look of Anders Torger’s method (especially for red colors like in the example above) and I hope that it can improve SDR/HDR matching. Now I’m curious if it’s possible to use this method for the ACES DRT? I mean, is it possible to find an inverse of the transform?
I pushed a new proto version v042-pex that has a chroma compression without saturation boost. Available from my DRT prototype repo. Please test and see how that behaves compared to the previous one and how the Rec.709 and Rec.2100 appearance match looks. There’s not much difference to v035 in Rec.709.
I created LUTs for Rec.709, Rec.709 sim and Rec.2100 P3Limited, also available from the same repo under the LUT directory.
I also created an alternative version of Rec.2100 P3Limited LUT which maps middle gray to 13.3 nits. It’s there for testing to see what a lower middle gray mapping does to the appearance match when comparing against Rec.709.
For the version that goes to testing can we have it as a DCTL?
I have tried to get Nuke non-commercial to work with Blinkscrip with no success. I have a Windows system with AMD hardware.
I would also like to run the test images on the 12.9" iPad M2 Pro with DaVinci Resolve for iPad to view in both SDR and HDR. Nuke does not run on iPad.
Thanks
(An additional note is to be aware that some GPU cards have settings for graphics pixel bit format which is separate and differs from display color bit depth. From my understanding the pixel bit will effect the calculations, truncating them to the selected bits. Make sure that the GPU is set to 10-bit in both areas. The latest AMD Radeon Pro W7900 & 7800 go to 12-bit as do the upper end Nvidia. )
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.
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.
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.
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.
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.
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.
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: