Notice of Meeting - ACES Gamut Compression Implementation VWG Meeting - September 9, 2021

ACES Gamut Compression Implementation VWG Meeting

Thursday, September 9, 2021
5:00pm PDT Add to Calendar (.ics)

Dropbox Paper homepage for this group:

We use the same GoToMeeting URL and phone numbers for all VWG meetings.

You may join via computer/smartphone (preferred) which will allow you to see any presentations or documents that are shared, or you can join using a telephone which will be an audio only experience.

Please note that meetings are recorded and transcribed and open to the public. By participating you are agreeing to the ACESCentral Virtual Working Group Participation Guidelines.

Audio + Video
Please join my meeting from your computer, tablet or smartphone.

Audio Only
You can also dial in using your phone.
Dial the closest number to your location and then follow the prompts to enter the access code.

United States: +1 (669) 224-3319
Access Code: 241-798-885

More phone numbers:
Australia: +61 2 8355 1038
Austria: +43 7 2081 5337
Belgium: +32 28 93 7002
Canada: +1 (647) 497-9379
Denmark: +45 32 72 03 69
Finland: +358 923 17 0556
France: +33 170 950 590
Germany: +49 692 5736 7300
Ireland: +353 15 360 756
Italy: +39 0 230 57 81 80
Netherlands: +31 207 941 375
New Zealand: +64 9 913 2226
Norway: +47 21 93 37 37
Spain: +34 932 75 1230
Sweden: +46 853 527 818
Switzerland: +41 225 4599 60
United Kingdom: +44 330 221 0097


  • Talked about PR for the reference implementations in applications for temporary use.
    • Feedback welcome
    • Should we enable ACEScc as a working space along with ACEScg and ACEScct? Group says not necessary.
    • @sdyer: we should update the main readme as well
  • Talked about the PR for updating the naming conventions on the CTL
    • @sdyer : didn’t take it too far with the inverse separation, so if anyone has opinions, let us know
    • URN versioning updates:
      • a1.3.0 → a1.1.0
      • Options: a1.v1 - this is the proposed new versioning schema Scott is likely to propose in a revision to the current naming/version doc
      • Group likes a1.v1
  • Talked through the User Guide a bit
    • @jzp : make sure the same consideration is given to each dept, and not just finishing and VFX
    • @matthias.scharfenber : yes, and around 3D LUTs - one of the open questions is should we “bless” a shaper function to accompany the work for the cases where folks need to bake a LUT based on ACEScct vs a camera vendor encoding?
    • Group agreed that we should provide information around the issues, but not a solution, as once the algorithm is properly implemented in all software, it should not be necessary.

Recording and Transcript

In the meeting it was mentioned that for creating a LUT for on-set in a LUT box that if the native camera gamut was used there would not be a need for a shaper that covers negative values.

Just wanted to clarify if I’m understanding how this would be implemented in Resolve Here’s a stab:

  1. ACES is set in the Project Settings Color Management
  2. Camera Raw footage is debayered into the working space (ACEScct)
  3. The RGC DCTL is added to the first grade node from the LUT menu.

Would that be the workflow to go from the camera gamut into the RGC? Or is there something I’m missing? Just trying to connect the dots. Thanks so much!

It’s slightly more complex than that. A LUT for use in an on set LUT box would need to also include the IDT and ODT, as well as the gamut compression. In ACES mode, Resolve only exports the node tree as a LUT.

So you would need to build the whole ACES pipeline in the node tree, probably using the ACES transform OFX. You would also possibly need to add a legal to full scale at the start of the node tree, and a full to legal at the end, depending on the LUT device you plan to use the LUT in. See this table for more info.

Thanks @Nick, I’m tracking with making the input and output with OFX nodes. Could you say a bit more about how the “full to legal” would be done in Resolve?

I use DCTL to do those scalings. @Paul_Dore has functions for them here in his ACES DCTL library.

It’s worth bearing in mind when you construct pipelines like this specifically to build LUTs, that the image may not “look normal” with all the nodes applied.

I also see that Resolve ships with a LUT called “data to video with clip.” Would that also work?

Just working through this out loud… the reason you are doing a legal to full at the start and full to legal at the end is the same idea of when one adds a log shaper to a LUT where we begin in linear working space, do an inverse log sandwiched with a lin2log:

log to lin (inverse log)
lin to log

Likewise here we are assuming that the camera data is full range, and Resolve is working in full range and do the same “sandwiching” to bring all of that into legal range for the LUT:

legal to full (inverse legal)
full to legal

Therefore the “data to video with clip” would not work because there’s not a way to invert LUTs in Resolve that I’m aware of.

So I took a stab at writing erm… copy-pasting the DCTL you linked to. I’m not a programmer nor a scientist by a long shot so be gentle, but I would appreciate any corrections in case I mucked things up somewhere…

For the legal to full DCTL I have

__DEVICE__ float smpteRange_to_fullRange( float in) {
const float REFBLACK = ( 64.0f / 1023.0f);
const float REFWHITE = ( 940.0f / 1023.0f);
return (( in - REFBLACK) / ( REFWHITE - REFBLACK));

__DEVICE__ float3 smpteRange_to_fullRange_f3( float3 rgbIn) {
float3 rgbOut;
rgbOut.x = smpteRange_to_fullRange( rgbIn.x); 
rgbOut.y = smpteRange_to_fullRange( rgbIn.y); 
rgbOut.z = smpteRange_to_fullRange( rgbIn.z);
return rgbOut;

and for the full to legal DCTL I have

__DEVICE__ float fullRange_to_smpteRange( float in) {
const float REFBLACK = ( 64.0f / 1023.0f);
const float REFWHITE = ( 940.0f / 1023.0f);
return ( in * ( REFWHITE - REFBLACK) + REFBLACK );

__DEVICE__ float3 fullRange_to_smpteRange_f3( float3 rgbIn) {
float3 rgbOut;
rgbOut.x = fullRange_to_smpteRange( rgbIn.x); 
rgbOut.y = fullRange_to_smpteRange( rgbIn.y); 
rgbOut.z = fullRange_to_smpteRange( rgbIn.z);
return rgbOut;

That LUT does no scaling. It just clips to the float equivalent of 64-940. So no, it wouldn’t work.

In terms of the DCTL, what you have above defines the necessary functions, but you then need the main function which actually applies those functions to the image data.

__DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B)
    return smpteRange_to_fullRange_f3(make_float3(p_R, p_G, p_B));

But whether you need those or not depends on the LUT device, and how it applies LUTs. So for example, because the LUT processing in an ALEXA treats 0-1 in the LUT table as meaning 0-100% IRE (and likewise maps 0-100% IRE to the input domain of the LUT) you don’t need to add any scaling either end. For a LUT box which operates directly on the SDI code values without scaling, you need an input legal to full scale baked into the LUT for an ALEXA LogC signal (but not for a Sony signal, as S-Log3 0-1 is mapped to unscaled SDI code values) and an output full to legal scale (for both LogC and S-Log3).

It’s very confusing, and I do plan to write a blog post on the subject at some point (but I’ve been saying that for a while!) You need to know what your incoming signal is, how the processing in your LUT device works, and what your monitor expects.

Indeed! Thanks for helping to clear a path through the jungle!

Bookmarked. I did find what you wrote here helpful too.

At some point it would be great to update the @cmlgeoff post of camera LUTs with the ref gamut compression (RGC) too. Although it of course only seems fair that it should not be expected that this would happen before it is implemented in the DCC software (ColorFront, Pomfort, Nuke, Resolve) ! :slight_smile: