Update mpv config:
This commit is contained in:
parent
64e685695e
commit
d1e0b97d62
36 changed files with 5555 additions and 10 deletions
346
mpv/shaders/hdr-toys/tone-mapping/aces.glsl
Normal file
346
mpv/shaders/hdr-toys/tone-mapping/aces.glsl
Normal file
|
@ -0,0 +1,346 @@
|
|||
// The Academy Color Encoding System (ACES)
|
||||
// https://github.com/ampas/aces-core/tree/v1.3.1
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!DESC tone mapping (aces)
|
||||
|
||||
const float TINY = 1e-5;
|
||||
const float HALF_POS_INF = 31744.0;
|
||||
|
||||
// Gamut Compress Parameters
|
||||
const float LIM_CYAN = 1.147;
|
||||
const float LIM_MAGENTA = 1.264;
|
||||
const float LIM_YELLOW = 1.312;
|
||||
|
||||
const float THR_CYAN = 0.815;
|
||||
const float THR_MAGENTA = 0.803;
|
||||
const float THR_YELLOW = 0.880;
|
||||
|
||||
const float PWR = 1.2;
|
||||
|
||||
// "Glow" module constants
|
||||
const float RRT_GLOW_GAIN = 0.05;
|
||||
const float RRT_GLOW_MID = 0.08;
|
||||
|
||||
// Red modifier constants
|
||||
const float RRT_RED_SCALE = 0.82;
|
||||
const float RRT_RED_PIVOT = 0.03;
|
||||
const float RRT_RED_HUE = 0.0;
|
||||
const float RRT_RED_WIDTH = 135.0;
|
||||
|
||||
// Desaturation constants
|
||||
const float RRT_SAT_FACTOR = 0.96;
|
||||
const float ODT_SAT_FACTOR = 0.93;
|
||||
|
||||
// Gamma compensation factor
|
||||
const float DIM_SURROUND_GAMMA = 0.9811;
|
||||
|
||||
|
||||
const mat3 RGB_to_XYZ = mat3(
|
||||
0.6369580483012914, 0.14461690358620832, 0.1688809751641721,
|
||||
0.2627002120112671, 0.6779980715188708, 0.05930171646986196,
|
||||
0.000000000000000, 0.028072693049087428, 1.060985057710791
|
||||
);
|
||||
|
||||
const mat3 XYZ_to_RGB = mat3(
|
||||
1.716651187971268, -0.355670783776392, -0.253366281373660,
|
||||
-0.666684351832489, 1.616481236634939, 0.0157685458139111,
|
||||
0.017639857445311, -0.042770613257809, 0.942103121235474
|
||||
);
|
||||
|
||||
const mat3 AP0_to_XYZ = mat3(
|
||||
0.9525523959, 0.0000000000, 0.0000936786,
|
||||
0.3439664498, 0.7281660966, -0.0721325464,
|
||||
0.0000000000, 0.0000000000, 1.0088251844
|
||||
);
|
||||
|
||||
const mat3 XYZ_to_AP0 = mat3(
|
||||
1.0498110175, 0.0000000000, -0.0000974845,
|
||||
-0.4959030231, 1.3733130458, 0.0982400361,
|
||||
0.0000000000, 0.0000000000, 0.9912520182
|
||||
);
|
||||
|
||||
const mat3 AP1_to_XYZ = mat3(
|
||||
0.6624541811, 0.1340042065, 0.1561876870,
|
||||
0.2722287168, 0.6740817658, 0.0536895174,
|
||||
-0.0055746495, 0.0040607335, 1.0103391003
|
||||
);
|
||||
|
||||
const mat3 XYZ_to_AP1 = mat3(
|
||||
1.6410233797, -0.3248032942, -0.2364246952,
|
||||
-0.6636628587, 1.6153315917, 0.0167563477,
|
||||
0.0117218943, -0.0082844420, 0.9883948585
|
||||
);
|
||||
|
||||
const vec3 LUMINANCE_AP1 = vec3(0.2722287168, 0.6740817658, 0.0536895174);
|
||||
|
||||
const mat3 D60_to_D65_CAT = mat3(
|
||||
0.987224, -0.00611327, 0.0159533,
|
||||
-0.00759836, 1.00186, 0.00533002,
|
||||
0.00307257, -0.00509595, 1.08168
|
||||
);
|
||||
|
||||
const mat3 D65_to_D60_CAT = mat3(
|
||||
1.0130349238541335252, 0.0061053088545854651618, -0.014970963195236360098,
|
||||
0.0076982295895192892886, 0.9981648317745535941, -0.0050320341346474782061,
|
||||
-0.0028413125165573776196, 0.0046851555780399034147, 0.92450665292696206889
|
||||
);
|
||||
|
||||
// Power compression function
|
||||
// https://www.desmos.com/calculator/iwcyjg6av0
|
||||
float compress(float dist, float lim, float thr, float pwr) {
|
||||
float scl = (lim - thr) / pow(pow((1.0 - thr) / (lim - thr), -pwr) - 1.0, 1.0 / pwr);
|
||||
float c = thr + (dist - thr) / (pow(1.0 + pow((dist - thr) / scl, pwr), 1.0 / pwr));
|
||||
return (dist < thr ? dist : c);
|
||||
}
|
||||
|
||||
vec3 reference_gamut_compress(vec3 rgb) {
|
||||
// Achromatic axis
|
||||
float ac = max(max(rgb.r, rgb.g), rgb.b);
|
||||
|
||||
// Inverse RGB Ratios: distance from achromatic axis
|
||||
vec3 d = ac == 0.0 ? vec3(0.0) : (ac - rgb) / abs(ac);
|
||||
|
||||
// Compressed distance
|
||||
vec3 cd = vec3(
|
||||
compress(d.x, LIM_CYAN, THR_CYAN, PWR),
|
||||
compress(d.y, LIM_MAGENTA, THR_MAGENTA, PWR),
|
||||
compress(d.z, LIM_YELLOW, THR_YELLOW, PWR)
|
||||
);
|
||||
|
||||
// Inverse RGB Ratios to RGB
|
||||
vec3 crgb = ac - cd * abs(ac);
|
||||
|
||||
return crgb;
|
||||
}
|
||||
|
||||
float rgb_to_saturation(vec3 rgb) {
|
||||
float mi = min(min(rgb.r, rgb.g), rgb.b);
|
||||
float ma = max(max(rgb.r, rgb.g), rgb.b);
|
||||
return (max(ma, TINY) - max(mi, TINY)) / max(ma, 1e-2);
|
||||
}
|
||||
|
||||
// Converts RGB to a luminance proxy, here called YC
|
||||
// YC is ~ Y + K * Chroma
|
||||
// Constant YC is a cone-shaped surface in RGB space, with the tip on the
|
||||
// neutral axis, towards white.
|
||||
// YC is normalized: RGB 1 1 1 maps to YC = 1
|
||||
//
|
||||
// ycRadiusWeight defaults to 1.75, although can be overridden in function
|
||||
// call to rgb_to_yc
|
||||
// ycRadiusWeight = 1 -> YC for pure cyan, magenta, yellow == YC for neutral
|
||||
// of same value
|
||||
// ycRadiusWeight = 2 -> YC for pure red, green, blue == YC for neutral of
|
||||
// same value.
|
||||
float rgb_to_yc(vec3 rgb) {
|
||||
float ycRadiusWeight = 1.75;
|
||||
|
||||
float r = rgb.r;
|
||||
float g = rgb.g;
|
||||
float b = rgb.b;
|
||||
|
||||
float chroma = sqrt(b * (b - g) + g * (g - r) + r * (r - b));
|
||||
|
||||
return (b + g + r + ycRadiusWeight * chroma) / 3.0;
|
||||
}
|
||||
|
||||
// Sigmoid function in the range 0 to 1 spanning -2 to +2.
|
||||
float sigmoid_shaper(float x) {
|
||||
float t = max(1.0 - abs(x / 2.0), 0.0);
|
||||
float y = 1.0 + sign(x) * (1.0 - t * t);
|
||||
return y / 2.0;
|
||||
}
|
||||
|
||||
float glow_fwd(float ycIn, float glowGainIn, float glowMid) {
|
||||
float glowGainOut;
|
||||
|
||||
if (ycIn <= 2.0 / 3.0 * glowMid) {
|
||||
glowGainOut = glowGainIn;
|
||||
} else if ( ycIn >= 2.0 * glowMid) {
|
||||
glowGainOut = 0.0;
|
||||
} else {
|
||||
glowGainOut = glowGainIn * (glowMid / ycIn - 1.0 / 2.0);
|
||||
}
|
||||
|
||||
return glowGainOut;
|
||||
}
|
||||
|
||||
// Returns a geometric hue angle in degrees (0-360) based on RGB values.
|
||||
// For neutral colors, hue is undefined and the function will return a quiet NaN value.
|
||||
float rgb_to_hue(vec3 rgb) {
|
||||
// RGB triplets where RGB are equal have an undefined hue
|
||||
float hue = 0.0;
|
||||
|
||||
if (!(rgb.x == rgb.y && rgb.y == rgb.z)) {
|
||||
float x = sqrt(3.0) * (rgb.y - rgb.z);
|
||||
float y = 2.0 * rgb.x - rgb.y - rgb.z;
|
||||
hue = degrees(atan(y, x));
|
||||
}
|
||||
|
||||
return (hue < 0.0) ? hue + 360.0 : hue;
|
||||
}
|
||||
|
||||
float center_hue(float hue, float centerH) {
|
||||
float hueCentered = hue - centerH;
|
||||
if (hueCentered < -180.0) {
|
||||
hueCentered = hueCentered + 360.0;
|
||||
} else if (hueCentered > 180.0) {
|
||||
hueCentered = hueCentered - 360.0;
|
||||
}
|
||||
return hueCentered;
|
||||
}
|
||||
|
||||
// Fitting of RRT + ODT (RGB monitor 100 nits dim) from:
|
||||
// https://github.com/colour-science/colour-unity/blob/master/Assets/Colour/Notebooks/CIECAM02_Unity.ipynb
|
||||
// RMSE: 0.0012846272106
|
||||
vec3 tonescale(vec3 ap1) {
|
||||
float a = 2.785085;
|
||||
float b = 0.107772;
|
||||
float c = 2.936045;
|
||||
float d = 0.887122;
|
||||
float e = 0.806889;
|
||||
return (ap1 * (a * ap1 + b)) / (ap1 * (c * ap1 + d) + e);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_xyY(vec3 XYZ) {
|
||||
float X = XYZ.x;
|
||||
float Y = XYZ.y;
|
||||
float Z = XYZ.z;
|
||||
|
||||
float divisor = X + Y + Z;
|
||||
if (divisor == 0.0) divisor = 1e-6;
|
||||
|
||||
float x = X / divisor;
|
||||
float y = Y / divisor;
|
||||
|
||||
return vec3(x, y, Y);
|
||||
}
|
||||
|
||||
vec3 xyY_to_XYZ(vec3 xyY) {
|
||||
float x = xyY.x;
|
||||
float y = xyY.y;
|
||||
float Y = xyY.z;
|
||||
|
||||
float multiplo = Y / max(y, 1e-6);
|
||||
|
||||
float z = 1.0 - x - y;
|
||||
float X = x * multiplo;
|
||||
float Z = z * multiplo;
|
||||
|
||||
return vec3(X, Y, Z);
|
||||
}
|
||||
|
||||
vec3 darkSurround_to_dimSurround(vec3 linearCV) {
|
||||
vec3 XYZ = linearCV * AP1_to_XYZ;
|
||||
vec3 xyY = XYZ_to_xyY(XYZ);
|
||||
|
||||
xyY.z = clamp(xyY.z, 0.0, HALF_POS_INF);
|
||||
xyY.z = pow(xyY.z, DIM_SURROUND_GAMMA);
|
||||
|
||||
XYZ = xyY_to_XYZ(xyY);
|
||||
return XYZ * XYZ_to_AP1;
|
||||
}
|
||||
|
||||
vec3 ACES(vec3 color) {
|
||||
vec3 ap0;
|
||||
vec3 ap1;
|
||||
vec3 cv;
|
||||
|
||||
// Look Modification Transforms (LMTs)
|
||||
ap1 = color * RGB_to_XYZ * D65_to_D60_CAT * XYZ_to_AP1;
|
||||
|
||||
ap1 = reference_gamut_compress(ap1);
|
||||
|
||||
ap0 = ap1 * AP1_to_XYZ * XYZ_to_AP0;
|
||||
|
||||
|
||||
// Reference Rendering Transform (RRT)
|
||||
|
||||
// Glow module
|
||||
float saturation = rgb_to_saturation(ap0);
|
||||
float ycIn = rgb_to_yc(ap0);
|
||||
float s = sigmoid_shaper((saturation - 0.4) / 0.2);
|
||||
float addedGlow = 1.0 + glow_fwd(ycIn, RRT_GLOW_GAIN * s, RRT_GLOW_MID);
|
||||
ap0 *= addedGlow;
|
||||
|
||||
// Red modifier
|
||||
float hue = rgb_to_hue(ap0);
|
||||
float centeredHue = center_hue(hue, RRT_RED_HUE);
|
||||
// hueWeight = cubic_basis_shaper(centeredHue, RRT_RED_WIDTH);
|
||||
float hueWeight = smoothstep(0.0, 1.0, 1.0 - abs(2.0 * centeredHue / RRT_RED_WIDTH));
|
||||
hueWeight *= hueWeight;
|
||||
|
||||
ap0.r += hueWeight * saturation * (RRT_RED_PIVOT - ap0.r) * (1.0 - RRT_RED_SCALE);
|
||||
|
||||
// ACES to RGB rendering space
|
||||
ap1 = ap0 * AP0_to_XYZ * XYZ_to_AP1;
|
||||
|
||||
// avoids saturated negative colors from becoming positive in the matrix
|
||||
ap1 = clamp(ap1, 0.0, HALF_POS_INF);
|
||||
|
||||
// Global desaturation
|
||||
ap1 = mix(vec3(dot(ap1, LUMINANCE_AP1)), ap1, RRT_SAT_FACTOR);
|
||||
|
||||
|
||||
// Output Device Transform (ODT)
|
||||
|
||||
// Apply the tonescale independently in rendering-space RGB
|
||||
ap1 = tonescale(ap1);
|
||||
|
||||
// Apply gamma adjustment to compensate for dim surround
|
||||
cv = darkSurround_to_dimSurround(ap1);
|
||||
|
||||
// Apply desaturation to compensate for luminance difference
|
||||
cv = mix(vec3(dot(cv, LUMINANCE_AP1)), cv, ODT_SAT_FACTOR);
|
||||
|
||||
// Convert to display primary encoding
|
||||
cv = cv * AP1_to_XYZ * D60_to_D65_CAT * XYZ_to_RGB;
|
||||
|
||||
return cv;
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = ACES(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;
|
||||
}
|
936
mpv/shaders/hdr-toys/tone-mapping/astra.glsl
Normal file
936
mpv/shaders/hdr-toys/tone-mapping/astra.glsl
Normal file
|
@ -0,0 +1,936 @@
|
|||
// Astra, a tone mapping operator designed to preserve the creator's intent
|
||||
|
||||
// shoulder segment: http://filmicworlds.com/blog/filmic-tonemapping-with-piecewise-power-curves/
|
||||
// toe segment: https://technorgb.blogspot.com/2018/02/hyperbola-tone-mapping.html
|
||||
// working space: https://doi.org/10.1364/OE.25.015131
|
||||
// hk effect: https://doi.org/10.1364/OE.534073
|
||||
// chroma correction: https://www.itu.int/pub/R-REP-BT.2408
|
||||
// dynamic metadata: https://github.com/mpv-player/mpv/pull/15239
|
||||
// fast gaussian blur: https://www.rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/
|
||||
|
||||
//!PARAM min_luma
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_luma
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_cll
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_fall
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_r
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_g
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_b
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_avg
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_pq_y
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM avg_pq_y
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM reference_white
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1000.0
|
||||
203.0
|
||||
|
||||
//!PARAM auto_exposure_anchor
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1.0
|
||||
0.75
|
||||
|
||||
//!PARAM hk_effect_compensate_scaling
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1.0
|
||||
1.0
|
||||
|
||||
//!PARAM chroma_correction_scaling
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1.0
|
||||
1.0
|
||||
|
||||
//!PARAM spatial_stable_iterations
|
||||
//!TYPE uint
|
||||
//!MINIMUM 0
|
||||
//!MAXIMUM 8
|
||||
2
|
||||
|
||||
//!PARAM temporal_stable_frames
|
||||
//!TYPE uint
|
||||
//!MINIMUM 0
|
||||
//!MAXIMUM 120
|
||||
8
|
||||
|
||||
//!PARAM enable_metering
|
||||
//!TYPE uint
|
||||
//!MINIMUM 0
|
||||
//!MAXIMUM 1
|
||||
1
|
||||
|
||||
//!PARAM preview_metering
|
||||
//!TYPE uint
|
||||
//!MINIMUM 0
|
||||
//!MAXIMUM 1
|
||||
0
|
||||
|
||||
//!BUFFER METERED
|
||||
//!VAR uint metered_max_i
|
||||
//!STORAGE
|
||||
|
||||
//!BUFFER METERED_TEMPORAL
|
||||
//!VAR uint metered_max_i_t[128]
|
||||
//!STORAGE
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!SAVE METERING
|
||||
//!COMPONENTS 1
|
||||
//!WIDTH 512
|
||||
//!HEIGHT 288
|
||||
//!WHEN enable_metering 0 > max_pq_y 0 = * scene_max_r 0 = * scene_max_g 0 = * scene_max_b 0 = *
|
||||
//!DESC metering (feature map)
|
||||
|
||||
const vec3 y_coef = vec3(0.2627002120112671, 0.6779980715188708, 0.05930171646986196);
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
float l = dot(color.rgb * reference_white, y_coef);
|
||||
float i = pq_eotf_inv(l);
|
||||
return vec4(i, vec3(0.0));
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 0 >
|
||||
//!DESC metering (spatial stabilization, blur, horizonal)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(1.0, 0.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 0 >
|
||||
//!DESC metering (spatial stabilization, blur, vertical)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(0.0, 1.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 1 >
|
||||
//!DESC metering (spatial stabilization, blur, horizonal)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(1.0, 0.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 1 >
|
||||
//!DESC metering (spatial stabilization, blur, vertical)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(0.0, 1.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 2 >
|
||||
//!DESC metering (spatial stabilization, blur, horizonal)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(1.0, 0.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 2 >
|
||||
//!DESC metering (spatial stabilization, blur, vertical)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(0.0, 1.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 3 >
|
||||
//!DESC metering (spatial stabilization, blur, horizonal)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(1.0, 0.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 3 >
|
||||
//!DESC metering (spatial stabilization, blur, vertical)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(0.0, 1.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 4 >
|
||||
//!DESC metering (spatial stabilization, blur, horizonal)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(1.0, 0.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 4 >
|
||||
//!DESC metering (spatial stabilization, blur, vertical)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(0.0, 1.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 5 >
|
||||
//!DESC metering (spatial stabilization, blur, horizonal)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(1.0, 0.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 5 >
|
||||
//!DESC metering (spatial stabilization, blur, vertical)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(0.0, 1.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 6 >
|
||||
//!DESC metering (spatial stabilization, blur, horizonal)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(1.0, 0.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 6 >
|
||||
//!DESC metering (spatial stabilization, blur, vertical)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(0.0, 1.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 7 >
|
||||
//!DESC metering (spatial stabilization, blur, horizonal)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(1.0, 0.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!SAVE METERING
|
||||
//!WHEN spatial_stable_iterations 7 >
|
||||
//!DESC metering (spatial stabilization, blur, vertical)
|
||||
|
||||
const vec4 offset = vec4(0.0, 1.411764705882353, 3.2941176470588234, 5.176470588235294);
|
||||
const vec4 weight = vec4(0.1964825501511404, 0.2969069646728344, 0.09447039785044732, 0.010381362401148057);
|
||||
const vec2 direction = vec2(0.0, 1.0);
|
||||
|
||||
vec4 hook(){
|
||||
uint i = 0;
|
||||
vec4 c = METERING_texOff(offset[i]) * weight[i];
|
||||
for (i = 1; i < 4; i++) {
|
||||
c += METERING_texOff( direction * offset[i]) * weight[i];
|
||||
c += METERING_texOff(-direction * offset[i]) * weight[i];
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!BIND METERED
|
||||
//!SAVE EMPTY
|
||||
//!COMPUTE 32 32
|
||||
//!DESC metering (data, max)
|
||||
|
||||
shared uint local_max;
|
||||
|
||||
void hook() {
|
||||
if (gl_GlobalInvocationID.x == 0 && gl_GlobalInvocationID.y == 0) {
|
||||
metered_max_i = 0;
|
||||
}
|
||||
|
||||
if (gl_LocalInvocationIndex == 0) {
|
||||
local_max = 0;
|
||||
}
|
||||
|
||||
memoryBarrierShared();
|
||||
barrier();
|
||||
|
||||
float value = METERING_tex(METERING_pos).x;
|
||||
uint rounded = uint(value * 4095.0 + 0.5);
|
||||
atomicMax(local_max, rounded);
|
||||
|
||||
memoryBarrierShared();
|
||||
barrier();
|
||||
|
||||
if (gl_LocalInvocationIndex == 0) {
|
||||
atomicMax(metered_max_i, local_max);
|
||||
}
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND METERING
|
||||
//!BIND METERED
|
||||
//!BIND METERED_TEMPORAL
|
||||
//!SAVE EMPTY
|
||||
//!WIDTH 1
|
||||
//!HEIGHT 1
|
||||
//!COMPUTE 1 1
|
||||
//!WHEN temporal_stable_frames
|
||||
//!DESC metering (temporal stabilization)
|
||||
|
||||
void temporal_prepend() {
|
||||
for (uint i = temporal_stable_frames - 1; i > 0; i--) {
|
||||
metered_max_i_t[i] = metered_max_i_t[i - 1];
|
||||
}
|
||||
metered_max_i_t[0] = metered_max_i;
|
||||
}
|
||||
|
||||
float temporal_harmonic_mean() {
|
||||
float sum = 0.0;
|
||||
for (uint i = 0; i < temporal_stable_frames; i++) {
|
||||
float current = float(metered_max_i_t[i]);
|
||||
sum += 1.0 / max(current, 1e-6);
|
||||
}
|
||||
return temporal_stable_frames / sum;
|
||||
}
|
||||
|
||||
void temporal_fill() {
|
||||
for (uint i = 0; i < temporal_stable_frames; i++) {
|
||||
metered_max_i_t[i] = metered_max_i;
|
||||
}
|
||||
}
|
||||
|
||||
float temporal_predict() {
|
||||
float sum_x = 0.0;
|
||||
float sum_y = 0.0;
|
||||
float sum_x2 = 0.0;
|
||||
float sum_xy = 0.0;
|
||||
|
||||
float n = temporal_stable_frames;
|
||||
float xp = float(n + 1);
|
||||
|
||||
for (int i = 0; i < n; i++) {
|
||||
float x = float(i + 1);
|
||||
sum_x += x;
|
||||
sum_y += metered_max_i_t[i];
|
||||
sum_x2 += x * x;
|
||||
sum_xy += x * metered_max_i_t[i];
|
||||
}
|
||||
|
||||
float a = (n * sum_xy - sum_x * sum_y) / (n * sum_x2 - sum_x * sum_x);
|
||||
float b = (sum_y - a * sum_x) / float(n);
|
||||
|
||||
return a * xp + b;
|
||||
}
|
||||
|
||||
bool is_sence_changed(float m, float p) {
|
||||
float black = 16.0;
|
||||
if (black > metered_max_i)
|
||||
return true;
|
||||
|
||||
float tolerance = 36.0;
|
||||
float im = float(m) / 4095.0;
|
||||
float ip = float(p) / 4095.0;
|
||||
float delta = 720 * abs(im - ip);
|
||||
return delta > tolerance;
|
||||
}
|
||||
|
||||
void hook() {
|
||||
float p = temporal_predict();
|
||||
temporal_prepend();
|
||||
float m = temporal_harmonic_mean();
|
||||
|
||||
if (is_sence_changed(m, p)) {
|
||||
temporal_fill();
|
||||
return;
|
||||
}
|
||||
|
||||
metered_max_i = uint(m + 0.5);
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!BIND METERING
|
||||
//!BIND METERED
|
||||
//!WHEN preview_metering
|
||||
//!DESC metering (preview)
|
||||
|
||||
bool almost_equal(float a, float b, float epsilon) {
|
||||
return abs(a - b) < epsilon;
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
float metering = METERING_tex(METERING_pos).x;
|
||||
float lmi = float(metered_max_i) / 4095.0;
|
||||
|
||||
vec3 color = vec3(metering);
|
||||
|
||||
float delta = 720 * abs(metering - lmi);
|
||||
if (delta < 4.0)
|
||||
color = vec3(1.0, 0.0, 0.0);
|
||||
|
||||
if (almost_equal(1.0 - METERING_pos.y, lmi, 1e-3))
|
||||
color = vec3(0.0, 1.0, 0.0);
|
||||
|
||||
return vec4(color, 1.0);
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!BIND METERED
|
||||
//!DESC tone mapping (astra)
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec3 pq_eotf_inv(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf_inv(color.r),
|
||||
pq_eotf_inv(color.g),
|
||||
pq_eotf_inv(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
float pq_eotf(float x) {
|
||||
float t = pow(x, 1.0 / m2);
|
||||
return pow(max(t - c1, 0.0) / (c2 - c3 * t), 1.0 / m1) * pw;
|
||||
}
|
||||
|
||||
vec3 pq_eotf(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf(color.r),
|
||||
pq_eotf(color.g),
|
||||
pq_eotf(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
vec3 RGB_to_XYZ(vec3 RGB) {
|
||||
return RGB * mat3(
|
||||
0.6369580483012914, 0.14461690358620832, 0.1688809751641721,
|
||||
0.2627002120112671, 0.6779980715188708, 0.05930171646986196,
|
||||
0.0 , 0.028072693049087428, 1.060985057710791
|
||||
);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_RGB(vec3 XYZ) {
|
||||
return XYZ * mat3(
|
||||
1.716651187971268, -0.355670783776392, -0.25336628137366,
|
||||
-0.666684351832489, 1.616481236634939, 0.0157685458139111,
|
||||
0.017639857445311, -0.042770613257809, 0.942103121235474
|
||||
);
|
||||
}
|
||||
|
||||
const float b = 1.15;
|
||||
const float g = 0.66;
|
||||
|
||||
vec3 XYZ_to_XYZm(vec3 XYZ) {
|
||||
float Xm = (b * XYZ.x) - ((b - 1.0) * XYZ.z);
|
||||
float Ym = (g * XYZ.y) - ((g - 1.0) * XYZ.x);
|
||||
return vec3(Xm, Ym, XYZ.z);
|
||||
}
|
||||
|
||||
vec3 XYZm_to_XYZ(vec3 XYZm) {
|
||||
float Xa = (XYZm.x + ((b - 1.0) * XYZm.z)) / b;
|
||||
float Ya = (XYZm.y + ((g - 1.0) * Xa)) / g;
|
||||
return vec3(Xa, Ya, XYZm.z);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_LMS(vec3 XYZ) {
|
||||
return XYZ * mat3(
|
||||
0.41478972, 0.579999, 0.0146480,
|
||||
-0.2015100, 1.120649, 0.0531008,
|
||||
-0.0166008, 0.264800, 0.6684799
|
||||
);
|
||||
}
|
||||
|
||||
vec3 LMS_to_XYZ(vec3 LMS) {
|
||||
return LMS * mat3(
|
||||
1.9242264357876067, -1.0047923125953657, 0.037651404030618,
|
||||
0.35031676209499907, 0.7264811939316552, -0.06538442294808501,
|
||||
-0.09098281098284752, -0.3127282905230739, 1.5227665613052603
|
||||
);
|
||||
}
|
||||
|
||||
vec3 LMS_to_Iab(vec3 LMS) {
|
||||
return LMS * mat3(
|
||||
0.5, 0.5, 0.0,
|
||||
3.524000, -4.066708, 0.542708,
|
||||
0.199076, 1.096799, -1.295875
|
||||
);
|
||||
}
|
||||
|
||||
vec3 Iab_to_LMS(vec3 Iab) {
|
||||
return Iab * mat3(
|
||||
1.0, 0.1386050432715393, 0.0580473161561189,
|
||||
1.0, -0.1386050432715393, -0.0580473161561189,
|
||||
1.0, -0.0960192420263190, -0.8118918960560390
|
||||
);
|
||||
}
|
||||
|
||||
const float d = -0.56;
|
||||
const float d0 = 1.6295499532821566e-11;
|
||||
|
||||
float I_to_J(float I) {
|
||||
return ((1.0 + d) * I) / (1.0 + (d * I)) - d0;
|
||||
}
|
||||
|
||||
float J_to_I(float J) {
|
||||
return (J + d0) / (1.0 + d - d * (J + d0));
|
||||
}
|
||||
|
||||
float hke_fh_hellwig(float h, float a1, float a2, float a3, float a4, float a5) {
|
||||
return a1 * cos(h) + a2 * cos(2.0 * h) + a3 * sin(h) + a4 * sin(2.0 * h) + a5;
|
||||
}
|
||||
|
||||
float hke_fh_high(float h, float k1, float k2, float k3, float k4) {
|
||||
h = mod(mod(degrees(h), 360.0) + 360.0, 360.0);
|
||||
float by = k1 * abs(sin(radians((h - 90.0)/ 2.0))) + k2;
|
||||
float r = h <= 90.0 || h >= 270.0 ? k3 * abs(cos(radians(h))) + k4 : 0.0;
|
||||
return by + r;
|
||||
}
|
||||
|
||||
float hke_fh_liao(float h, float k3, float k4, float k5) {
|
||||
h = mod(mod(degrees(h), 360.0) + 360.0, 360.0);
|
||||
return k3 * abs(log(((h + k4) / (90.0 + k4)))) + k5;
|
||||
}
|
||||
|
||||
float hke_fh(float h) {
|
||||
float result = hke_fh_liao(h, 0.3495, 45.0, 0.1567);
|
||||
return result * hk_effect_compensate_scaling;
|
||||
}
|
||||
|
||||
float J_to_Jhk(vec3 JCh) {
|
||||
float J = JCh.x;
|
||||
float C = JCh.y;
|
||||
float h = JCh.z;
|
||||
return J + C * hke_fh(h);
|
||||
}
|
||||
|
||||
float Jhk_to_J(vec3 JCh) {
|
||||
float J = JCh.x;
|
||||
float C = JCh.y;
|
||||
float h = JCh.z;
|
||||
return J - C * hke_fh(h);
|
||||
}
|
||||
|
||||
// https://github.com/color-js/color.js/pull/629
|
||||
const float epsilon = 0.0002363;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
vec3 RGB_to_Jab(vec3 color) {
|
||||
color *= reference_white;
|
||||
color = RGB_to_XYZ(color);
|
||||
color = XYZ_to_XYZm(color);
|
||||
color = XYZ_to_LMS(color);
|
||||
color = pq_eotf_inv(color);
|
||||
color = LMS_to_Iab(color);
|
||||
color.x = I_to_J(color.x);
|
||||
color.x = J_to_Jhk(Lab_to_LCh(color));
|
||||
return color;
|
||||
}
|
||||
|
||||
vec3 Jab_to_RGB(vec3 color) {
|
||||
color.x = Jhk_to_J(Lab_to_LCh(color));
|
||||
color.x = J_to_I(color.x);
|
||||
color = Iab_to_LMS(color);
|
||||
color = pq_eotf(color);
|
||||
color = LMS_to_XYZ(color);
|
||||
color = XYZm_to_XYZ(color);
|
||||
color = XYZ_to_RGB(color);
|
||||
color /= reference_white;
|
||||
return color;
|
||||
}
|
||||
|
||||
float get_max_i() {
|
||||
if (max_pq_y > 0.0)
|
||||
return max_pq_y;
|
||||
|
||||
if (scene_max_r > 0.0 || scene_max_g > 0.0 || scene_max_b > 0.0) {
|
||||
vec3 scene_max_rgb = vec3(scene_max_r, scene_max_g, scene_max_b);
|
||||
return pq_eotf_inv(RGB_to_XYZ(scene_max_rgb).y);
|
||||
}
|
||||
|
||||
if (enable_metering > 0)
|
||||
return float(metered_max_i) / 4095.0;
|
||||
|
||||
if (max_cll > 0.0)
|
||||
return pq_eotf_inv(max_cll);
|
||||
|
||||
if (max_luma > 0.0)
|
||||
return pq_eotf_inv(max_luma);
|
||||
|
||||
return pq_eotf_inv(1000.0);
|
||||
}
|
||||
|
||||
float get_min_i() {
|
||||
if (min_luma > 0.0)
|
||||
return pq_eotf_inv(min_luma);
|
||||
|
||||
return pq_eotf_inv(0.001);
|
||||
}
|
||||
|
||||
float get_avg_i() {
|
||||
if (avg_pq_y > 0.0)
|
||||
return avg_pq_y;
|
||||
|
||||
if (scene_avg > 0.0)
|
||||
return pq_eotf_inv(scene_avg);
|
||||
|
||||
// if (max_fall > 0.0)
|
||||
// return pq_eotf_inv(max_fall);
|
||||
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
float ev = 0.0;
|
||||
|
||||
vec3 auto_exposure(vec3 color) {
|
||||
if (auto_exposure_anchor <= 0.0)
|
||||
return color;
|
||||
|
||||
float avg_i = get_avg_i();
|
||||
|
||||
if (avg_i <= 0.0)
|
||||
return color;
|
||||
|
||||
float ach = pq_eotf(J_to_I(
|
||||
auto_exposure_anchor *
|
||||
I_to_J(pq_eotf_inv(reference_white))
|
||||
));
|
||||
float avg = pq_eotf(avg_i);
|
||||
float mxx = pq_eotf(get_max_i());
|
||||
float ref = reference_white;
|
||||
float old = 100.0;
|
||||
|
||||
float ev_min = min(log2(max(ref / mxx, 1e-6)), 0.0);
|
||||
float ev_max = max(log2(max(ref / old, 1e-6)), 0.0);
|
||||
|
||||
ev = log2(max(ach / avg, 1e-6));
|
||||
ev = clamp(ev, ev_min, ev_max);
|
||||
|
||||
return color * exp2(ev);
|
||||
}
|
||||
|
||||
float f(float x, float iw, float ib, float ow, float ob) {
|
||||
float midgray = 0.5 * ow;
|
||||
float shadow = mix(midgray, ob, 0.66);
|
||||
float highlight = mix(midgray, ow, 0.04);
|
||||
|
||||
float x0 = ib;
|
||||
float y0 = ob;
|
||||
float x1 = shadow;
|
||||
float y1 = shadow;
|
||||
float x2 = highlight;
|
||||
float y2 = highlight;
|
||||
float x3 = iw;
|
||||
float y3 = ow;
|
||||
|
||||
float al = (y2 - y1) / (x2 - x1);
|
||||
|
||||
if (x < x1) {
|
||||
float at = al * (x1 - x0) * (x1 - x0) * (y1 - y0) * (y1 - y0) / ((y1 - y0 - al * (x1 - x0)) * (y1 - y0 - al * (x1 - x0)));
|
||||
float bt = al * (x1 - x0) * (x1 - x0) / (y1 - y0 - al * (x1 - x0));
|
||||
float ct = (y1 - y0) * (y1 - y0) / (y1 - y0 - al * (x1 - x0));
|
||||
x = -at / (x - x0 + bt) + ct + y0;
|
||||
} else if (x < x2) {
|
||||
float bl = y1 - al * x1;
|
||||
x = al * x + bl;
|
||||
} else {
|
||||
float bs = al * (x3 - x2) / (y3 - y2);
|
||||
float as = log(y3 - y2) - bs * log(x3 - x2);
|
||||
x = -exp(as + bs * log(max(-(x - x3), 1e-6))) + y3;
|
||||
}
|
||||
|
||||
return clamp(x, ob, ow);
|
||||
}
|
||||
|
||||
float curve(float x) {
|
||||
float ow = I_to_J(pq_eotf_inv(reference_white));
|
||||
float ob = I_to_J(pq_eotf_inv(reference_white / 1000.0));
|
||||
float iw = get_max_i();
|
||||
float ib = get_min_i();
|
||||
|
||||
if (ev != 0.0) {
|
||||
iw = pq_eotf_inv(pq_eotf(iw) * exp2(ev));
|
||||
ib = pq_eotf_inv(pq_eotf(ib) * exp2(ev));
|
||||
}
|
||||
|
||||
iw = max(I_to_J(iw), ow + 1e-3);
|
||||
ib = min(I_to_J(ib), ob - 1e-3);
|
||||
|
||||
return f(x, iw, ib, ow, ob);
|
||||
}
|
||||
|
||||
vec2 chroma_correction(vec2 ab, float i1, float i2) {
|
||||
float r1 = i1 / max(i2, 1e-6);
|
||||
float r2 = i2 / max(i1, 1e-6);
|
||||
return ab * mix(1.0, min(r1, r2), chroma_correction_scaling);
|
||||
}
|
||||
|
||||
vec3 tone_mapping(vec3 iab) {
|
||||
float i2 = curve(iab.x);
|
||||
vec2 ab2 = chroma_correction(iab.yz, iab.x, i2);
|
||||
return vec3(i2, ab2);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = auto_exposure(color.rgb);
|
||||
color.rgb = RGB_to_Jab(color.rgb);
|
||||
color.rgb = tone_mapping(color.rgb);
|
||||
color.rgb = Jab_to_RGB(color.rgb);
|
||||
|
||||
return color;
|
||||
}
|
764
mpv/shaders/hdr-toys/tone-mapping/bt2390.glsl
Normal file
764
mpv/shaders/hdr-toys/tone-mapping/bt2390.glsl
Normal file
|
@ -0,0 +1,764 @@
|
|||
// ITU-R BT.2390 EETF
|
||||
// https://www.itu.int/pub/R-REP-BT.2390
|
||||
// https://www.itu.int/pub/R-REP-BT.2408
|
||||
|
||||
//!PARAM min_luma
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_luma
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_cll
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_r
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_g
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_b
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_pq_y
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM reference_white
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1000.0
|
||||
203.0
|
||||
|
||||
//!PARAM chroma_correction_scaling
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1.0
|
||||
1.0
|
||||
|
||||
//!PARAM representation
|
||||
//!TYPE ENUM int
|
||||
ictcp
|
||||
ycbcr
|
||||
yrgb
|
||||
prergb
|
||||
maxrgb
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!WHEN representation 0 =
|
||||
//!DESC tone mapping (bt.2390, ICtCp)
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec3 pq_eotf_inv(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf_inv(color.r),
|
||||
pq_eotf_inv(color.g),
|
||||
pq_eotf_inv(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
float pq_eotf(float x) {
|
||||
float t = pow(x, 1.0 / m2);
|
||||
return pow(max(t - c1, 0.0) / (c2 - c3 * t), 1.0 / m1) * pw;
|
||||
}
|
||||
|
||||
vec3 pq_eotf(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf(color.r),
|
||||
pq_eotf(color.g),
|
||||
pq_eotf(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
vec3 RGB_to_XYZ(vec3 RGB) {
|
||||
return RGB * mat3(
|
||||
0.6369580483012914, 0.14461690358620832, 0.1688809751641721,
|
||||
0.2627002120112671, 0.6779980715188708, 0.05930171646986196,
|
||||
0.0 , 0.028072693049087428, 1.060985057710791
|
||||
);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_RGB(vec3 XYZ) {
|
||||
return XYZ * mat3(
|
||||
1.716651187971268, -0.355670783776392, -0.25336628137366,
|
||||
-0.666684351832489, 1.616481236634939, 0.0157685458139111,
|
||||
0.017639857445311, -0.042770613257809, 0.942103121235474
|
||||
);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_LMS(vec3 XYZ) {
|
||||
return XYZ * mat3(
|
||||
0.3592832590121217, 0.6976051147779502, -0.0358915932320290,
|
||||
-0.1920808463704993, 1.1004767970374321, 0.0753748658519118,
|
||||
0.0070797844607479, 0.0748396662186362, 0.8433265453898765
|
||||
);
|
||||
}
|
||||
|
||||
vec3 LMS_to_XYZ(vec3 LMS) {
|
||||
return LMS * mat3(
|
||||
2.0701522183894223, -1.3263473389671563, 0.2066510476294053,
|
||||
0.3647385209748072, 0.6805660249472273, -0.0453045459220347,
|
||||
-0.0497472075358123, -0.0492609666966131, 1.1880659249923042
|
||||
);
|
||||
}
|
||||
|
||||
vec3 LMS_to_ICtCp(vec3 LMS) {
|
||||
return LMS * mat3(
|
||||
2048.0 / 4096.0, 2048.0 / 4096.0, 0.0 / 4096.0,
|
||||
6610.0 / 4096.0, -13613.0 / 4096.0, 7003.0 / 4096.0,
|
||||
17933.0 / 4096.0, -17390.0 / 4096.0, -543.0 / 4096.0
|
||||
);
|
||||
}
|
||||
|
||||
vec3 ICtCp_to_LMS(vec3 ICtCp) {
|
||||
return ICtCp * mat3(
|
||||
1.0, 0.0086090370379328, 0.1110296250030260,
|
||||
1.0, -0.0086090370379328, -0.1110296250030260,
|
||||
1.0, 0.5600313357106791, -0.3206271749873189
|
||||
);
|
||||
}
|
||||
|
||||
vec3 RGB_to_ICtCp(vec3 color) {
|
||||
color *= reference_white;
|
||||
color = RGB_to_XYZ(color);
|
||||
color = XYZ_to_LMS(color);
|
||||
color = pq_eotf_inv(color);
|
||||
color = LMS_to_ICtCp(color);
|
||||
return color;
|
||||
}
|
||||
|
||||
vec3 ICtCp_to_RGB(vec3 color) {
|
||||
color = ICtCp_to_LMS(color);
|
||||
color = pq_eotf(color);
|
||||
color = LMS_to_XYZ(color);
|
||||
color = XYZ_to_RGB(color);
|
||||
color /= reference_white;
|
||||
return color;
|
||||
}
|
||||
|
||||
float get_max_i() {
|
||||
if (max_pq_y > 0.0)
|
||||
return max_pq_y;
|
||||
|
||||
if (scene_max_r > 0.0 || scene_max_g > 0.0 || scene_max_b > 0.0) {
|
||||
vec3 scene_max_rgb = vec3(scene_max_r, scene_max_g, scene_max_b);
|
||||
return pq_eotf_inv(RGB_to_XYZ(scene_max_rgb).y);
|
||||
}
|
||||
|
||||
if (max_cll > 0.0)
|
||||
return pq_eotf_inv(max_cll);
|
||||
|
||||
if (max_luma > 0.0)
|
||||
return pq_eotf_inv(max_luma);
|
||||
|
||||
return pq_eotf_inv(1000.0);
|
||||
}
|
||||
|
||||
float get_min_i() {
|
||||
if (min_luma > 0.0)
|
||||
return pq_eotf_inv(min_luma);
|
||||
|
||||
return pq_eotf_inv(0.001);
|
||||
}
|
||||
|
||||
float f(float x, float iw, float ib, float ow, float ob) {
|
||||
float minLum = (ob - ib) / (iw - ib);
|
||||
float maxLum = (ow - ib) / (iw - ib);
|
||||
|
||||
float KS = 1.5 * maxLum - 0.5;
|
||||
float b = minLum;
|
||||
|
||||
// E1
|
||||
x = (x - ib) / (iw - ib);
|
||||
|
||||
// E2
|
||||
if (KS <= x) {
|
||||
float TB = (x - KS) / (1.0 - KS);
|
||||
float TB2 = TB * TB;
|
||||
float TB3 = TB * TB2;
|
||||
|
||||
float PB = (2.0 * TB3 - 3.0 * TB2 + 1.0) * KS +
|
||||
(TB3 - 2.0 * TB2 + TB) * (1.0 - KS) +
|
||||
(-2.0 * TB3 + 3.0 * TB2) * maxLum;
|
||||
|
||||
x = PB;
|
||||
}
|
||||
|
||||
// E3
|
||||
if (0.0 <= x) {
|
||||
x = x + b * pow((1.0 - x), 4.0);
|
||||
}
|
||||
|
||||
// E4
|
||||
x = x * (iw - ib) + ib;
|
||||
|
||||
return clamp(x, ob, ow);
|
||||
}
|
||||
|
||||
float curve(float x) {
|
||||
float ow = pq_eotf_inv(reference_white);
|
||||
float ob = pq_eotf_inv(reference_white / 1000.0);
|
||||
float iw = max(get_max_i(), ow + 1e-3);
|
||||
float ib = min(get_min_i(), ob - 1e-3);
|
||||
return f(x, iw, ib, ow, ob);
|
||||
}
|
||||
|
||||
vec2 chroma_correction(vec2 ab, float i1, float i2) {
|
||||
float r1 = i1 / max(i2, 1e-6);
|
||||
float r2 = i2 / max(i1, 1e-6);
|
||||
return ab * mix(1.0, min(r1, r2), chroma_correction_scaling);
|
||||
}
|
||||
|
||||
vec3 tone_mapping(vec3 iab) {
|
||||
float i2 = curve(iab.x);
|
||||
vec2 ab2 = chroma_correction(iab.yz, iab.x, i2);
|
||||
return vec3(i2, ab2);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = RGB_to_ICtCp(color.rgb);
|
||||
color.rgb = tone_mapping(color.rgb);
|
||||
color.rgb = ICtCp_to_RGB(color.rgb);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!WHEN representation 1 =
|
||||
//!DESC tone mapping (bt.2390, Y'Cb'Cr')
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec3 pq_eotf_inv(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf_inv(color.r),
|
||||
pq_eotf_inv(color.g),
|
||||
pq_eotf_inv(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
float pq_eotf(float x) {
|
||||
float t = pow(x, 1.0 / m2);
|
||||
return pow(max(t - c1, 0.0) / (c2 - c3 * t), 1.0 / m1) * pw;
|
||||
}
|
||||
|
||||
vec3 pq_eotf(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf(color.r),
|
||||
pq_eotf(color.g),
|
||||
pq_eotf(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
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_i() {
|
||||
if (max_pq_y > 0.0)
|
||||
return max_pq_y;
|
||||
|
||||
if (scene_max_r > 0.0 || scene_max_g > 0.0 || scene_max_b > 0.0) {
|
||||
vec3 scene_max_rgb = vec3(scene_max_r, scene_max_g, scene_max_b);
|
||||
return pq_eotf_inv(dot(scene_max_rgb, y_coef));
|
||||
}
|
||||
|
||||
if (max_cll > 0.0)
|
||||
return pq_eotf_inv(max_cll);
|
||||
|
||||
if (max_luma > 0.0)
|
||||
return pq_eotf_inv(max_luma);
|
||||
|
||||
return pq_eotf_inv(1000.0);
|
||||
}
|
||||
|
||||
float get_min_i() {
|
||||
if (min_luma > 0.0)
|
||||
return pq_eotf_inv(min_luma);
|
||||
|
||||
return pq_eotf_inv(0.001);
|
||||
}
|
||||
|
||||
float f(float x, float iw, float ib, float ow, float ob) {
|
||||
float minLum = (ob - ib) / (iw - ib);
|
||||
float maxLum = (ow - ib) / (iw - ib);
|
||||
|
||||
float KS = 1.5 * maxLum - 0.5;
|
||||
float b = minLum;
|
||||
|
||||
// E1
|
||||
x = (x - ib) / (iw - ib);
|
||||
|
||||
// E2
|
||||
if (KS <= x) {
|
||||
float TB = (x - KS) / (1.0 - KS);
|
||||
float TB2 = TB * TB;
|
||||
float TB3 = TB * TB2;
|
||||
|
||||
float PB = (2.0 * TB3 - 3.0 * TB2 + 1.0) * KS +
|
||||
(TB3 - 2.0 * TB2 + TB) * (1.0 - KS) +
|
||||
(-2.0 * TB3 + 3.0 * TB2) * maxLum;
|
||||
|
||||
x = PB;
|
||||
}
|
||||
|
||||
// E3
|
||||
if (0.0 <= x) {
|
||||
x = x + b * pow((1.0 - x), 4.0);
|
||||
}
|
||||
|
||||
// E4
|
||||
x = x * (iw - ib) + ib;
|
||||
|
||||
return clamp(x, ob, ow);
|
||||
}
|
||||
|
||||
float curve(float x) {
|
||||
float ow = pq_eotf_inv(reference_white);
|
||||
float ob = pq_eotf_inv(reference_white / 1000.0);
|
||||
float iw = max(get_max_i(), ow + 1e-3);
|
||||
float ib = min(get_min_i(), ob - 1e-3);
|
||||
return f(x, iw, ib, ow, ob);
|
||||
}
|
||||
|
||||
vec2 chroma_correction(vec2 ab, float i1, float i2) {
|
||||
float r1 = i1 / max(i2, 1e-6);
|
||||
float r2 = i2 / max(i1, 1e-6);
|
||||
return ab * mix(1.0, min(r1, r2), chroma_correction_scaling);
|
||||
}
|
||||
|
||||
vec3 tone_mapping(vec3 iab) {
|
||||
float i2 = curve(iab.x);
|
||||
vec2 ab2 = chroma_correction(iab.yz, iab.x, i2);
|
||||
return vec3(i2, ab2);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = pq_eotf_inv(color.rgb * reference_white);
|
||||
color.rgb = RGB_to_YCbCr(color.rgb);
|
||||
color.rgb = tone_mapping(color.rgb);
|
||||
color.rgb = YCbCr_to_RGB(color.rgb);
|
||||
color.rgb = pq_eotf(color.rgb) / reference_white;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!WHEN representation 2 =
|
||||
//!DESC tone mapping (bt.2390, YRGB)
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec3 pq_eotf_inv(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf_inv(color.r),
|
||||
pq_eotf_inv(color.g),
|
||||
pq_eotf_inv(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
float pq_eotf(float x) {
|
||||
float t = pow(x, 1.0 / m2);
|
||||
return pow(max(t - c1, 0.0) / (c2 - c3 * t), 1.0 / m1) * pw;
|
||||
}
|
||||
|
||||
vec3 pq_eotf(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf(color.r),
|
||||
pq_eotf(color.g),
|
||||
pq_eotf(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
const vec3 y_coef = vec3(0.2627002120112671, 0.6779980715188708, 0.05930171646986196);
|
||||
|
||||
float get_max_i() {
|
||||
if (max_pq_y > 0.0)
|
||||
return max_pq_y;
|
||||
|
||||
if (scene_max_r > 0.0 || scene_max_g > 0.0 || scene_max_b > 0.0) {
|
||||
vec3 scene_max_rgb = vec3(scene_max_r, scene_max_g, scene_max_b);
|
||||
return pq_eotf_inv(dot(scene_max_rgb, y_coef));
|
||||
}
|
||||
|
||||
if (max_cll > 0.0)
|
||||
return pq_eotf_inv(max_cll);
|
||||
|
||||
if (max_luma > 0.0)
|
||||
return pq_eotf_inv(max_luma);
|
||||
|
||||
return pq_eotf_inv(1000.0);
|
||||
}
|
||||
|
||||
float get_min_i() {
|
||||
if (min_luma > 0.0)
|
||||
return pq_eotf_inv(min_luma);
|
||||
|
||||
return pq_eotf_inv(0.001);
|
||||
}
|
||||
|
||||
float f(float x, float iw, float ib, float ow, float ob) {
|
||||
float minLum = (ob - ib) / (iw - ib);
|
||||
float maxLum = (ow - ib) / (iw - ib);
|
||||
|
||||
float KS = 1.5 * maxLum - 0.5;
|
||||
float b = minLum;
|
||||
|
||||
// E1
|
||||
x = (x - ib) / (iw - ib);
|
||||
|
||||
// E2
|
||||
if (KS <= x) {
|
||||
float TB = (x - KS) / (1.0 - KS);
|
||||
float TB2 = TB * TB;
|
||||
float TB3 = TB * TB2;
|
||||
|
||||
float PB = (2.0 * TB3 - 3.0 * TB2 + 1.0) * KS +
|
||||
(TB3 - 2.0 * TB2 + TB) * (1.0 - KS) +
|
||||
(-2.0 * TB3 + 3.0 * TB2) * maxLum;
|
||||
|
||||
x = PB;
|
||||
}
|
||||
|
||||
// E3
|
||||
if (0.0 <= x) {
|
||||
x = x + b * pow((1.0 - x), 4.0);
|
||||
}
|
||||
|
||||
// E4
|
||||
x = x * (iw - ib) + ib;
|
||||
|
||||
return clamp(x, ob, ow);
|
||||
}
|
||||
|
||||
float curve(float x) {
|
||||
float ow = pq_eotf_inv(reference_white);
|
||||
float ob = pq_eotf_inv(reference_white / 1000.0);
|
||||
float iw = max(get_max_i(), ow + 1e-3);
|
||||
float ib = min(get_min_i(), ob - 1e-3);
|
||||
return f(x, iw, ib, ow, ob);
|
||||
}
|
||||
|
||||
vec3 tone_mapping(vec3 rgb) {
|
||||
float y1 = dot(rgb, y_coef) * reference_white;
|
||||
float y2 = pq_eotf(curve(pq_eotf_inv(y1)));
|
||||
return (y2 / max(y1, 1e-6)) * rgb;
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = tone_mapping(color.rgb);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!WHEN representation 3 =
|
||||
//!DESC tone mapping (bt.2390, R'G'B')
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec3 pq_eotf_inv(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf_inv(color.r),
|
||||
pq_eotf_inv(color.g),
|
||||
pq_eotf_inv(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
float pq_eotf(float x) {
|
||||
float t = pow(x, 1.0 / m2);
|
||||
return pow(max(t - c1, 0.0) / (c2 - c3 * t), 1.0 / m1) * pw;
|
||||
}
|
||||
|
||||
vec3 pq_eotf(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf(color.r),
|
||||
pq_eotf(color.g),
|
||||
pq_eotf(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
const vec3 y_coef = vec3(0.2627002120112671, 0.6779980715188708, 0.05930171646986196);
|
||||
|
||||
float get_max_i() {
|
||||
if (max_pq_y > 0.0)
|
||||
return max_pq_y;
|
||||
|
||||
if (scene_max_r > 0.0 || scene_max_g > 0.0 || scene_max_b > 0.0) {
|
||||
vec3 scene_max_rgb = vec3(scene_max_r, scene_max_g, scene_max_b);
|
||||
return pq_eotf_inv(dot(scene_max_rgb, y_coef));
|
||||
}
|
||||
|
||||
if (max_cll > 0.0)
|
||||
return pq_eotf_inv(max_cll);
|
||||
|
||||
if (max_luma > 0.0)
|
||||
return pq_eotf_inv(max_luma);
|
||||
|
||||
return pq_eotf_inv(1000.0);
|
||||
}
|
||||
|
||||
float get_min_i() {
|
||||
if (min_luma > 0.0)
|
||||
return pq_eotf_inv(min_luma);
|
||||
|
||||
return pq_eotf_inv(0.001);
|
||||
}
|
||||
|
||||
float f(float x, float iw, float ib, float ow, float ob) {
|
||||
float minLum = (ob - ib) / (iw - ib);
|
||||
float maxLum = (ow - ib) / (iw - ib);
|
||||
|
||||
float KS = 1.5 * maxLum - 0.5;
|
||||
float b = minLum;
|
||||
|
||||
// E1
|
||||
x = (x - ib) / (iw - ib);
|
||||
|
||||
// E2
|
||||
if (KS <= x) {
|
||||
float TB = (x - KS) / (1.0 - KS);
|
||||
float TB2 = TB * TB;
|
||||
float TB3 = TB * TB2;
|
||||
|
||||
float PB = (2.0 * TB3 - 3.0 * TB2 + 1.0) * KS +
|
||||
(TB3 - 2.0 * TB2 + TB) * (1.0 - KS) +
|
||||
(-2.0 * TB3 + 3.0 * TB2) * maxLum;
|
||||
|
||||
x = PB;
|
||||
}
|
||||
|
||||
// E3
|
||||
if (0.0 <= x) {
|
||||
x = x + b * pow((1.0 - x), 4.0);
|
||||
}
|
||||
|
||||
// E4
|
||||
x = x * (iw - ib) + ib;
|
||||
|
||||
return clamp(x, ob, ow);
|
||||
}
|
||||
|
||||
float curve(float x) {
|
||||
float ow = pq_eotf_inv(reference_white);
|
||||
float ob = pq_eotf_inv(reference_white / 1000.0);
|
||||
float iw = max(get_max_i(), ow + 1e-3);
|
||||
float ib = min(get_min_i(), ob - 1e-3);
|
||||
return f(x, iw, ib, ow, ob);
|
||||
}
|
||||
|
||||
vec3 tone_mapping(vec3 rgb) {
|
||||
return vec3(
|
||||
curve(rgb.r),
|
||||
curve(rgb.g),
|
||||
curve(rgb.b)
|
||||
);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = pq_eotf_inv(color.rgb * reference_white);
|
||||
color.rgb = tone_mapping(color.rgb);
|
||||
color.rgb = pq_eotf(color.rgb) / reference_white;
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!WHEN representation 4 =
|
||||
//!DESC tone mapping (bt.2390, maxRGB)
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec3 pq_eotf_inv(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf_inv(color.r),
|
||||
pq_eotf_inv(color.g),
|
||||
pq_eotf_inv(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
float pq_eotf(float x) {
|
||||
float t = pow(x, 1.0 / m2);
|
||||
return pow(max(t - c1, 0.0) / (c2 - c3 * t), 1.0 / m1) * pw;
|
||||
}
|
||||
|
||||
vec3 pq_eotf(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf(color.r),
|
||||
pq_eotf(color.g),
|
||||
pq_eotf(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
const vec3 y_coef = vec3(0.2627002120112671, 0.6779980715188708, 0.05930171646986196);
|
||||
|
||||
float get_max_i() {
|
||||
if (max_pq_y > 0.0)
|
||||
return max_pq_y;
|
||||
|
||||
if (scene_max_r > 0.0 || scene_max_g > 0.0 || scene_max_b > 0.0) {
|
||||
vec3 scene_max_rgb = vec3(scene_max_r, scene_max_g, scene_max_b);
|
||||
return pq_eotf_inv(dot(scene_max_rgb, y_coef));
|
||||
}
|
||||
|
||||
if (max_cll > 0.0)
|
||||
return pq_eotf_inv(max_cll);
|
||||
|
||||
if (max_luma > 0.0)
|
||||
return pq_eotf_inv(max_luma);
|
||||
|
||||
return pq_eotf_inv(1000.0);
|
||||
}
|
||||
|
||||
float get_min_i() {
|
||||
if (min_luma > 0.0)
|
||||
return pq_eotf_inv(min_luma);
|
||||
|
||||
return pq_eotf_inv(0.001);
|
||||
}
|
||||
|
||||
float f(float x, float iw, float ib, float ow, float ob) {
|
||||
float minLum = (ob - ib) / (iw - ib);
|
||||
float maxLum = (ow - ib) / (iw - ib);
|
||||
|
||||
float KS = 1.5 * maxLum - 0.5;
|
||||
float b = minLum;
|
||||
|
||||
// E1
|
||||
x = (x - ib) / (iw - ib);
|
||||
|
||||
// E2
|
||||
if (KS <= x) {
|
||||
float TB = (x - KS) / (1.0 - KS);
|
||||
float TB2 = TB * TB;
|
||||
float TB3 = TB * TB2;
|
||||
|
||||
float PB = (2.0 * TB3 - 3.0 * TB2 + 1.0) * KS +
|
||||
(TB3 - 2.0 * TB2 + TB) * (1.0 - KS) +
|
||||
(-2.0 * TB3 + 3.0 * TB2) * maxLum;
|
||||
|
||||
x = PB;
|
||||
}
|
||||
|
||||
// E3
|
||||
if (0.0 <= x) {
|
||||
x = x + b * pow((1.0 - x), 4.0);
|
||||
}
|
||||
|
||||
// E4
|
||||
x = x * (iw - ib) + ib;
|
||||
|
||||
return clamp(x, ob, ow);
|
||||
}
|
||||
|
||||
float curve(float x) {
|
||||
float ow = pq_eotf_inv(reference_white);
|
||||
float ob = pq_eotf_inv(reference_white / 1000.0);
|
||||
float iw = max(get_max_i(), ow + 1e-3);
|
||||
float ib = min(get_min_i(), ob - 1e-3);
|
||||
return f(x, iw, ib, ow, ob);
|
||||
}
|
||||
|
||||
vec3 tone_mapping(vec3 rgb) {
|
||||
float m1 = max(max(rgb.r, rgb.g), rgb.b) * reference_white;
|
||||
float m2 = pq_eotf(curve(pq_eotf_inv(m1)));
|
||||
return (m2 / max(m1, 1e-6)) * rgb;
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = tone_mapping(color.rgb);
|
||||
|
||||
return color;
|
||||
}
|
142
mpv/shaders/hdr-toys/tone-mapping/bt2446a.glsl
Normal file
142
mpv/shaders/hdr-toys/tone-mapping/bt2446a.glsl
Normal file
|
@ -0,0 +1,142 @@
|
|||
// 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;
|
||||
}
|
315
mpv/shaders/hdr-toys/tone-mapping/bt2446c.glsl
Normal file
315
mpv/shaders/hdr-toys/tone-mapping/bt2446c.glsl
Normal file
|
@ -0,0 +1,315 @@
|
|||
// ITU-R BT.2446 Conversion Method C
|
||||
// https://www.itu.int/pub/R-REP-BT.2446
|
||||
|
||||
//!PARAM reference_white
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1000.0
|
||||
203.0
|
||||
|
||||
//!PARAM alpha
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.00
|
||||
//!MAXIMUM 0.33
|
||||
0.04
|
||||
|
||||
//!PARAM sigma
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1.0
|
||||
0.33
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!WHEN alpha
|
||||
//!DESC tone mapping (bt.2446c, crosstalk)
|
||||
|
||||
// The crosstalk matrix is applied such that saturations of linear signals are reduced to achromatic to
|
||||
// avoid hue changes caused by clipping of compressed highlight parts.
|
||||
|
||||
vec3 crosstalk(vec3 x, float a) {
|
||||
float b = 1.0 - 2.0 * a;
|
||||
mat3 transform = mat3(
|
||||
b, a, a,
|
||||
a, b, a,
|
||||
a, a, b
|
||||
);
|
||||
return x * transform;
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = crosstalk(color.rgb, alpha);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!WHEN sigma
|
||||
//!DESC tone mapping (bt.2446c, chroma correction)
|
||||
|
||||
// Optional processing of chroma correction above HDR Reference White
|
||||
|
||||
// In SDR production, highlight parts are sometimes intentionally expressed as white. The processing
|
||||
// described in this section is optionally used to shift chroma above HDR Reference White to achromatic
|
||||
// when the converted SDR content requires a degree of consistency for SDR production content. This
|
||||
// processing is applied as needed before the tone-mapping processing.
|
||||
|
||||
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
|
||||
);
|
||||
}
|
||||
|
||||
float cbrt(float x) {
|
||||
return sign(x) * pow(abs(x), 1.0 / 3.0);
|
||||
}
|
||||
|
||||
const float delta = 6.0 / 29.0;
|
||||
const float deltac = delta * 2.0 / 3.0;
|
||||
|
||||
float f(float x) {
|
||||
return x > pow(delta, 3.0) ?
|
||||
cbrt(x) :
|
||||
deltac + x / (3.0 * pow(delta, 2.0));
|
||||
}
|
||||
|
||||
vec3 f(vec3 x) {
|
||||
return vec3(f(x.x), f(x.y), f(x.z));
|
||||
}
|
||||
|
||||
float f_inv(float x) {
|
||||
return x > delta ?
|
||||
pow(x, 3.0) :
|
||||
(x - deltac) * (3.0 * pow(delta, 2.0));
|
||||
}
|
||||
|
||||
vec3 f_inv(vec3 x) {
|
||||
return vec3(f_inv(x.x), f_inv(x.y), f_inv(x.z));
|
||||
}
|
||||
|
||||
const vec3 XYZn = vec3(0.95047, 1.00000, 1.08883);
|
||||
|
||||
vec3 XYZ_to_Lab(vec3 XYZ) {
|
||||
XYZ = f(XYZ / XYZn);
|
||||
|
||||
float X = XYZ.x;
|
||||
float Y = XYZ.y;
|
||||
float Z = XYZ.z;
|
||||
|
||||
float L = 116.0 * Y - 16.0;
|
||||
float a = 500.0 * (X - Y);
|
||||
float b = 200.0 * (Y - Z);
|
||||
|
||||
return vec3(L, a, b);
|
||||
}
|
||||
|
||||
vec3 Lab_to_XYZ(vec3 Lab) {
|
||||
float L = Lab.x;
|
||||
float a = Lab.y;
|
||||
float b = Lab.z;
|
||||
|
||||
float Y = (L + 16.0) / 116.0;
|
||||
float X = Y + a / 500.0;
|
||||
float Z = Y - b / 200.0;
|
||||
|
||||
vec3 XYZ = f_inv(vec3(X, Y, Z)) * XYZn;
|
||||
|
||||
return XYZ;
|
||||
}
|
||||
|
||||
vec3 RGB_to_Lab(vec3 color) {
|
||||
color = RGB_to_XYZ(color);
|
||||
color = XYZ_to_Lab(color);
|
||||
return color;
|
||||
}
|
||||
|
||||
vec3 Lab_to_RGB(vec3 color) {
|
||||
color = Lab_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 chroma_correction(float L, float Lref, float Lmax, float sigma) {
|
||||
return L <= Lref ? 1.0 : max(1.0 - sigma * (L - Lref) / (Lmax - Lref), 0.0);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
const float Lref = RGB_to_Lab(vec3(1.0)).x;
|
||||
const float Lmax = RGB_to_Lab(vec3(1000.0 / reference_white)).x;
|
||||
|
||||
color.rgb = RGB_to_Lab(color.rgb);
|
||||
color.rgb = Lab_to_LCh(color.rgb);
|
||||
color.y *= chroma_correction(color.x, Lref, Lmax, sigma);
|
||||
color.rgb = LCh_to_Lab(color.rgb);
|
||||
color.rgb = Lab_to_RGB(color.rgb);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!DESC tone mapping (bt.2446c)
|
||||
|
||||
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_xyY(vec3 XYZ) {
|
||||
float X = XYZ.x;
|
||||
float Y = XYZ.y;
|
||||
float Z = XYZ.z;
|
||||
|
||||
float divisor = X + Y + Z;
|
||||
if (divisor == 0.0) divisor = 1e-6;
|
||||
|
||||
float x = X / divisor;
|
||||
float y = Y / divisor;
|
||||
|
||||
return vec3(x, y, Y);
|
||||
}
|
||||
|
||||
vec3 xyY_to_XYZ(vec3 xyY) {
|
||||
float x = xyY.x;
|
||||
float y = xyY.y;
|
||||
float Y = xyY.z;
|
||||
|
||||
float multiplier = Y / max(y, 1e-6);
|
||||
|
||||
float z = 1.0 - x - y;
|
||||
float X = x * multiplier;
|
||||
float Z = z * multiplier;
|
||||
|
||||
return vec3(X, Y, Z);
|
||||
}
|
||||
|
||||
const float ip = 0.58535; // linear length
|
||||
const float k1 = 0.83802; // linear strength
|
||||
const float k3 = 0.74204; // shoulder strength
|
||||
|
||||
float f(float Y, float k1, float k3, float ip) {
|
||||
ip /= k1;
|
||||
float k2 = (k1 * ip) * (1.0 - k3);
|
||||
float k4 = (k1 * ip) - (k2 * log(1.0 - k3));
|
||||
return Y < ip ? Y * k1 : log((Y / ip) - k3) * k2 + k4;
|
||||
}
|
||||
|
||||
float curve(float x) {
|
||||
return f(x, k1, k3, ip);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = RGB_to_XYZ(color.rgb);
|
||||
color.rgb = XYZ_to_xyY(color.rgb);
|
||||
color.z = curve(color.z);
|
||||
color.rgb = xyY_to_XYZ(color.rgb);
|
||||
color.rgb = XYZ_to_RGB(color.rgb);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!WHEN alpha
|
||||
//!DESC tone mapping (bt.2446c, inverse crosstalk)
|
||||
|
||||
// The inverse crosstalk matrix is applied to ensure that the original hues of input HDR images are
|
||||
// recovered.
|
||||
|
||||
vec3 crosstalk_inv(vec3 x, float a) {
|
||||
float b = 1.0 - a;
|
||||
float c = 1.0 / (1.0 - 3.0 * a);
|
||||
mat3 transform = mat3(
|
||||
b, -a, -a,
|
||||
-a, b, -a,
|
||||
-a, -a, b
|
||||
);
|
||||
return x * transform * c;
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = crosstalk_inv(color.rgb, alpha);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!DESC tone mapping (bt.2446c, signal scaling)
|
||||
|
||||
// Handling 109% range (super-whites) and black point compensation
|
||||
|
||||
float f(float x, float a, float b, float c, float d) {
|
||||
return (x - a) * (d - c) / (b - a) + c;
|
||||
}
|
||||
|
||||
vec3 f(vec3 x, float a, float b, float c, float d) {
|
||||
return vec3(
|
||||
f(x.x, a, b, c, d),
|
||||
f(x.y, a, b, c, d),
|
||||
f(x.z, a, b, c, d)
|
||||
);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = f(color.rgb, 0.0, 1019.0 / 940.0, 0.001, 1.0);
|
||||
|
||||
return color;
|
||||
}
|
325
mpv/shaders/hdr-toys/tone-mapping/false.glsl
Normal file
325
mpv/shaders/hdr-toys/tone-mapping/false.glsl
Normal file
|
@ -0,0 +1,325 @@
|
|||
// 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;
|
||||
}
|
203
mpv/shaders/hdr-toys/tone-mapping/linear.glsl
Normal file
203
mpv/shaders/hdr-toys/tone-mapping/linear.glsl
Normal file
|
@ -0,0 +1,203 @@
|
|||
// Linear applies a simple scaling to the I component
|
||||
|
||||
//!PARAM min_luma
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_luma
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_cll
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_r
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_g
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_b
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_pq_y
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM reference_white
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1000.0
|
||||
203.0
|
||||
|
||||
//!PARAM chroma_correction_scaling
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1.0
|
||||
1.0
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!DESC tone mapping (linear)
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec3 pq_eotf_inv(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf_inv(color.r),
|
||||
pq_eotf_inv(color.g),
|
||||
pq_eotf_inv(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
float pq_eotf(float x) {
|
||||
float t = pow(x, 1.0 / m2);
|
||||
return pow(max(t - c1, 0.0) / (c2 - c3 * t), 1.0 / m1) * pw;
|
||||
}
|
||||
|
||||
vec3 pq_eotf(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf(color.r),
|
||||
pq_eotf(color.g),
|
||||
pq_eotf(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
vec3 RGB_to_XYZ(vec3 RGB) {
|
||||
return RGB * mat3(
|
||||
0.6369580483012914, 0.14461690358620832, 0.1688809751641721,
|
||||
0.2627002120112671, 0.6779980715188708, 0.05930171646986196,
|
||||
0.0 , 0.028072693049087428, 1.060985057710791
|
||||
);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_RGB(vec3 XYZ) {
|
||||
return XYZ * mat3(
|
||||
1.716651187971268, -0.355670783776392, -0.25336628137366,
|
||||
-0.666684351832489, 1.616481236634939, 0.0157685458139111,
|
||||
0.017639857445311, -0.042770613257809, 0.942103121235474
|
||||
);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_LMS(vec3 XYZ) {
|
||||
return XYZ * mat3(
|
||||
0.3592832590121217, 0.6976051147779502, -0.0358915932320290,
|
||||
-0.1920808463704993, 1.1004767970374321, 0.0753748658519118,
|
||||
0.0070797844607479, 0.0748396662186362, 0.8433265453898765
|
||||
);
|
||||
}
|
||||
|
||||
vec3 LMS_to_XYZ(vec3 LMS) {
|
||||
return LMS * mat3(
|
||||
2.0701522183894223, -1.3263473389671563, 0.2066510476294053,
|
||||
0.3647385209748072, 0.6805660249472273, -0.0453045459220347,
|
||||
-0.0497472075358123, -0.0492609666966131, 1.1880659249923042
|
||||
);
|
||||
}
|
||||
|
||||
vec3 LMS_to_ICtCp(vec3 LMS) {
|
||||
return LMS * mat3(
|
||||
2048.0 / 4096.0, 2048.0 / 4096.0, 0.0 / 4096.0,
|
||||
6610.0 / 4096.0, -13613.0 / 4096.0, 7003.0 / 4096.0,
|
||||
17933.0 / 4096.0, -17390.0 / 4096.0, -543.0 / 4096.0
|
||||
);
|
||||
}
|
||||
|
||||
vec3 ICtCp_to_LMS(vec3 ICtCp) {
|
||||
return ICtCp * mat3(
|
||||
1.0, 0.0086090370379328, 0.1110296250030260,
|
||||
1.0, -0.0086090370379328, -0.1110296250030260,
|
||||
1.0, 0.5600313357106791, -0.3206271749873189
|
||||
);
|
||||
}
|
||||
|
||||
vec3 RGB_to_ICtCp(vec3 color) {
|
||||
color *= reference_white;
|
||||
color = RGB_to_XYZ(color);
|
||||
color = XYZ_to_LMS(color);
|
||||
color = pq_eotf_inv(color);
|
||||
color = LMS_to_ICtCp(color);
|
||||
return color;
|
||||
}
|
||||
|
||||
vec3 ICtCp_to_RGB(vec3 color) {
|
||||
color = ICtCp_to_LMS(color);
|
||||
color = pq_eotf(color);
|
||||
color = LMS_to_XYZ(color);
|
||||
color = XYZ_to_RGB(color);
|
||||
color /= reference_white;
|
||||
return color;
|
||||
}
|
||||
|
||||
float get_max_i() {
|
||||
if (max_pq_y > 0.0)
|
||||
return max_pq_y;
|
||||
|
||||
if (scene_max_r > 0.0 || scene_max_g > 0.0 || scene_max_b > 0.0) {
|
||||
vec3 scene_max_rgb = vec3(scene_max_r, scene_max_g, scene_max_b);
|
||||
return pq_eotf_inv(RGB_to_XYZ(scene_max_rgb).y);
|
||||
}
|
||||
|
||||
if (max_cll > 0.0)
|
||||
return pq_eotf_inv(max_cll);
|
||||
|
||||
if (max_luma > 0.0)
|
||||
return pq_eotf_inv(max_luma);
|
||||
|
||||
return pq_eotf_inv(1000.0);
|
||||
}
|
||||
|
||||
float get_min_i() {
|
||||
if (min_luma > 0.0)
|
||||
return pq_eotf_inv(min_luma);
|
||||
|
||||
return pq_eotf_inv(0.001);
|
||||
}
|
||||
|
||||
float f(float x, float a, float b, float c, float d) {
|
||||
return (x - a) * (d - c) / (b - a) + c;
|
||||
}
|
||||
|
||||
float curve(float x) {
|
||||
float ow = pq_eotf_inv(reference_white);
|
||||
float ob = pq_eotf_inv(reference_white / 1000.0);
|
||||
float iw = max(get_max_i(), ow + 1e-3);
|
||||
float ib = min(get_min_i(), ob - 1e-3);
|
||||
return f(x, ib, iw, ob, ow);
|
||||
}
|
||||
|
||||
vec2 chroma_correction(vec2 ab, float i1, float i2) {
|
||||
float r1 = i1 / max(i2, 1e-6);
|
||||
float r2 = i2 / max(i1, 1e-6);
|
||||
return ab * mix(1.0, min(r1, r2), chroma_correction_scaling);
|
||||
}
|
||||
|
||||
vec3 tone_mapping(vec3 iab) {
|
||||
float i2 = curve(iab.x);
|
||||
vec2 ab2 = chroma_correction(iab.yz, iab.x, i2);
|
||||
return vec3(i2, ab2);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = RGB_to_ICtCp(color.rgb);
|
||||
color.rgb = tone_mapping(color.rgb);
|
||||
color.rgb = ICtCp_to_RGB(color.rgb);
|
||||
|
||||
return color;
|
||||
}
|
229
mpv/shaders/hdr-toys/tone-mapping/reinhard.glsl
Normal file
229
mpv/shaders/hdr-toys/tone-mapping/reinhard.glsl
Normal file
|
@ -0,0 +1,229 @@
|
|||
// Photographic tone reproduction for digital images
|
||||
// https://doi.org/10.1145/566654.566575
|
||||
|
||||
//!PARAM max_luma
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_cll
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_r
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_g
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_b
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_pq_y
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM reference_white
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1000.0
|
||||
203.0
|
||||
|
||||
//!PARAM chroma_correction_scaling
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1.0
|
||||
1.0
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!DESC tone mapping (reinhard)
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec3 pq_eotf_inv(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf_inv(color.r),
|
||||
pq_eotf_inv(color.g),
|
||||
pq_eotf_inv(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
float pq_eotf(float x) {
|
||||
float t = pow(x, 1.0 / m2);
|
||||
return pow(max(t - c1, 0.0) / (c2 - c3 * t), 1.0 / m1) * pw;
|
||||
}
|
||||
|
||||
vec3 pq_eotf(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf(color.r),
|
||||
pq_eotf(color.g),
|
||||
pq_eotf(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
vec3 RGB_to_XYZ(vec3 RGB) {
|
||||
return RGB * mat3(
|
||||
0.6369580483012914, 0.14461690358620832, 0.1688809751641721,
|
||||
0.2627002120112671, 0.6779980715188708, 0.05930171646986196,
|
||||
0.0 , 0.028072693049087428, 1.060985057710791
|
||||
);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_RGB(vec3 XYZ) {
|
||||
return XYZ * mat3(
|
||||
1.716651187971268, -0.355670783776392, -0.25336628137366,
|
||||
-0.666684351832489, 1.616481236634939, 0.0157685458139111,
|
||||
0.017639857445311, -0.042770613257809, 0.942103121235474
|
||||
);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_LMS(vec3 XYZ) {
|
||||
return XYZ * mat3(
|
||||
0.3592832590121217, 0.6976051147779502, -0.0358915932320290,
|
||||
-0.1920808463704993, 1.1004767970374321, 0.0753748658519118,
|
||||
0.0070797844607479, 0.0748396662186362, 0.8433265453898765
|
||||
);
|
||||
}
|
||||
|
||||
vec3 LMS_to_XYZ(vec3 LMS) {
|
||||
return LMS * mat3(
|
||||
2.0701522183894223, -1.3263473389671563, 0.2066510476294053,
|
||||
0.3647385209748072, 0.6805660249472273, -0.0453045459220347,
|
||||
-0.0497472075358123, -0.0492609666966131, 1.1880659249923042
|
||||
);
|
||||
}
|
||||
|
||||
vec3 LMS_to_ICtCp(vec3 LMS) {
|
||||
return LMS * mat3(
|
||||
2048.0 / 4096.0, 2048.0 / 4096.0, 0.0 / 4096.0,
|
||||
6610.0 / 4096.0, -13613.0 / 4096.0, 7003.0 / 4096.0,
|
||||
17933.0 / 4096.0, -17390.0 / 4096.0, -543.0 / 4096.0
|
||||
);
|
||||
}
|
||||
|
||||
vec3 ICtCp_to_LMS(vec3 ICtCp) {
|
||||
return ICtCp * mat3(
|
||||
1.0, 0.0086090370379328, 0.1110296250030260,
|
||||
1.0, -0.0086090370379328, -0.1110296250030260,
|
||||
1.0, 0.5600313357106791, -0.3206271749873189
|
||||
);
|
||||
}
|
||||
|
||||
vec3 RGB_to_ICtCp(vec3 color) {
|
||||
color *= reference_white;
|
||||
color = RGB_to_XYZ(color);
|
||||
color = XYZ_to_LMS(color);
|
||||
color = pq_eotf_inv(color);
|
||||
color = LMS_to_ICtCp(color);
|
||||
return color;
|
||||
}
|
||||
|
||||
vec3 ICtCp_to_RGB(vec3 color) {
|
||||
color = ICtCp_to_LMS(color);
|
||||
color = pq_eotf(color);
|
||||
color = LMS_to_XYZ(color);
|
||||
color = XYZ_to_RGB(color);
|
||||
color /= reference_white;
|
||||
return color;
|
||||
}
|
||||
|
||||
float get_max_l() {
|
||||
if (max_pq_y > 0.0)
|
||||
return pq_eotf(max_pq_y);
|
||||
|
||||
if (scene_max_r > 0.0 || scene_max_g > 0.0 || scene_max_b > 0.0) {
|
||||
vec3 scene_max_rgb = vec3(scene_max_r, scene_max_g, scene_max_b);
|
||||
return RGB_to_XYZ(scene_max_rgb).y;
|
||||
}
|
||||
|
||||
if (max_cll > 0.0)
|
||||
return max_cll;
|
||||
|
||||
if (max_luma > 0.0)
|
||||
return max_luma;
|
||||
|
||||
return 1000.0;
|
||||
}
|
||||
|
||||
float f(float x, float w) {
|
||||
float simple = x / (1.0 + x);
|
||||
float extended = simple * (1.0 + x / (w * w));
|
||||
return extended;
|
||||
}
|
||||
|
||||
float curve(float x) {
|
||||
float w = get_max_l();
|
||||
return f(x, w);
|
||||
}
|
||||
|
||||
vec2 chroma_correction(vec2 ab, float i1, float i2) {
|
||||
float r1 = i1 / max(i2, 1e-6);
|
||||
float r2 = i2 / max(i1, 1e-6);
|
||||
return ab * mix(1.0, min(r1, r2), chroma_correction_scaling);
|
||||
}
|
||||
|
||||
vec3 tone_mapping(vec3 iab) {
|
||||
float i2 = pq_eotf_inv(curve(pq_eotf(iab.x) / reference_white) * reference_white);
|
||||
vec2 ab2 = chroma_correction(iab.yz, iab.x, i2);
|
||||
return vec3(i2, ab2);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = RGB_to_ICtCp(color.rgb);
|
||||
color.rgb = tone_mapping(color.rgb);
|
||||
color.rgb = ICtCp_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;
|
||||
}
|
431
mpv/shaders/hdr-toys/tone-mapping/st2094-10.glsl
Normal file
431
mpv/shaders/hdr-toys/tone-mapping/st2094-10.glsl
Normal file
|
@ -0,0 +1,431 @@
|
|||
// ST 2094-10:2021 - SMPTE Standard - Dynamic Metadata for Color Volume Transform - Application #1
|
||||
// https://ieeexplore.ieee.org/document/9405553
|
||||
|
||||
//!PARAM min_luma
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_luma
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_cll
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_fall
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_r
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_g
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_max_b
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM scene_avg
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM max_pq_y
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM avg_pq_y
|
||||
//!TYPE float
|
||||
0.0
|
||||
|
||||
//!PARAM reference_white
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1000.0
|
||||
203.0
|
||||
|
||||
//!PARAM chroma_correction_scaling
|
||||
//!TYPE float
|
||||
//!MINIMUM 0.0
|
||||
//!MAXIMUM 1.0
|
||||
0.5
|
||||
|
||||
//!BUFFER METERED
|
||||
//!VAR float metered_avg_l
|
||||
//!STORAGE
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!SAVE AVG
|
||||
//!COMPONENTS 1
|
||||
//!WIDTH 1024
|
||||
//!HEIGHT 1024
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 1024)
|
||||
|
||||
const vec3 y_coef = vec3(0.2627002120112671, 0.6779980715188708, 0.05930171646986196);
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
float l = dot(color.rgb * reference_white, y_coef);
|
||||
float i = pq_eotf_inv(l);
|
||||
return vec4(i, vec3(0.0));
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND AVG
|
||||
//!SAVE AVG
|
||||
//!WIDTH AVG.w 2 /
|
||||
//!HEIGHT AVG.h 2 /
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 512)
|
||||
vec4 hook() { return AVG_tex(AVG_pos); }
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND AVG
|
||||
//!SAVE AVG
|
||||
//!WIDTH AVG.w 2 /
|
||||
//!HEIGHT AVG.h 2 /
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 256)
|
||||
vec4 hook() { return AVG_tex(AVG_pos); }
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND AVG
|
||||
//!SAVE AVG
|
||||
//!WIDTH AVG.w 2 /
|
||||
//!HEIGHT AVG.h 2 /
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 128)
|
||||
vec4 hook() { return AVG_tex(AVG_pos); }
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND AVG
|
||||
//!SAVE AVG
|
||||
//!WIDTH AVG.w 2 /
|
||||
//!HEIGHT AVG.h 2 /
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 64)
|
||||
vec4 hook() { return AVG_tex(AVG_pos); }
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND AVG
|
||||
//!SAVE AVG
|
||||
//!WIDTH AVG.w 2 /
|
||||
//!HEIGHT AVG.h 2 /
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 32)
|
||||
vec4 hook() { return AVG_tex(AVG_pos); }
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND AVG
|
||||
//!SAVE AVG
|
||||
//!WIDTH AVG.w 2 /
|
||||
//!HEIGHT AVG.h 2 /
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 16)
|
||||
vec4 hook() { return AVG_tex(AVG_pos); }
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND AVG
|
||||
//!SAVE AVG
|
||||
//!WIDTH AVG.w 2 /
|
||||
//!HEIGHT AVG.h 2 /
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 8)
|
||||
vec4 hook() { return AVG_tex(AVG_pos); }
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND AVG
|
||||
//!SAVE AVG
|
||||
//!WIDTH AVG.w 2 /
|
||||
//!HEIGHT AVG.h 2 /
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 4)
|
||||
vec4 hook() { return AVG_tex(AVG_pos); }
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND AVG
|
||||
//!SAVE AVG
|
||||
//!WIDTH AVG.w 2 /
|
||||
//!HEIGHT AVG.h 2 /
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 2)
|
||||
vec4 hook() { return AVG_tex(AVG_pos); }
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND AVG
|
||||
//!BIND METERED
|
||||
//!SAVE AVG
|
||||
//!WIDTH 1
|
||||
//!HEIGHT 1
|
||||
//!COMPUTE 1 1
|
||||
//!WHEN avg_pq_y 0 = scene_avg 0 = *
|
||||
//!DESC tone mapping (st2094-10, average, 1)
|
||||
|
||||
void hook() {
|
||||
metered_avg_l = AVG_tex(AVG_pos).x;
|
||||
}
|
||||
|
||||
//!HOOK OUTPUT
|
||||
//!BIND HOOKED
|
||||
//!BIND METERED
|
||||
//!DESC tone mapping (st2094-10)
|
||||
|
||||
const float m1 = 2610.0 / 4096.0 / 4.0;
|
||||
const float m2 = 2523.0 / 4096.0 * 128.0;
|
||||
const float c1 = 3424.0 / 4096.0;
|
||||
const float c2 = 2413.0 / 4096.0 * 32.0;
|
||||
const float c3 = 2392.0 / 4096.0 * 32.0;
|
||||
const float pw = 10000.0;
|
||||
|
||||
float pq_eotf_inv(float x) {
|
||||
float t = pow(x / pw, m1);
|
||||
return pow((c1 + c2 * t) / (1.0 + c3 * t), m2);
|
||||
}
|
||||
|
||||
vec3 pq_eotf_inv(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf_inv(color.r),
|
||||
pq_eotf_inv(color.g),
|
||||
pq_eotf_inv(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
float pq_eotf(float x) {
|
||||
float t = pow(x, 1.0 / m2);
|
||||
return pow(max(t - c1, 0.0) / (c2 - c3 * t), 1.0 / m1) * pw;
|
||||
}
|
||||
|
||||
vec3 pq_eotf(vec3 color) {
|
||||
return vec3(
|
||||
pq_eotf(color.r),
|
||||
pq_eotf(color.g),
|
||||
pq_eotf(color.b)
|
||||
);
|
||||
}
|
||||
|
||||
vec3 RGB_to_XYZ(vec3 RGB) {
|
||||
return RGB * mat3(
|
||||
0.6369580483012914, 0.14461690358620832, 0.1688809751641721,
|
||||
0.2627002120112671, 0.6779980715188708, 0.05930171646986196,
|
||||
0.0 , 0.028072693049087428, 1.060985057710791
|
||||
);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_RGB(vec3 XYZ) {
|
||||
return XYZ * mat3(
|
||||
1.716651187971268, -0.355670783776392, -0.25336628137366,
|
||||
-0.666684351832489, 1.616481236634939, 0.0157685458139111,
|
||||
0.017639857445311, -0.042770613257809, 0.942103121235474
|
||||
);
|
||||
}
|
||||
|
||||
vec3 XYZ_to_LMS(vec3 XYZ) {
|
||||
return XYZ * mat3(
|
||||
0.3592832590121217, 0.6976051147779502, -0.0358915932320290,
|
||||
-0.1920808463704993, 1.1004767970374321, 0.0753748658519118,
|
||||
0.0070797844607479, 0.0748396662186362, 0.8433265453898765
|
||||
);
|
||||
}
|
||||
|
||||
vec3 LMS_to_XYZ(vec3 LMS) {
|
||||
return LMS * mat3(
|
||||
2.0701522183894223, -1.3263473389671563, 0.2066510476294053,
|
||||
0.3647385209748072, 0.6805660249472273, -0.0453045459220347,
|
||||
-0.0497472075358123, -0.0492609666966131, 1.1880659249923042
|
||||
);
|
||||
}
|
||||
|
||||
vec3 LMS_to_ICtCp(vec3 LMS) {
|
||||
return LMS * mat3(
|
||||
2048.0 / 4096.0, 2048.0 / 4096.0, 0.0 / 4096.0,
|
||||
6610.0 / 4096.0, -13613.0 / 4096.0, 7003.0 / 4096.0,
|
||||
17933.0 / 4096.0, -17390.0 / 4096.0, -543.0 / 4096.0
|
||||
);
|
||||
}
|
||||
|
||||
vec3 ICtCp_to_LMS(vec3 ICtCp) {
|
||||
return ICtCp * mat3(
|
||||
1.0, 0.0086090370379328, 0.1110296250030260,
|
||||
1.0, -0.0086090370379328, -0.1110296250030260,
|
||||
1.0, 0.5600313357106791, -0.3206271749873189
|
||||
);
|
||||
}
|
||||
|
||||
vec3 RGB_to_ICtCp(vec3 color) {
|
||||
color *= reference_white;
|
||||
color = RGB_to_XYZ(color);
|
||||
color = XYZ_to_LMS(color);
|
||||
color = pq_eotf_inv(color);
|
||||
color = LMS_to_ICtCp(color);
|
||||
return color;
|
||||
}
|
||||
|
||||
vec3 ICtCp_to_RGB(vec3 color) {
|
||||
color = ICtCp_to_LMS(color);
|
||||
color = pq_eotf(color);
|
||||
color = LMS_to_XYZ(color);
|
||||
color = XYZ_to_RGB(color);
|
||||
color /= reference_white;
|
||||
return color;
|
||||
}
|
||||
|
||||
float get_max_l() {
|
||||
if (max_pq_y > 0.0)
|
||||
return pq_eotf(max_pq_y);
|
||||
|
||||
if (scene_max_r > 0.0 || scene_max_g > 0.0 || scene_max_b > 0.0) {
|
||||
vec3 scene_max_rgb = vec3(scene_max_r, scene_max_g, scene_max_b);
|
||||
return RGB_to_XYZ(scene_max_rgb).y;
|
||||
}
|
||||
|
||||
if (max_cll > 0.0)
|
||||
return max_cll;
|
||||
|
||||
if (max_luma > 0.0)
|
||||
return max_luma;
|
||||
|
||||
return 1000.0;
|
||||
}
|
||||
|
||||
float get_min_l() {
|
||||
if (min_luma > 0.0)
|
||||
return min_luma;
|
||||
|
||||
return 0.001;
|
||||
}
|
||||
|
||||
float get_avg_l() {
|
||||
if (avg_pq_y > 0.0)
|
||||
return pq_eotf(avg_pq_y);
|
||||
|
||||
if (scene_avg > 0.0)
|
||||
return scene_avg;
|
||||
|
||||
if (metered_avg_l > 0.0)
|
||||
return pq_eotf(clamp(metered_avg_l, 0.1, 0.5));
|
||||
|
||||
if (max_fall > 0.0)
|
||||
return max_fall;
|
||||
|
||||
return pq_eotf(0.3);
|
||||
}
|
||||
|
||||
// n: contrast [0.5, 1.5]
|
||||
// o: offset [-0.5, 0.5]
|
||||
// g: gain [0.5, 1.5]
|
||||
// p: gamma [0.5, 1.5]
|
||||
float f(
|
||||
float x,
|
||||
float iw, float ib, float ow, float ob, float adapt,
|
||||
float n, float o, float g, float p
|
||||
) {
|
||||
float x1 = ib;
|
||||
float y1 = ob;
|
||||
|
||||
float x3 = iw;
|
||||
float y3 = ow;
|
||||
|
||||
float x2 = adapt;
|
||||
float y2 = sqrt(x2 * sqrt(y3 * y1));
|
||||
|
||||
x2 = clamp(x2, x1 + 0.001, 0.9 * x3);
|
||||
y2 = clamp(y2, y1 + 0.001, 0.9 * y3);
|
||||
|
||||
float a = x3 * y3 * (x1 - x2) + x2 * y2 * (x3 - x1) + x1 * y1 * (x2 - x3);
|
||||
|
||||
mat3 cmat = mat3(
|
||||
x2 * x3 * (y2 - y3), x1 * x3 * (y3 - y1), x1 * x2 * (y1 - y2),
|
||||
x3 * y3 - x2 * y2 , x1 * y1 - x3 * y3 , x2 * y2 - x1 * y1 ,
|
||||
x3 - x2 , x1 - x3 , x2 - x1
|
||||
);
|
||||
|
||||
vec3 coeffs = vec3(y1, y2, y3) * cmat / a;
|
||||
|
||||
float c1 = coeffs.r;
|
||||
float c2 = coeffs.g;
|
||||
float c3 = coeffs.b;
|
||||
|
||||
x = clamp(x, x1, x3);
|
||||
x = pow(x, n);
|
||||
x = (c1 + c2 * x) / (1.0 + c3 * x);
|
||||
x = pow(min(max(0.0, ((x / y3) * g) + o), 1.0), p) * y3;
|
||||
x = clamp(x, y1, y3);
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
float f(float x, float iw, float ib, float ow, float ob, float adapt) {
|
||||
return f(x, iw, ib, ow, ob, adapt, 1.0, 0.0, 1.0, 1.0);
|
||||
}
|
||||
|
||||
float curve(float x) {
|
||||
float ow = 1.0;
|
||||
float ob = 0.001;
|
||||
float iw = max(get_max_l() / reference_white, ow + 1e-3);
|
||||
float ib = min(get_min_l() / reference_white, ob - 1e-3);
|
||||
float avg = get_avg_l() / reference_white;
|
||||
return f(x, iw, ib, ow, ob, avg);
|
||||
}
|
||||
|
||||
vec2 chroma_correction(vec2 ab, float i1, float i2) {
|
||||
float r1 = i1 / max(i2, 1e-6);
|
||||
float r2 = i2 / max(i1, 1e-6);
|
||||
return ab * mix(1.0, min(r1, r2), chroma_correction_scaling);
|
||||
}
|
||||
|
||||
vec3 tone_mapping(vec3 iab) {
|
||||
float i2 = pq_eotf_inv(curve(pq_eotf(iab.x) / reference_white) * reference_white);
|
||||
vec2 ab2 = chroma_correction(iab.yz, iab.x, i2);
|
||||
return vec3(i2, ab2);
|
||||
}
|
||||
|
||||
// c: chroma compensation weight [-0.5, 0.5]
|
||||
// s: saturation gain [-0.5, 0.5]
|
||||
vec3 gamut_adjustment(vec3 f, float c, float s) {
|
||||
float y = RGB_to_XYZ(f).y;
|
||||
return f * pow((1.0 + c) * f / y, vec3(s));
|
||||
}
|
||||
|
||||
vec3 gamut_adjustment(vec3 f) {
|
||||
return gamut_adjustment(f, 0.0, 0.0);
|
||||
}
|
||||
|
||||
// t: tone detail factor [0, 1];
|
||||
vec3 detail_managenment(vec3 p, float t) {
|
||||
// TODO: do what?
|
||||
vec3 q = p;
|
||||
return p * (1.0 - t) + q * t;
|
||||
}
|
||||
|
||||
vec3 detail_managenment(vec3 p) {
|
||||
return detail_managenment(p, 0.0);
|
||||
}
|
||||
|
||||
vec4 hook() {
|
||||
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||
|
||||
color.rgb = RGB_to_ICtCp(color.rgb);
|
||||
color.rgb = tone_mapping(color.rgb);
|
||||
color.rgb = ICtCp_to_RGB(color.rgb);
|
||||
color.rgb = gamut_adjustment(color.rgb);
|
||||
color.rgb = detail_managenment(color.rgb);
|
||||
|
||||
return color;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue