Hey everybody,
It shouldn't be too hard to get this working as a DCTL until we have native support in DaVinci. I put together a quick showcase for Alexa LogC3 only.
Is there any detailed technical documentation on how to implement this correctly?
* How large are the zones for those "extra stops"?
* What is considered over- or underexposed? The example on the landing page showed clipping in areas where there is still detail.
* How do you derive the luminance channel? In my example, I converted to linear and then AWG to XYZ, using the Y channel to calculate the zones.
* What are the exact RGB values for the zones? I just color-picked them from the webpage for now.
If there's interest, I can add more transfer functions or working spaces like ACES or DaVinciWG - unless that's already in the works?
// Created by Valentin Bernauer
// user inputs
DEFINE_UI_PARAMS(color_space, Working Color Space, DCTLUI_COMBO_BOX, 0, {alexalogc3__alexawidegamut}, {Alexa Log3/Wide Gamut})
__DEVICE__ float3 logc3_to_linear(float3 rgb)
{
const float r = rgb.x > 0.1496582f ? (_powf(10.0f, (rgb.x - 0.385537f) / 0.2471896f) - 0.052272f) / 5.555556f : (rgb.x - 0.092809f) / 5.367655f;
const float g = rgb.y > 0.1496582f ? (_powf(10.0f, (rgb.y - 0.385537f) / 0.2471896f) - 0.052272f) / 5.555556f : (rgb.y - 0.092809f) / 5.367655f;
const float b = rgb.z > 0.1496582f ? (_powf(10.0f, (rgb.z - 0.385537f) / 0.2471896f) - 0.052272f) / 5.555556f : (rgb.z - 0.092809f) / 5.367655f;
return make_float3(r,g,b);
}
// alexawidegamut3rgb_to_xyz
__DEVICE__ float3 alexawidegamut3rgb_to_xyz(float3 rgb)
{
float r = (rgb.x * 0.638008 ) + (rgb.y * 0.214704) + (rgb.z * 0.097744);
float g = (rgb.x * 0.291954 ) + (rgb.y * 0.823841 ) + (rgb.z * -0.115795);
float b = (rgb.x * 0.002798 ) + (rgb.y * -0.067034) + (rgb.z * 1.153294);
return make_float3(r, g, b);
}
__DEVICE__ float3 transform(int p_Width, int p_Height, int p_X, int p_Y, float p_R, float p_G, float p_B)
{
float r = p_R;
float g = p_G;
float b = p_B;
float3 rgb = make_float3(r,g,b);
rgb = logc3_to_linear(rgb);
rgb = alexawidegamut3rgb_to_xyz(rgb);
float Y = rgb.y;
// Exposure stops relative to middle gray (0.18)
#define EV_N10 0.00017578125f // 0.18 * pow(2,-10)
#define EV_N6 0.0028125f // 0.18 * pow(2,-6)
#define EV_N5 0.005625f // 0.18 * pow(2,-5)
#define EV_N4 0.01125f // 0.18 * pow(2,-4)
#define EV_N3 0.0225f // 0.18 * pow(2,-3)
#define EV_N2 0.045f // 0.18 * pow(2,-2)
#define EV_N1 0.090f // 0.18 * pow(2,-1)
#define EV_N05 0.1272792f // 0.18 * pow(2,-0.5)
#define EV_05 0.2545584f // 0.18 * pow(2,0.5)
#define EV_1 0.36f // 0.18 * pow(2,1)
#define EV_2 0.72f // 0.18 * pow(2,2)
#define EV_3 1.44f // 0.18 * pow(2,3)
#define EV_4 2.88f // 0.18 * pow(2,4)
#define EV_5 5.76f // 0.18 * pow(2,5)
#define EV_6 11.52f // 0.18 * pow(2,6)
#define EV_10 184.32f // 0.18 * pow(2,10)
// Zones
if (Y < EV_N10 ){rgb = make_float3(0.0, 0.0, 0.0);}
else if (Y >= EV_N10 && Y < EV_N6 ){rgb = make_float3(0.397, 0.285, 0.618);}
else if (Y >= EV_N6 && Y < EV_N5){rgb = make_float3(0.634, 0.509, 0.742);}
else if (Y >= EV_N5 && Y < EV_N4){rgb = make_float3(0.096, 0.465, 0.666);}
else if (Y >= EV_N4 && Y < EV_N3){rgb = make_float3(0.160, 0.698, 0.915);}
else if (Y >= EV_N3 && Y < EV_N2){rgb = make_float3(0.112, 0.670, 0.297);}
else if (Y >= EV_N2 && Y < EV_N1){rgb = make_float3(0.372, 0.748, 0.285);}
else if (Y >= EV_N1 && Y < EV_N05){rgb = make_float3(0.594, 0.802, 0.253);}
else if (Y >= EV_N05 && Y < EV_05){rgb = make_float3(0.5, 0.5, 0.5);}
else if (Y >= EV_05 && Y < EV_1){rgb = make_float3(1.0, 0.931, 0.04);}
else if (Y >= EV_1 && Y < EV_2){rgb = make_float3(1.0, 0.995, 0.670);}
else if (Y >= EV_2 && Y < EV_3){rgb = make_float3(0.978, 0.445, 0.168);}
else if (Y >= EV_3 && Y < EV_4){rgb = make_float3(0.991, 0.677, 0.288);}
else if (Y >= EV_4 && Y < EV_5){rgb = make_float3(0.955, 0.112, 0.148);}
else if (Y >= EV_5 && Y < EV_6){rgb = make_float3(0.911, 0.505, 0.562);}
else if (Y >= EV_6 && Y < EV_10){rgb = make_float3(0.975, 0.762, 0.770);}
else if (Y > EV_10 ){rgb = make_float3(1.0, 1.0, 1.0);}
return rgb;
}