dotfiles/mpv/shaders/hdr-toys/tone-mapping/bt2446a.glsl
2025-05-26 00:03:04 +10:00

142 lines
3 KiB
GLSL

// ITU-R BT.2446 Conversion Method A
// https://www.itu.int/pub/R-REP-BT.2446
//!PARAM max_luma
//!TYPE float
0.0
//!PARAM max_cll
//!TYPE float
0.0
//!PARAM reference_white
//!TYPE float
//!MINIMUM 0.0
//!MAXIMUM 1000.0
203.0
//!HOOK OUTPUT
//!BIND HOOKED
//!DESC tone mapping (bt.2446a)
const vec3 y_coef = vec3(0.2627002120112671, 0.6779980715188708, 0.05930171646986196);
const float a = y_coef.r;
const float b = y_coef.g;
const float c = y_coef.b;
const float d = 2.0 * (1.0 - c);
const float e = 2.0 * (1.0 - a);
vec3 RGB_to_YCbCr(vec3 RGB) {
return RGB * mat3(
a, b, c,
-a / d, -b / d, 0.5,
0.5, -b / e, -c / e
);
}
vec3 YCbCr_to_RGB(vec3 YCbCr) {
return YCbCr * mat3(
1.0, 0.0, e,
1.0, -c / b * d, -a / b * e,
1.0, d, 0.0
);
}
float get_max_l() {
if (max_cll > 0.0)
return max_cll;
if (max_luma > 0.0)
return max_luma;
return 1000.0;
}
float f(float Y) {
Y = pow(Y, 1.0 / 2.4);
float pHDR = 1.0 + 32.0 * pow(get_max_l() / 10000.0, 1.0 / 2.4);
float pSDR = 1.0 + 32.0 * pow(reference_white / 10000.0, 1.0 / 2.4);
float Yp = log(1.0 + (pHDR - 1.0) * Y) / log(pHDR);
float Yc;
if (Yp <= 0.7399) Yc = Yp * 1.0770;
else if (Yp < 0.9909) Yc = Yp * (-1.1510 * Yp + 2.7811) - 0.6302;
else Yc = Yp * 0.5000 + 0.5000;
float Ysdr = (pow(pSDR, Yc) - 1.0) / (pSDR - 1.0);
Y = pow(Ysdr, 2.4);
return Y;
}
float curve(float Y) {
return f(Y);
}
vec3 tone_mapping(vec3 YCbCr) {
YCbCr /= get_max_l() / reference_white;
float Y = YCbCr.r;
float Cb = YCbCr.g;
float Cr = YCbCr.b;
float Ysdr = curve(Y);
float Yr = Ysdr / max(1.1 * Y, 1e-6);
Cb *= Yr;
Cr *= Yr;
Y = Ysdr - max(0.1 * Cr, 0.0);
return vec3(Y, Cb, Cr);
}
vec4 hook() {
vec4 color = HOOKED_tex(HOOKED_pos);
color.rgb = RGB_to_YCbCr(color.rgb);
color.rgb = tone_mapping(color.rgb);
color.rgb = YCbCr_to_RGB(color.rgb);
return color;
}
//!HOOK OUTPUT
//!BIND HOOKED
//!DESC black point compensation
// https://www.color.org/WP40-Black_Point_Compensation_2010-07-27.pdf
vec3 RGB_to_XYZ(vec3 RGB) {
return RGB * mat3(
0.6369580483012914, 0.14461690358620832, 0.1688809751641721,
0.2627002120112671, 0.6779980715188708, 0.05930171646986196,
0.000000000000000, 0.028072693049087428, 1.060985057710791
);
}
vec3 XYZ_to_RGB(vec3 XYZ) {
return XYZ * mat3(
1.716651187971268, -0.355670783776392, -0.253366281373660,
-0.666684351832489, 1.616481236634939, 0.0157685458139111,
0.017639857445311, -0.042770613257809, 0.942103121235474
);
}
vec3 black_point_compensation(vec3 XYZ, float s, float d) {
float r = (1.0 - d) / (1.0 - s);
return r * XYZ + (1.0 - r) * RGB_to_XYZ(vec3(1.0));
}
vec4 hook() {
vec4 color = HOOKED_tex(HOOKED_pos);
color.rgb = RGB_to_XYZ(color.rgb);
color.rgb = black_point_compensation(color.rgb, 0.0, 0.001);
color.rgb = XYZ_to_RGB(color.rgb);
return color;
}