Skip to content
Go to file
This does not change the intent of the transforms. It simply changes the syntax and logic used to trigger the SMPTE legal range code block. There have been repeated reports of the CTL interpreter not correctly setting the default value to false when using a 'uniform bool'. The correct place to fix this would be in the CTL codebase, but I don't have resources to fix that. Therefore, this change back to the old logic that apparently works should allow users to utilize these transforms in instances where the CTL interpreter is behaving inconsistently.
2 contributors

Users who have contributed to this file

@scottdyer @aforsythe
128 lines (103 sloc) 4.09 KB
// <ACEStransformID>urn:ampas:aces:transformId:v1.5:ODT.Academy.Rec709_100nits_dim.a1.0.3</ACEStransformID>
// <ACESuserName>ACES 1.0 Output - Rec.709</ACESuserName>
// Output Device Transform - Rec709
// Summary :
// This transform is intended for mapping OCES onto a Rec.709 broadcast monitor
// that is calibrated to a D65 white point at 100 cd/m^2. The assumed observer
// adapted white is D65, and the viewing environment is a dim surround.
// A possible use case for this transform would be HDTV/video mastering.
// Device Primaries :
// Primaries are those specified in Rec. ITU-R BT.709
// CIE 1931 chromaticities: x y Y
// Red: 0.64 0.33
// Green: 0.3 0.6
// Blue: 0.15 0.06
// White: 0.3127 0.329 100 cd/m^2
// Display EOTF :
// The reference electro-optical transfer function specified in
// Rec. ITU-R BT.1886.
// Signal Range:
// By default, this transform outputs full range code values. If instead a
// SMPTE "legal" signal is desired, there is a runtime flag to output
// SMPTE legal signal. In ctlrender, this can be achieved by appending
// '-param1 legalRange 1' after the '-ctl odt.ctl' string.
// Assumed observer adapted white point:
// CIE 1931 chromaticities: x y
// 0.3127 0.329
// Viewing Environment:
// This ODT has a compensation for viewing environment variables more typical
// of those associated with video mastering.
import "ACESlib.Utilities";
import "ACESlib.Transform_Common";
import "ACESlib.ODT_Common";
import "ACESlib.Tonescales";
/* --- ODT Parameters --- */
const Chromaticities DISPLAY_PRI = REC709_PRI;
const float XYZ_2_DISPLAY_PRI_MAT[4][4] = XYZtoRGB(DISPLAY_PRI,1.0);
const float DISPGAMMA = 2.4;
const float L_W = 1.0;
const float L_B = 0.0;
void main
input varying float rIn,
input varying float gIn,
input varying float bIn,
input varying float aIn,
output varying float rOut,
output varying float gOut,
output varying float bOut,
output varying float aOut,
input varying int legalRange = 0
float oces[3] = { rIn, gIn, bIn};
// OCES to RGB rendering space
float rgbPre[3] = mult_f3_f44( oces, AP0_2_AP1_MAT);
// Apply the tonescale independently in rendering-space RGB
float rgbPost[3];
rgbPost[0] = segmented_spline_c9_fwd( rgbPre[0]);
rgbPost[1] = segmented_spline_c9_fwd( rgbPre[1]);
rgbPost[2] = segmented_spline_c9_fwd( rgbPre[2]);
// Scale luminance to linear code value
float linearCV[3];
linearCV[0] = Y_2_linCV( rgbPost[0], CINEMA_WHITE, CINEMA_BLACK);
linearCV[1] = Y_2_linCV( rgbPost[1], CINEMA_WHITE, CINEMA_BLACK);
linearCV[2] = Y_2_linCV( rgbPost[2], CINEMA_WHITE, CINEMA_BLACK);
// Apply gamma adjustment to compensate for dim surround
linearCV = darkSurround_to_dimSurround( linearCV);
// Apply desaturation to compensate for luminance difference
linearCV = mult_f3_f33( linearCV, ODT_SAT_MAT);
// Convert to display primary encoding
// Rendering space RGB to XYZ
float XYZ[3] = mult_f3_f44( linearCV, AP1_2_XYZ_MAT);
// Apply CAT from ACES white point to assumed observer adapted white point
XYZ = mult_f3_f33( XYZ, D60_2_D65_CAT);
// CIE XYZ to display primaries
linearCV = mult_f3_f44( XYZ, XYZ_2_DISPLAY_PRI_MAT);
// Handle out-of-gamut values
// Clip values < 0 or > 1 (i.e. projecting outside the display primaries)
linearCV = clamp_f3( linearCV, 0., 1.);
// Encode linear code values with transfer function
float outputCV[3];
outputCV[0] = bt1886_r( linearCV[0], DISPGAMMA, L_W, L_B);
outputCV[1] = bt1886_r( linearCV[1], DISPGAMMA, L_W, L_B);
outputCV[2] = bt1886_r( linearCV[2], DISPGAMMA, L_W, L_B);
// Default output is full range, check if legalRange param was set to true
if (legalRange == 1) {
outputCV = fullRange_to_smpteRange_f3( outputCV);
rOut = outputCV[0];
gOut = outputCV[1];
bOut = outputCV[2];
aOut = aIn;