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

325 lines
10 KiB
GLSL

// Visualizes the image using false color
// You can preview the colors in Visual Studio Code by the following plugin
// https://marketplace.visualstudio.com/items?itemName=naumovs.color-highlight
//!PARAM mode
//!TYPE ENUM int
luminance
exposure
//!PARAM reference_white
//!TYPE float
//!MINIMUM 0.0
//!MAXIMUM 1000.0
203.0
//!HOOK OUTPUT
//!BIND HOOKED
//!WHEN mode 0 =
//!DESC tone mapping (false color, luminance)
// oklch(0.99500 0.00 000.0) >10000 nits
// oklch(0.94659 0.11 005.0) 10000 nits
// oklch(0.83878 0.33 025.0) 4000 nits
// oklch(0.73097 0.33 090.0) 2000 nits
// oklch(0.52324 0.33 130.0) 1000 nits
// oklch(0.33922 0.24 245.0) brighter than SDR
// oklch(0.56925 0.00 000.0) SDR
// oklch(0.20104 0.16 350.0) darker than SDR
// oklch(0.13040 0.08 350.0) 0nits
float cbrt(float x) {
return sign(x) * pow(abs(x), 1.0 / 3.0);
}
vec3 cbrt(vec3 color) {
return vec3(
cbrt(color.x),
cbrt(color.y),
cbrt(color.z)
);
}
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 XYZ_to_LMS(vec3 XYZ) {
return XYZ * mat3(
0.8190224379967030, 0.3619062600528904, -0.1288737815209879,
0.0329836539323885, 0.9292868615863434, 0.0361446663506424,
0.0481771893596242, 0.2642395317527308, 0.6335478284694309
);
}
vec3 LMS_to_XYZ(vec3 LMS) {
return LMS * mat3(
1.2268798758459243, -0.5578149944602171, 0.2813910456659647,
-0.0405757452148008, 1.1122868032803170, -0.0717110580655164,
-0.0763729366746601, -0.4214933324022432, 1.5869240198367816
);
}
vec3 LMS_to_Lab(vec3 LMS) {
return LMS * mat3(
0.2104542683093140, 0.7936177747023054, -0.0040720430116193,
1.9779985324311684, -2.4285922420485799, 0.4505937096174110,
0.0259040424655478, 0.7827717124575296, -0.8086757549230774
);
}
vec3 Lab_to_LMS(vec3 Lab) {
return Lab * mat3(
1.0000000000000000, 0.3963377773761749, 0.2158037573099136,
1.0000000000000000, -0.1055613458156586, -0.0638541728258133,
1.0000000000000000, -0.0894841775298119, -1.2914855480194092
);
}
vec3 RGB_to_Lab(vec3 color) {
color = RGB_to_XYZ(color);
color = XYZ_to_LMS(color);
color = cbrt(color);
color = LMS_to_Lab(color);
return color;
}
vec3 Lab_to_RGB(vec3 color) {
color = Lab_to_LMS(color);
color = pow(color, vec3(3.0));
color = LMS_to_XYZ(color);
color = XYZ_to_RGB(color);
return color;
}
const float epsilon = 1e-6;
vec3 Lab_to_LCh(vec3 Lab) {
float L = Lab.x;
float a = Lab.y;
float b = Lab.z;
float C = length(vec2(a, b));
float h = (abs(a) < epsilon && abs(b) < epsilon) ? 0.0 : atan(b, a);
return vec3(L, C, h);
}
vec3 LCh_to_Lab(vec3 LCh) {
float L = LCh.x;
float C = LCh.y;
float h = LCh.z;
C = max(C, 0.0);
float a = C * cos(h);
float b = C * sin(h);
return vec3(L, a, b);
}
float l(float x, float a, float b) {
float y = (x - a) / (b - a);
return clamp(y , 0.0, 1.0);
}
vec4 hook() {
vec4 color = HOOKED_tex(HOOKED_pos);
float y = RGB_to_XYZ(color.rgb).y * reference_white;
float l5 = 10000.0;
float l4 = 4000.0;
float l3 = 2000.0;
float l2 = 1000.0;
float l1 = reference_white;
float l0 = reference_white / 1000.0;
float lb = 0.0;
vec3 cw = vec3(0.99500, 0.00, radians(000.0));
vec3 c5 = vec3(0.94659, 0.11, radians(005.0));
vec3 c4 = vec3(0.83878, 0.33, radians(025.0));
vec3 c3 = vec3(0.73097, 0.33, radians(090.0));
vec3 c2 = vec3(0.52324, 0.33, radians(130.0));
vec3 c1 = vec3(0.33922, 0.24, radians(245.0));
vec3 c0 = vec3(0.20104, 0.16, radians(350.0));
vec3 cb = vec3(0.13040, 0.08, radians(350.0));
if (y > l5) color.rgb = Lab_to_RGB(LCh_to_Lab(cw));
else if (y > l4) color.rgb = Lab_to_RGB(LCh_to_Lab(mix(c4, c5, l(y, l4, l5))));
else if (y > l3) color.rgb = Lab_to_RGB(LCh_to_Lab(mix(c3, c4, l(y, l3, l4))));
else if (y > l2) color.rgb = Lab_to_RGB(LCh_to_Lab(mix(c2, c3, l(y, l2, l3))));
else if (y > l1) color.rgb = Lab_to_RGB(LCh_to_Lab(mix(c1, c2, l(y, l1, l2))));
else if (y > l0) color.rgb = vec3(l(y, l0, l1));
else color.rgb = Lab_to_RGB(LCh_to_Lab(mix(cb, c0, l(y, lb, l0))));
return color;
}
//!HOOK OUTPUT
//!BIND HOOKED
//!WHEN mode 1 =
//!DESC tone mapping (false color, exposure)
// Inspired by the Ansel Adams' Zone System
// https://en.wikipedia.org/wiki/Zone_System#Zones_as_tone_and_texture
// Expanded exposure stops based on the de facto devices' dynamic range
// oklch(0.99500 0.00 000.0) overexposure
// oklch(0.94659 0.11 005.0) +7 stops
// oklch(0.89269 0.22 015.0) +6 stops
// oklch(0.83878 0.33 025.0) +5 stops
// oklch(0.78487 0.11 060.0) +4 stops
// oklch(0.73097 0.33 090.0) +3 stops
// oklch(0.67706 0.22 105.0) +2 stops
// oklch(0.62315 0.11 120.0) +1 stop
// oklch(0.56925 0.00 000.0) middle gray
// oklch(0.52324 0.33 130.0) -1 stop
// oklch(0.47724 0.22 145.0) -2 stops
// oklch(0.43123 0.11 160.0) -3 stops
// oklch(0.38523 0.32 220.0) -4 stops
// oklch(0.33922 0.24 245.0) -5 stops
// oklch(0.29322 0.24 290.0) -6 stops
// oklch(0.24721 0.16 320.0) -7 stops
// oklch(0.20104 0.08 350.0) -8 stops
// oklch(0.13040 0.00 000.0) underexposure
float cbrt(float x) {
return sign(x) * pow(abs(x), 1.0 / 3.0);
}
vec3 cbrt(vec3 color) {
return vec3(
cbrt(color.x),
cbrt(color.y),
cbrt(color.z)
);
}
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 XYZ_to_LMS(vec3 XYZ) {
return XYZ * mat3(
0.8190224379967030, 0.3619062600528904, -0.1288737815209879,
0.0329836539323885, 0.9292868615863434, 0.0361446663506424,
0.0481771893596242, 0.2642395317527308, 0.6335478284694309
);
}
vec3 LMS_to_XYZ(vec3 LMS) {
return LMS * mat3(
1.2268798758459243, -0.5578149944602171, 0.2813910456659647,
-0.0405757452148008, 1.1122868032803170, -0.0717110580655164,
-0.0763729366746601, -0.4214933324022432, 1.5869240198367816
);
}
vec3 LMS_to_Lab(vec3 LMS) {
return LMS * mat3(
0.2104542683093140, 0.7936177747023054, -0.0040720430116193,
1.9779985324311684, -2.4285922420485799, 0.4505937096174110,
0.0259040424655478, 0.7827717124575296, -0.8086757549230774
);
}
vec3 Lab_to_LMS(vec3 Lab) {
return Lab * mat3(
1.0000000000000000, 0.3963377773761749, 0.2158037573099136,
1.0000000000000000, -0.1055613458156586, -0.0638541728258133,
1.0000000000000000, -0.0894841775298119, -1.2914855480194092
);
}
vec3 RGB_to_Lab(vec3 color) {
color = RGB_to_XYZ(color);
color = XYZ_to_LMS(color);
color = cbrt(color);
color = LMS_to_Lab(color);
return color;
}
vec3 Lab_to_RGB(vec3 color) {
color = Lab_to_LMS(color);
color = pow(color, vec3(3.0));
color = LMS_to_XYZ(color);
color = XYZ_to_RGB(color);
return color;
}
const float epsilon = 1e-6;
vec3 Lab_to_LCh(vec3 Lab) {
float L = Lab.x;
float a = Lab.y;
float b = Lab.z;
float C = length(vec2(a, b));
float h = (abs(a) < epsilon && abs(b) < epsilon) ? 0.0 : atan(b, a);
return vec3(L, C, h);
}
vec3 LCh_to_Lab(vec3 LCh) {
float L = LCh.x;
float C = LCh.y;
float h = LCh.z;
C = max(C, 0.0);
float a = C * cos(h);
float b = C * sin(h);
return vec3(L, a, b);
}
vec4 hook() {
vec4 color = HOOKED_tex(HOOKED_pos);
float stops = log2(max(RGB_to_XYZ(color.rgb).y, 1e-6) / 0.18);
if (stops >= 7.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.99500, 0.00, radians(000.0))));
else if (stops >= 6.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.94659, 0.11, radians(005.0))));
else if (stops >= 5.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.89269, 0.22, radians(015.0))));
else if (stops >= 4.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.83878, 0.33, radians(025.0))));
else if (stops >= 3.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.78487, 0.11, radians(060.0))));
else if (stops >= 2.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.73097, 0.33, radians(090.0))));
else if (stops >= 1.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.67706, 0.22, radians(105.0))));
else if (stops >= 0.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.62315, 0.11, radians(120.0))));
else if (stops >= -0.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.56925, 0.00, radians(000.0))));
else if (stops >= -1.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.52324, 0.33, radians(130.0))));
else if (stops >= -2.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.47724, 0.22, radians(145.0))));
else if (stops >= -3.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.43123, 0.11, radians(160.0))));
else if (stops >= -4.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.38523, 0.32, radians(220.0))));
else if (stops >= -5.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.33922, 0.24, radians(245.0))));
else if (stops >= -6.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.29322, 0.24, radians(290.0))));
else if (stops >= -7.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.24721, 0.16, radians(320.0))));
else if (stops >= -8.5) color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.20104, 0.08, radians(350.0))));
else color.rgb = Lab_to_RGB(LCh_to_Lab(vec3(0.13040, 0.00, radians(000.0))));
return color;
}