Notice of Meeting - ACES Output Transforms Architecture VWG - Meeting #11 - 3/10/2021

ACES Output Transforms Architecture VWG Meeting #11

Wednesday, March 10, 2021
11:00am - 12:00pm Pacific Time (UTC-7:00pm)

Please join us for the next meeting of this virtual working group (VWG). Future meeting dates for this month include:

  • 3/17/21
  • 3/24/21
  • 3/31/21

Dropbox Paper link for this group:

We will be using the same GoToMeeting url and phone numbers as in previous groups.
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.

First GoToMeeting? Let’s do a quick system check:

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

Picking up on a discussion from last night’s meeting, can somebody clarify something for me?

I don’t know Unreal Engine. Am I understanding correctly that it uses a modified version of ACES which includes a trim (inversion of the blue highlight fix?) in display linear, just before the final display encoding step? So the discussion of matching UE4 was related to replicating the appearance of this with a standard ACES implementation? Essentially if you can add the same post rendering modification that UE4 does, it’s easy to match it. It’s much harder (indeed impossible for multiple targets) to create a scene-referred adjustment that achieves exactly the same result.

Have I got this right?

The recording and meeting summary are now available for yesterday’s meeting.

Correct, here are the relevant bits:

	const float3x3 BlueCorrectAP1    = mul( AP0_2_AP1, mul( BlueCorrect,    AP1_2_AP0 ) );
	const float3x3 BlueCorrectInvAP1 = mul( AP0_2_AP1, mul( BlueCorrectInv, AP1_2_AP0 ) );

	// Blue correction
	ColorAP1 = lerp( ColorAP1, mul( BlueCorrectAP1, ColorAP1 ), BlueCorrection );

	// Tonemapped color in the AP1 gamut
	float3 ToneMappedColorAP1 = FilmToneMap( ColorAP1 );
	ColorAP1 = lerp(ColorAP1, ToneMappedColorAP1, ToneCurveAmount);

	// ---> Note from Thomas: This is here!        
	// Uncorrect blue to maintain white point
	ColorAP1 = lerp( ColorAP1, mul( BlueCorrectInvAP1, ColorAP1 ), BlueCorrection );

	// Convert from AP1 to sRGB and clip out-of-gamut values
	float3 FilmColor = max(0, mul( AP1_2_sRGB, ColorAP1 ));

        // sRGB, user specified gamut
	if( GetOutputDevice() == 0 )
		// Convert from sRGB to specified output gamut	
		//float3 OutputGamutColor = mul( AP1_2_Output, mul( sRGB_2_AP1, FilmColor ) );

		// FIXME: Workaround for UE-29935, pushing all colors with a 0 component to black output
		// Default parameters seem to cancel out (sRGB->XYZ->AP1->XYZ->sRGB), so should be okay for a temp fix
		float3 OutputGamutColor = FilmColor;

		// Apply conversion to sRGB (this must be an exact sRGB conversion else darks are bad).
		OutDeviceColor = LinearToSrgb( OutputGamutColor );

and where FilmToneMap is the RRT + sRGB ODT:

#if 0
		float3 aces = ColorAP0;
		float3 oces = RRT( aces );
		LinearColor = ODT_sRGB_D65( oces );
	return mul( sRGB_2_AP1, LinearColor );

So this is changeable per-shot and because it is blendable, its effect can also vary from shot to shot.



BUT beyond that, there are few things that make things easier for live event productions, if the client ends up post-RRT/ODT/SSTS with a hard time to push some colours, e.g. yellow, it is certainly much easier to do that in display-referred state and provide a small surgery node to insert above the stack. It is relatively easy to do in UE4.



It is of course perfectly possible to do in most grading systems as well. While the standard ACES setup in Baselight/Resolve has the Output Transform applied at a system level, it is possible to apply it in the stack/node tree instead, and thereby “roll your own” custom ACES based pipeline with additional post OT tweaks. You diverge from the standard at your own risk, but if you just need to get something up on a single display, without the requirement to replicate it elsewhere, you can do what it takes to get that done.

@Thomas_Mansencal In our version that we did, we initially supported making the blue highlight fix lerp ration changeable per shot just like Unreal did but I removed it since artists didn’t understand what it was and just didn’t care about it. As a fun anecdote, we also had a red modifier scale too which went the way of the dodo even quicker. Anyway, this will be gone soon on our side since I’m updating to ACES 1.3.

I don’t think UE4 provides extra surgery nodes post-RRT/ODT/SSTS aside from this inverse blue fix. They do however get out of (kinda) ACES in their SDR codepath to support their legacy LUT blending before they apply the tonemap curve. I call it kinda ACES because their SDR codepath doesn’t use the real ACES curve while their HDR path does.

To any Unreal dev who reads this, I’m sorry if I’m harsh but I really believe that keeping that amount of legacy is a hindrance.



Indeed, but you can insert blendables before and/or after the tonemapper and do whatever you are required to do on the incoming buffer.

It is the intent to remove it, but maybe Epic Games does not want to change that on a minor version!