Update mpv config:
This commit is contained in:
parent
64e685695e
commit
d1e0b97d62
36 changed files with 5555 additions and 10 deletions
59
mpv/hdr-toys.conf
Normal file
59
mpv/hdr-toys.conf
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
target-colorspace-hint=no
|
||||||
|
|
||||||
|
tone-mapping=clip
|
||||||
|
gamut-mapping-mode=clip
|
||||||
|
|
||||||
|
[bt.2100-pq]
|
||||||
|
profile-cond=get("video-params/primaries") == "bt.2020" and get("video-params/gamma") == "pq"
|
||||||
|
profile-restore=copy
|
||||||
|
target-prim=bt.2020
|
||||||
|
target-trc=pq
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/utils/clip_both.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/transfer-function/pq_inv.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/tone-mapping/astra.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/gamut-mapping/jedypod.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/transfer-function/bt1886.glsl
|
||||||
|
# glsl-shader-opts=reference_white=100
|
||||||
|
|
||||||
|
[bt.2100-hlg]
|
||||||
|
profile-cond=get("video-params/primaries") == "bt.2020" and get("video-params/gamma") == "hlg"
|
||||||
|
profile-restore=copy
|
||||||
|
target-prim=bt.2020
|
||||||
|
target-trc=hlg
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/utils/clip_both.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/transfer-function/hlg_inv.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/tone-mapping/astra.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/gamut-mapping/jedypod.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/transfer-function/bt1886.glsl
|
||||||
|
|
||||||
|
[bt.2020]
|
||||||
|
profile-cond=get("video-params/primaries") == "bt.2020" and get("video-params/gamma") == "bt.1886"
|
||||||
|
profile-restore=copy
|
||||||
|
target-prim=bt.2020
|
||||||
|
target-trc=bt.1886
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/transfer-function/bt1886_inv.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/gamut-mapping/bottosson.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/transfer-function/bt1886.glsl
|
||||||
|
|
||||||
|
[openexr]
|
||||||
|
profile-cond=get("file-format") == "exr_pipe"
|
||||||
|
profile-restore=copy
|
||||||
|
target-prim=bt.2020
|
||||||
|
target-trc=linear
|
||||||
|
scale=bilinear
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/utils/clip_black.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/tone-mapping/astra.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/gamut-mapping/jedypod.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/transfer-function/bt1886.glsl
|
||||||
|
|
||||||
|
[radiance]
|
||||||
|
profile-cond=get("file-format") == "hdr_pipe"
|
||||||
|
profile-restore=copy
|
||||||
|
target-prim=bt.2020
|
||||||
|
target-trc=linear
|
||||||
|
vf=format:gamma=linear
|
||||||
|
scale=bilinear
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/utils/clip_black.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/tone-mapping/astra.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/gamut-mapping/jedypod.glsl
|
||||||
|
glsl-shader=~~/shaders/hdr-toys/transfer-function/bt1886.glsl
|
|
@ -25,6 +25,12 @@ alt+i script-binding uosc/keybinds #! Utils > Key bindings
|
||||||
O script-binding uosc/show-in-directory #! Utils > Show in directory
|
O script-binding uosc/show-in-directory #! Utils > Show in directory
|
||||||
# script-binding uosc/open-config-directory #! Utils > Open config directory
|
# script-binding uosc/open-config-directory #! Utils > Open config directory
|
||||||
# script-binding uosc/update #! Utils > Update uosc
|
# script-binding uosc/update #! Utils > Update uosc
|
||||||
|
shift+h apply-profile HDR_MODE:SDR_HDR_EFFECT #! HDR > inverse-tone-mapping
|
||||||
|
ctrl+shift+h apply-profile HDR_MODE:SDR_HDR_EFFECT restore #! HDR > Undo inverse-tone-mapping
|
||||||
|
# apply-profile HDR_MODE:SDR #! HDR > SDR under HDR
|
||||||
|
# apply-profile HDR_MODE:SDR restore #! HDR > Revert SDR under HDR
|
||||||
|
# apply-profile HDR_MODE:DOVI #! HDR > Dolby Vision
|
||||||
|
# apply-profile HDR_MODE:DOVI restore #! HDR > Dolby Vision
|
||||||
|
|
||||||
CTRL+1 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_VL.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode A (HQ)"
|
CTRL+1 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_VL.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode A (HQ)"
|
||||||
CTRL+2 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_Soft_VL.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode B (HQ)"
|
CTRL+2 no-osd change-list glsl-shaders set "~~/shaders/Anime4K_Clamp_Highlights.glsl:~~/shaders/Anime4K_Restore_CNN_Soft_VL.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_VL.glsl:~~/shaders/Anime4K_AutoDownscalePre_x2.glsl:~~/shaders/Anime4K_AutoDownscalePre_x4.glsl:~~/shaders/Anime4K_Upscale_CNN_x2_M.glsl"; show-text "Anime4K: Mode B (HQ)"
|
||||||
|
|
41
mpv/mpv.conf
41
mpv/mpv.conf
|
@ -115,17 +115,38 @@ target-colorspace-hint=auto
|
||||||
# target-peak=auto
|
# target-peak=auto
|
||||||
# gamut-mapping-mode=perceptual
|
# gamut-mapping-mode=perceptual
|
||||||
# hdr-contrast-recovery=1.0
|
# hdr-contrast-recovery=1.0
|
||||||
#
|
|
||||||
# [HDR_MODE:DOVI]
|
[HDR_MODE:DOVI]
|
||||||
# profile-restore=copy
|
profile-restore=copy
|
||||||
# #Automatically enables profile if DoVi video is played. Seems to work but maybe there a better way?
|
#Automatically enables profile if DoVi video is played. Seems to work but maybe there a better way?
|
||||||
# profile-cond=(p["video-dec-params/gamma"] == "auto")
|
# profile-cond=(p["video-dec-params/gamma"] == "auto")
|
||||||
# target-trc=pq
|
target-trc=pq
|
||||||
# target-prim=bt.2020
|
target-prim=bt.2020
|
||||||
# #Adjust this to the peak brightness of your display. e.g. 800 for LG CX
|
#Adjust this to the peak brightness of your display. e.g. 800 for LG CX
|
||||||
# target-peak=1500
|
target-peak=1037
|
||||||
# #Only necessary if you are switching between different profiles like me SDR_TO_HDR tonemap profile
|
#Only necessary if you are switching between different profiles like me SDR_TO_HDR tonemap profile
|
||||||
# tone-mapping-mode=auto
|
tone-mapping-mode=auto
|
||||||
|
|
||||||
|
[HDR_MODE:SDR]
|
||||||
|
profile-restore=copy
|
||||||
|
target-trc=pq
|
||||||
|
target-prim=bt.2020
|
||||||
|
#Seems to be some kind of magic number, higher values do not have any effect
|
||||||
|
target-peak=200
|
||||||
|
tone-mapping=bt.2390
|
||||||
|
tone-mapping-mode=rgb
|
||||||
|
inverse-tone-mapping=yes
|
||||||
|
|
||||||
|
[HDR_MODE:SDR_HDR_EFFECT]
|
||||||
|
profile-restore=copy
|
||||||
|
target-trc=pq
|
||||||
|
target-prim=bt.2020
|
||||||
|
# Higher value = stronger effect
|
||||||
|
target-peak=400
|
||||||
|
tone-mapping=spline
|
||||||
|
# All other values make the colors look awful in my opinion.
|
||||||
|
tone-mapping-mode=rgb
|
||||||
|
inverse-tone-mapping=yes
|
||||||
|
|
||||||
###################################
|
###################################
|
||||||
# Protocol Specific Configuration #
|
# Protocol Specific Configuration #
|
||||||
|
|
13
mpv/scripts/hdr-toys.lua
Normal file
13
mpv/scripts/hdr-toys.lua
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
local options = require("mp.options")
|
||||||
|
|
||||||
|
local o = {
|
||||||
|
temporal_stable_time = 1 / 3,
|
||||||
|
}
|
||||||
|
options.read_options(o, _, function() end)
|
||||||
|
|
||||||
|
mp.observe_property("container-fps", "native", function (property, value)
|
||||||
|
if not value then return end
|
||||||
|
value = value * o.temporal_stable_time
|
||||||
|
value = math.floor(value + 0.5)
|
||||||
|
mp.command("no-osd set glsl-shader-opts temporal_stable_frames=" .. value)
|
||||||
|
end)
|
350
mpv/shaders/hdr-toys/gamut-mapping/bottosson.glsl
Normal file
350
mpv/shaders/hdr-toys/gamut-mapping/bottosson.glsl
Normal file
|
@ -0,0 +1,350 @@
|
||||||
|
// https://bottosson.github.io/posts/gamutclipping/
|
||||||
|
// https://www.shadertoy.com/view/7sXcWn
|
||||||
|
|
||||||
|
//!PARAM softness_scale
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 0.0
|
||||||
|
//!MAXIMUM 1.0
|
||||||
|
0.3
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC gamut mapping (bottosson, soft)
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec3 output_RGB_to_XYZ(vec3 RGB) {
|
||||||
|
mat3 M = mat3(
|
||||||
|
0.41239079926595934, 0.357584339383878, 0.1804807884018343,
|
||||||
|
0.21263900587151027, 0.715168678767756, 0.07219231536073371,
|
||||||
|
0.01933081871559182, 0.11919477979462598, 0.9505321522496607);
|
||||||
|
return RGB * M;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 output_XYZ_to_RGB(vec3 XYZ) {
|
||||||
|
mat3 M = mat3(
|
||||||
|
3.2409699419045226, -1.537383177570094, -0.4986107602930034,
|
||||||
|
-0.9692436362808796, 1.8759675015077202, 0.04155505740717559,
|
||||||
|
0.05563007969699366, -0.20397695888897652, 1.0569715142428786);
|
||||||
|
return XYZ * M;
|
||||||
|
}
|
||||||
|
|
||||||
|
float findCenter(vec3 x) {
|
||||||
|
float a = 1.9779985324311684 * x.x - 2.4285922420485799 * x.y + 0.4505937096174110 * x.z;
|
||||||
|
float b = 0.0259040424655478 * x.x + 0.7827717124575296 * x.y - 0.8086757549230774 * x.z;
|
||||||
|
float C = sqrt(a*a+b*b);
|
||||||
|
|
||||||
|
// Matrix derived for max(l,m,s) to be as close to macadam limit as possible
|
||||||
|
// this makes it some kind of g0-like estimate
|
||||||
|
mat3 M = mat3(
|
||||||
|
2.26923008, -1.43594808, 0.166718,
|
||||||
|
-0.98545265, 2.12616699, -0.14071434,
|
||||||
|
-0.02985871, -0.25753239, 1.2873911);
|
||||||
|
x = x*M;
|
||||||
|
|
||||||
|
float x_min = min(x.r,min(x.g,x.b));
|
||||||
|
float x_max = max(x.r,max(x.g,x.b));
|
||||||
|
|
||||||
|
float c = 0.5*(x_max+x_min);
|
||||||
|
float s = (x_max-x_min);
|
||||||
|
|
||||||
|
// math trickery to create values close to c and s, but without producing hard edges
|
||||||
|
vec3 y = (x-c)/s;
|
||||||
|
float c_smooth = c + dot(y*y*y, vec3(1.0/3.0))*s;
|
||||||
|
float s_smooth = sqrt(dot(x-c,x-c)/2.0);
|
||||||
|
|
||||||
|
return c_smooth;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 findCenterAndPurity(vec3 x) {
|
||||||
|
// Matrix derived for (c_smooth+s_smooth) to be an approximation of the macadam limit
|
||||||
|
// this makes it some kind of g0-like estimate
|
||||||
|
mat3 M = mat3(
|
||||||
|
2.26775149, -1.43293879, 0.1651873,
|
||||||
|
-0.98535505, 2.1260072, -0.14065215,
|
||||||
|
-0.02501605, -0.26349465, 1.2885107);
|
||||||
|
|
||||||
|
x = x*M;
|
||||||
|
|
||||||
|
float x_min = min(x.r,min(x.g,x.b));
|
||||||
|
float x_max = max(x.r,max(x.g,x.b));
|
||||||
|
|
||||||
|
float c = 0.5*(x_max+x_min);
|
||||||
|
float s = (x_max-x_min);
|
||||||
|
|
||||||
|
// math trickery to create values close to c and s, but without producing hard edges
|
||||||
|
vec3 y = (x-c)/s;
|
||||||
|
float c_smooth = c + dot(y*y*y, vec3(1.0/3.0))*s;
|
||||||
|
float s_smooth = sqrt(dot(x-c,x-c)/2.0);
|
||||||
|
return vec2(c_smooth, s_smooth);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
vec3 toLms(vec3 c) {
|
||||||
|
vec3 lms_ = XYZ_to_LMS(output_RGB_to_XYZ(c));
|
||||||
|
return sign(lms_)*pow(abs(lms_), vec3(1.0/3.0));
|
||||||
|
}
|
||||||
|
|
||||||
|
float calculateC(vec3 lms) {
|
||||||
|
// Most of this could be precomputed
|
||||||
|
// Creating a transform that maps R,G,B in the target gamut to have same distance from grey axis
|
||||||
|
|
||||||
|
vec3 lmsR = toLms(vec3(1.0,0.0,0.0));
|
||||||
|
vec3 lmsG = toLms(vec3(0.0,1.0,0.0));
|
||||||
|
vec3 lmsB = toLms(vec3(0.0,0.0,1.0));
|
||||||
|
|
||||||
|
vec3 uDir = (lmsR - lmsG)/sqrt(2.0);
|
||||||
|
vec3 vDir = (lmsR + lmsG - 2.0*lmsB)/sqrt(6.0);
|
||||||
|
|
||||||
|
mat3 to_uv = inverse(mat3(
|
||||||
|
1.0, uDir.x, vDir.x,
|
||||||
|
1.0, uDir.y, vDir.y,
|
||||||
|
1.0, uDir.z, vDir.z
|
||||||
|
));
|
||||||
|
|
||||||
|
vec3 _uv = lms * to_uv;
|
||||||
|
|
||||||
|
return sqrt(_uv.y*_uv.y + _uv.z*_uv.z);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 calculateLCh(vec3 c) {
|
||||||
|
vec3 lms = toLms(c);
|
||||||
|
|
||||||
|
float maxLms = findCenter(lms);
|
||||||
|
|
||||||
|
float a = 1.9779985324311684 * lms.x - 2.4285922420485799 * lms.y + 0.4505937096174110 * lms.z;
|
||||||
|
float b = 0.0259040424655478 * lms.x + 0.7827717124575296 * lms.y - 0.8086757549230774 * lms.z;
|
||||||
|
|
||||||
|
float C = sqrt(a*a+b*b);
|
||||||
|
|
||||||
|
return vec3(maxLms, C, atan(-b, -a));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 expandShape(vec3 rgb, vec2 ST) {
|
||||||
|
vec3 LCh = calculateLCh(rgb);
|
||||||
|
vec2 STnew = vec2(LCh.x/LCh.y, (1.0-LCh.x)/LCh.y);
|
||||||
|
STnew = (STnew + 3.0*STnew*STnew*LCh.y);
|
||||||
|
|
||||||
|
return vec2(min(ST.x, STnew.x), min(ST.y, STnew.y));
|
||||||
|
}
|
||||||
|
|
||||||
|
float expandScale(vec3 rgb, vec2 ST, float scale) {
|
||||||
|
vec3 LCh = calculateLCh(rgb);
|
||||||
|
float Cnew = (1.0/((ST.x/LCh.x) + (ST.y/(1.0-LCh.x))));
|
||||||
|
|
||||||
|
return max(LCh.y/Cnew, scale);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 approximateShape() {
|
||||||
|
float m = -softness_scale*0.2;
|
||||||
|
float s = 1.0 + (softness_scale*0.2+softness_scale*0.8);
|
||||||
|
|
||||||
|
vec2 ST = vec2(1000.0,1000.0);
|
||||||
|
ST = expandShape(m+s*vec3(1.0,0.0,0.0), ST);
|
||||||
|
ST = expandShape(m+s*vec3(1.0,1.0,0.0), ST);
|
||||||
|
ST = expandShape(m+s*vec3(0.0,1.0,0.0), ST);
|
||||||
|
ST = expandShape(m+s*vec3(0.0,1.0,1.0), ST);
|
||||||
|
ST = expandShape(m+s*vec3(0.0,0.0,1.0), ST);
|
||||||
|
ST = expandShape(m+s*vec3(1.0,0.0,1.0), ST);
|
||||||
|
|
||||||
|
float scale = 0.0;
|
||||||
|
scale = expandScale(m+s*vec3(1.0,0.0,0.0), ST, scale);
|
||||||
|
scale = expandScale(m+s*vec3(1.0,1.0,0.0), ST, scale);
|
||||||
|
scale = expandScale(m+s*vec3(0.0,1.0,0.0), ST, scale);
|
||||||
|
scale = expandScale(m+s*vec3(0.0,1.0,1.0), ST, scale);
|
||||||
|
scale = expandScale(m+s*vec3(0.0,0.0,1.0), ST, scale);
|
||||||
|
scale = expandScale(m+s*vec3(1.0,0.0,1.0), ST, scale);
|
||||||
|
|
||||||
|
return ST/scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 compute(float L, float hue, float sat) {
|
||||||
|
vec3 c = vec3(L, cos(hue), sin(hue));
|
||||||
|
|
||||||
|
float l_ = + 0.3963377773761749 * c.y + 0.2158037573099136 * c.z;
|
||||||
|
float m_ = - 0.1055613458156586 * c.y - 0.0638541728258133 * c.z;
|
||||||
|
float s_ = - 0.0894841775298119 * c.y - 1.2914855480194092 * c.z;
|
||||||
|
|
||||||
|
vec3 lms = vec3(l_,m_,s_);
|
||||||
|
|
||||||
|
vec2 MC = findCenterAndPurity(lms);
|
||||||
|
|
||||||
|
lms -= MC.x;
|
||||||
|
|
||||||
|
lms *= sat;
|
||||||
|
|
||||||
|
lms += c.x;
|
||||||
|
|
||||||
|
lms = lms*lms*lms;
|
||||||
|
|
||||||
|
vec3 rgb = output_XYZ_to_RGB(LMS_to_XYZ(lms));
|
||||||
|
|
||||||
|
return rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 softSaturate(vec3 x, vec3 a) {
|
||||||
|
a = clamp(a, 0.0,softness_scale);
|
||||||
|
a = 1.0+a;
|
||||||
|
x = min(x, a);
|
||||||
|
vec3 b = (a-1.0)*sqrt(a/(2.0-a));
|
||||||
|
return 1.0 - (sqrt((x-a)*(x-a) + b*b) - b)/(sqrt(a*a+b*b)-b);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 softClipColor(vec3 color) {
|
||||||
|
// soft clip of rgb values to avoid artifacts of hard clipping
|
||||||
|
// causes hues distortions, but is a smooth mapping
|
||||||
|
|
||||||
|
float maxRGB = max(max(color.r, color.g), color.b);
|
||||||
|
float minRGB = min(min(color.r, color.g), color.b);
|
||||||
|
|
||||||
|
float grey = 0.2;
|
||||||
|
|
||||||
|
vec3 x = color-grey;
|
||||||
|
|
||||||
|
vec3 xsgn = sign(x);
|
||||||
|
vec3 xscale = 0.5 + xsgn*(0.5-grey);
|
||||||
|
x /= xscale;
|
||||||
|
|
||||||
|
float softness_0 = maxRGB/(1.0+softness_scale)*softness_scale;
|
||||||
|
float softness_1 = (1.0-minRGB)/(1.0+softness_scale)*softness_scale;
|
||||||
|
|
||||||
|
vec3 softness = vec3(0.5)*(softness_0+softness_1 + xsgn*(softness_1 - softness_0));
|
||||||
|
|
||||||
|
return grey + xscale*xsgn*softSaturate(abs(x), softness);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
vec3 lch = Lab_to_LCh(RGB_to_Lab(color.rgb));
|
||||||
|
|
||||||
|
float L = lch.x;
|
||||||
|
float C = lch.y;
|
||||||
|
float h = lch.z;
|
||||||
|
|
||||||
|
// if (L >= 1.0) {
|
||||||
|
// return vec4(vec3(1.0, 1.0, 1.0), color.a);
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if (L <= 0.0) {
|
||||||
|
// return vec4(vec3(0.0, 0.0, 0.0), color.a);
|
||||||
|
// }
|
||||||
|
|
||||||
|
if (C <= 1e-6) {
|
||||||
|
return color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec2 ST = approximateShape();
|
||||||
|
float C_smooth = (1.0 / ((ST.x / L) + (ST.y / max(1.0 - L, 1e-6))));
|
||||||
|
color.rgb = compute(L, h, C / sqrt(C * C / C_smooth / C_smooth + 1.0));
|
||||||
|
color.rgb = softClipColor(color.rgb);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
512
mpv/shaders/hdr-toys/gamut-mapping/clip.glsl
Normal file
512
mpv/shaders/hdr-toys/gamut-mapping/clip.glsl
Normal file
|
@ -0,0 +1,512 @@
|
||||||
|
// RGB to RGB conversion, includes chromatic adaptation transform
|
||||||
|
// All coordinates are based on the CIE 1931 2° chromaticity diagram
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC gamut mapping (clip)
|
||||||
|
|
||||||
|
// You can use custom chromaticity here.
|
||||||
|
// Example: BT.709 with a D93 white point: Chromaticity(BT709.r, BT709.g, BT709.b, D93)
|
||||||
|
// You can also define custom coordinates: Chromaticity(vec2(0.7347, 0.2653), BT709.g, BT709.b, D65)
|
||||||
|
|
||||||
|
#define from BT2020
|
||||||
|
#define to BT709
|
||||||
|
|
||||||
|
// White points of standard illuminants
|
||||||
|
// https://en.wikipedia.org/wiki/Standard_illuminant#White_points_of_standard_illuminants
|
||||||
|
|
||||||
|
const vec2 A = vec2(0.44757, 0.40745);
|
||||||
|
const vec2 B = vec2(0.34842, 0.35161);
|
||||||
|
const vec2 C = vec2(0.31006, 0.31616);
|
||||||
|
const vec2 D50 = vec2(0.34567, 0.35850);
|
||||||
|
const vec2 D55 = vec2(0.33242, 0.34743);
|
||||||
|
const vec2 D65 = vec2(0.31271, 0.32902);
|
||||||
|
const vec2 D75 = vec2(0.29902, 0.31485);
|
||||||
|
const vec2 D93 = vec2(0.28315, 0.29711);
|
||||||
|
const vec2 E = vec2(1.0/3.0, 1.0/3.0);
|
||||||
|
const vec2 F2 = vec2(0.37208, 0.37529);
|
||||||
|
const vec2 F7 = vec2(0.31292, 0.32933);
|
||||||
|
const vec2 F11 = vec2(0.38052, 0.37713);
|
||||||
|
const vec2 DCI = vec2(0.31400, 0.35100);
|
||||||
|
// It is also known as D60
|
||||||
|
const vec2 ACES = vec2(0.32168, 0.33767);
|
||||||
|
// Colour Matching Between OLED and CRT
|
||||||
|
// https://www.sony.jp/products/catalog/FUN_WhitePaper_OLED_ColorMatching_V1_00.pdf
|
||||||
|
const vec2 BRAVIA = vec2(0.3067, 0.318);
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Standard_illuminant#Illuminant_series_D
|
||||||
|
vec2 CIE_D(float T) {
|
||||||
|
// Compensate for the loss caused by the accuracy difference between the old and new standards
|
||||||
|
// c2 = 1.4387768775039337
|
||||||
|
// https://en.wikipedia.org/wiki/Planckian_locus#Planckian_locus_in_the_XYZ_color_space
|
||||||
|
T = (T * 1.4388) / 1.438;
|
||||||
|
|
||||||
|
// This formula is applicable to temperatures ranging from 4000K to 25000K
|
||||||
|
T = clamp(T, 4000.0, 25000.0);
|
||||||
|
|
||||||
|
float t1 = 1000.0 / T;
|
||||||
|
float t2 = t1 * t1;
|
||||||
|
float t3 = t1 * t2;
|
||||||
|
|
||||||
|
float x =
|
||||||
|
T <= 7000.0
|
||||||
|
? 0.244063 + 0.09911 * t1 + 2.9678 * t2 - 4.607 * t3
|
||||||
|
: 0.23704 + 0.24748 * t1 + 1.9018 * t2 - 2.0064 * t3;
|
||||||
|
|
||||||
|
// Daylight locus
|
||||||
|
float y = -0.275 + 2.87 * x - 3.0 * x * x;
|
||||||
|
|
||||||
|
return vec2(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://en.wikipedia.org/wiki/Planckian_locus#Approximation
|
||||||
|
vec2 Kang(float T) {
|
||||||
|
// This formula is applicable to temperatures ranging from 1667K to 25000K
|
||||||
|
T = clamp(T, 1667.0, 25000.0);
|
||||||
|
|
||||||
|
float t1 = 1000.0 / T;
|
||||||
|
float t2 = t1 * t1;
|
||||||
|
float t3 = t1 * t2;
|
||||||
|
|
||||||
|
float x =
|
||||||
|
T <= 4000.0
|
||||||
|
? -0.2661239 * t3 - 0.234358 * t2 + 0.8776956 * t1 + 0.17991
|
||||||
|
: -3.0258469 * t3 + 2.1070379 * t2 + 0.2226347 * t1 + 0.24039;
|
||||||
|
|
||||||
|
float x2 = x * x;
|
||||||
|
float x3 = x2 * x;
|
||||||
|
|
||||||
|
float y =
|
||||||
|
T <= 2222.0
|
||||||
|
? -1.1063814 * x3 - 1.3481102 * x2 - 2.18555832 * x - 0.20219683
|
||||||
|
: T <= 4000.0
|
||||||
|
? -0.9549476 * x3 - 1.37418593 * x2 - 2.09137015 * x - 0.16748867
|
||||||
|
: 3.081758 * x3 - 5.8733867 * x2 + 3.75112997 * x - 0.37001483;
|
||||||
|
|
||||||
|
return vec2(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Chromaticities
|
||||||
|
// https://www.itu.int/rec/T-REC-H.273
|
||||||
|
// https://github.com/colour-science/colour/tree/develop/colour/models/rgb/datasets
|
||||||
|
|
||||||
|
struct Chromaticity {
|
||||||
|
vec2 r, g, b, w;
|
||||||
|
};
|
||||||
|
|
||||||
|
// ITU-R BT.2020, ITU-R BT.2100
|
||||||
|
const Chromaticity BT2020 = Chromaticity(
|
||||||
|
vec2(0.708, 0.292),
|
||||||
|
vec2(0.170, 0.797),
|
||||||
|
vec2(0.131, 0.046),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// ITU-R BT.709, IEC 61966-2-1 (sRGB)
|
||||||
|
const Chromaticity BT709 = Chromaticity(
|
||||||
|
vec2(0.64, 0.33),
|
||||||
|
vec2(0.30, 0.60),
|
||||||
|
vec2(0.15, 0.06),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// ITU-R BT.601 (525 lines), SMPTE ST 240
|
||||||
|
const Chromaticity BT601_525 = Chromaticity(
|
||||||
|
vec2(0.630, 0.340),
|
||||||
|
vec2(0.310, 0.595),
|
||||||
|
vec2(0.155, 0.070),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// ITU-R BT.601 (625 lines), BT.470 (B/G), EBU 3213-E
|
||||||
|
const Chromaticity BT601_625 = Chromaticity(
|
||||||
|
vec2(0.64, 0.33),
|
||||||
|
vec2(0.29, 0.60),
|
||||||
|
vec2(0.15, 0.06),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// ITU-R BT.470 (M)
|
||||||
|
const Chromaticity BT470m = Chromaticity(
|
||||||
|
vec2(0.67, 0.33),
|
||||||
|
vec2(0.21, 0.71),
|
||||||
|
vec2(0.14, 0.08),
|
||||||
|
C
|
||||||
|
);
|
||||||
|
|
||||||
|
// P3-DCI (Theater)
|
||||||
|
const Chromaticity P3DCI = Chromaticity(
|
||||||
|
vec2(0.680, 0.320),
|
||||||
|
vec2(0.265, 0.690),
|
||||||
|
vec2(0.150, 0.060),
|
||||||
|
DCI
|
||||||
|
);
|
||||||
|
|
||||||
|
// P3-D65 (Display)
|
||||||
|
const Chromaticity P3D65 = Chromaticity(
|
||||||
|
P3DCI.r,
|
||||||
|
P3DCI.g,
|
||||||
|
P3DCI.b,
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// P3-D60 (ACES Cinema)
|
||||||
|
const Chromaticity P3D60 = Chromaticity(
|
||||||
|
P3DCI.r,
|
||||||
|
P3DCI.g,
|
||||||
|
P3DCI.b,
|
||||||
|
ACES
|
||||||
|
);
|
||||||
|
|
||||||
|
// ITU-T H.273 (Generic film)
|
||||||
|
const Chromaticity H273_8 = Chromaticity(
|
||||||
|
vec2(0.681, 0.319),
|
||||||
|
vec2(0.243, 0.692),
|
||||||
|
vec2(0.145, 0.049),
|
||||||
|
C
|
||||||
|
);
|
||||||
|
|
||||||
|
// ITU-T H.273 (No corresponding industry specification identified)
|
||||||
|
const Chromaticity H273_22 = Chromaticity(
|
||||||
|
vec2(0.630, 0.340),
|
||||||
|
vec2(0.295, 0.605),
|
||||||
|
vec2(0.155, 0.077),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// CIE RGB (CIE 1931 color space)
|
||||||
|
const Chromaticity CIERGB = Chromaticity(
|
||||||
|
vec2(0.73474284, 0.26525716),
|
||||||
|
vec2(0.27377903, 0.7174777),
|
||||||
|
vec2(0.16655563, 0.00891073),
|
||||||
|
E
|
||||||
|
);
|
||||||
|
|
||||||
|
// CIE XYZ (CIE 1931 color space)
|
||||||
|
const Chromaticity XYZ = Chromaticity(
|
||||||
|
vec2(1.0, 0.0),
|
||||||
|
vec2(0.0, 1.0),
|
||||||
|
vec2(0.0, 0.0),
|
||||||
|
E
|
||||||
|
);
|
||||||
|
|
||||||
|
// CIE XYZ (CIE 1931 color space, D65 whitepoint)
|
||||||
|
const Chromaticity XYZD65 = Chromaticity(
|
||||||
|
XYZ.r,
|
||||||
|
XYZ.g,
|
||||||
|
XYZ.b,
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// CIE XYZ (CIE 1931 color space, D50 whitepoint)
|
||||||
|
const Chromaticity XYZD50 = Chromaticity(
|
||||||
|
XYZ.r,
|
||||||
|
XYZ.g,
|
||||||
|
XYZ.b,
|
||||||
|
D50
|
||||||
|
);
|
||||||
|
|
||||||
|
// Grayscale, Monochrome
|
||||||
|
const Chromaticity GRAY = Chromaticity(
|
||||||
|
vec2(0.0, 1.0),
|
||||||
|
vec2(0.0, 1.0),
|
||||||
|
vec2(0.0, 1.0),
|
||||||
|
E
|
||||||
|
);
|
||||||
|
|
||||||
|
// Adobe RGB (1998)
|
||||||
|
const Chromaticity AdobeRGB = Chromaticity(
|
||||||
|
vec2(0.64, 0.33),
|
||||||
|
vec2(0.21, 0.71),
|
||||||
|
vec2(0.15, 0.06),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// Adobe Wide Gamut RGB
|
||||||
|
const Chromaticity AdobeWideGamutRGB = Chromaticity(
|
||||||
|
vec2(0.7347, 0.2653),
|
||||||
|
vec2(0.1152, 0.8264),
|
||||||
|
vec2(0.1566, 0.0177),
|
||||||
|
D50
|
||||||
|
);
|
||||||
|
|
||||||
|
// ROMM (ProPhoto RGB)
|
||||||
|
const Chromaticity ROMM = Chromaticity(
|
||||||
|
vec2(0.734699, 0.265301),
|
||||||
|
vec2(0.159597, 0.840403),
|
||||||
|
vec2(0.036598, 0.000105),
|
||||||
|
D50
|
||||||
|
);
|
||||||
|
|
||||||
|
// AP0 (ACES 2065-1)
|
||||||
|
const Chromaticity AP0 = Chromaticity(
|
||||||
|
vec2(0.7347, 0.2653),
|
||||||
|
vec2(0.0000, 1.0000),
|
||||||
|
vec2(0.0001, -0.0770),
|
||||||
|
ACES
|
||||||
|
);
|
||||||
|
|
||||||
|
// AP1 (ACEScg, cc, cct, proxy)
|
||||||
|
const Chromaticity AP1 = Chromaticity(
|
||||||
|
vec2(0.713, 0.293),
|
||||||
|
vec2(0.165, 0.830),
|
||||||
|
vec2(0.128, 0.044),
|
||||||
|
ACES
|
||||||
|
);
|
||||||
|
|
||||||
|
// ARRI Wide Gamut 3
|
||||||
|
const Chromaticity AWG3 = Chromaticity(
|
||||||
|
vec2(0.684, 0.313),
|
||||||
|
vec2(0.221, 0.848),
|
||||||
|
vec2(0.0861, -0.102),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// ARRI Wide Gamut 4
|
||||||
|
const Chromaticity AWG4 = Chromaticity(
|
||||||
|
vec2(0.7347, 0.2653),
|
||||||
|
vec2(0.1424, 0.8576),
|
||||||
|
vec2(0.0991, -0.0308),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// RED Wide Gamut RGB
|
||||||
|
const Chromaticity RWG = Chromaticity(
|
||||||
|
vec2(0.780308, 0.304253),
|
||||||
|
vec2(0.121595, 1.493994),
|
||||||
|
vec2(0.095612, -0.084589),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// DaVinci Wide Gamut
|
||||||
|
const Chromaticity DWG = Chromaticity(
|
||||||
|
vec2(0.8000, 0.3130),
|
||||||
|
vec2(0.1682, 0.9877),
|
||||||
|
vec2(0.0790, -0.1155),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// FilmLight E-Gamut
|
||||||
|
const Chromaticity EGAMUT = Chromaticity(
|
||||||
|
vec2(0.8000, 0.3177),
|
||||||
|
vec2(0.1800, 0.9000),
|
||||||
|
vec2(0.0650, -0.0805),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// FilmLight E-Gamut 2
|
||||||
|
const Chromaticity EGAMUT2 = Chromaticity(
|
||||||
|
vec2(0.8300, 0.3100),
|
||||||
|
vec2(0.1500, 0.9500),
|
||||||
|
vec2(0.0650, -0.0805),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// FUJIFILM F-Gamut C
|
||||||
|
const Chromaticity FGAMUTC = Chromaticity(
|
||||||
|
vec2(0.7347, 0.2653),
|
||||||
|
vec2(0.0263, 0.9737),
|
||||||
|
vec2(0.1173, -0.0224),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// Sony S-Gamut3/S-Gamut
|
||||||
|
const Chromaticity SGAMUT = Chromaticity(
|
||||||
|
vec2(0.73, 0.280),
|
||||||
|
vec2(0.14, 0.855),
|
||||||
|
vec2(0.10, -0.050),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// Sony S-Gamut.Cine
|
||||||
|
const Chromaticity SGAMUTCINE = Chromaticity(
|
||||||
|
vec2(0.766, 0.275),
|
||||||
|
vec2(0.225, 0.800),
|
||||||
|
vec2(0.089, -0.087),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// Canon Cinema Gamut
|
||||||
|
const Chromaticity CINEMA_GAMUT = Chromaticity(
|
||||||
|
vec2(0.74, 0.27),
|
||||||
|
vec2(0.17, 1.14),
|
||||||
|
vec2(0.08, -0.10),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// Panasonic V-Gamut
|
||||||
|
const Chromaticity VGAMUT = Chromaticity(
|
||||||
|
vec2(0.730, 0.28),
|
||||||
|
vec2(0.165, 0.84),
|
||||||
|
vec2(0.100, -0.03),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// DJI D-Gamut
|
||||||
|
const Chromaticity DGAMUT = Chromaticity(
|
||||||
|
vec2(0.71, 0.31),
|
||||||
|
vec2(0.21, 0.88),
|
||||||
|
vec2(0.09, -0.08),
|
||||||
|
D65
|
||||||
|
);
|
||||||
|
|
||||||
|
// Chromatic adaptation transform
|
||||||
|
// https://en.wikipedia.org/wiki/LMS_color_space
|
||||||
|
|
||||||
|
// It is also known as von Kries
|
||||||
|
const mat3 HPE = mat3(
|
||||||
|
0.40024, 0.70760, -0.08081,
|
||||||
|
-0.22630, 1.16532, 0.04570,
|
||||||
|
0.00000, 0.00000, 0.91822
|
||||||
|
);
|
||||||
|
|
||||||
|
const mat3 Bradford = mat3(
|
||||||
|
0.8951, 0.2664, -0.1614,
|
||||||
|
-0.7502, 1.7135, 0.0367,
|
||||||
|
0.0389, -0.0685, 1.0296
|
||||||
|
);
|
||||||
|
|
||||||
|
const mat3 CAT97 = mat3(
|
||||||
|
0.8562, 0.3372, -0.1934,
|
||||||
|
-0.8360, 1.8327, 0.0033,
|
||||||
|
0.0357, -0.0469, 1.0112
|
||||||
|
);
|
||||||
|
|
||||||
|
const mat3 CAT02 = mat3(
|
||||||
|
0.7328, 0.4296, -0.1624,
|
||||||
|
-0.7036, 1.6975, 0.0061,
|
||||||
|
0.0030, 0.0136, 0.9834
|
||||||
|
);
|
||||||
|
|
||||||
|
const mat3 CAT16 = mat3(
|
||||||
|
0.401288, 0.650173, -0.051461,
|
||||||
|
-0.250268, 1.204414, 0.045854,
|
||||||
|
-0.002079, 0.048952, 0.953127
|
||||||
|
);
|
||||||
|
|
||||||
|
// Other constants
|
||||||
|
|
||||||
|
const mat3 Identity3 = mat3(
|
||||||
|
1.0, 0.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0,
|
||||||
|
0.0, 0.0, 1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
const mat3 SingularY3 = mat3(
|
||||||
|
0.0, 1.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0,
|
||||||
|
0.0, 1.0, 0.0
|
||||||
|
);
|
||||||
|
|
||||||
|
// http://www.brucelindbloom.com/Eqn_xyY_to_XYZ.html
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://www.brucelindbloom.com/Eqn_XYZ_to_xyY.html
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://www.brucelindbloom.com/Eqn_RGB_XYZ_Matrix.html
|
||||||
|
mat3 RGB_to_XYZ(Chromaticity C) {
|
||||||
|
if (C == GRAY)
|
||||||
|
return Identity3;
|
||||||
|
|
||||||
|
vec3 r = xyY_to_XYZ(vec3(C.r, 1.0));
|
||||||
|
vec3 g = xyY_to_XYZ(vec3(C.g, 1.0));
|
||||||
|
vec3 b = xyY_to_XYZ(vec3(C.b, 1.0));
|
||||||
|
vec3 w = xyY_to_XYZ(vec3(C.w, 1.0));
|
||||||
|
|
||||||
|
mat3 xyz = transpose(mat3(r, g, b));
|
||||||
|
|
||||||
|
vec3 scale = w * inverse(xyz);
|
||||||
|
mat3 scale_diag = mat3(
|
||||||
|
scale.x, 0.0, 0.0,
|
||||||
|
0.0, scale.y, 0.0,
|
||||||
|
0.0, 0.0, scale.z
|
||||||
|
);
|
||||||
|
|
||||||
|
return scale_diag * xyz;
|
||||||
|
}
|
||||||
|
|
||||||
|
mat3 XYZ_to_RGB(Chromaticity C) {
|
||||||
|
if (C == GRAY)
|
||||||
|
return SingularY3;
|
||||||
|
|
||||||
|
return inverse(RGB_to_XYZ(C));
|
||||||
|
}
|
||||||
|
|
||||||
|
// http://www.brucelindbloom.com/Eqn_ChromAdapt.html
|
||||||
|
mat3 adaptation(vec2 w1, vec2 w2, mat3 cat) {
|
||||||
|
vec3 src_xyz = xyY_to_XYZ(vec3(w1, 1.0));
|
||||||
|
vec3 dst_xyz = xyY_to_XYZ(vec3(w2, 1.0));
|
||||||
|
|
||||||
|
vec3 src_lms = src_xyz * cat;
|
||||||
|
vec3 dst_lms = dst_xyz * cat;
|
||||||
|
|
||||||
|
vec3 scale = dst_lms / src_lms;
|
||||||
|
mat3 scale_diag = mat3(
|
||||||
|
scale.x, 0.0, 0.0,
|
||||||
|
0.0, scale.y, 0.0,
|
||||||
|
0.0, 0.0, scale.z
|
||||||
|
);
|
||||||
|
|
||||||
|
return cat * scale_diag * inverse(cat);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CAM16 uses CAT16 as cat and equal-energy illuminant (E) as wt.
|
||||||
|
// https://www.researchgate.net/publication/318152296_Comprehensive_color_solutions_CAM16_CAT16_and_CAM16-UCS
|
||||||
|
// Android uses Bradford as cat and D50 as wt.
|
||||||
|
// https://android.googlesource.com/platform/frameworks/base/+/master/graphics/java/android/graphics/ColorSpace.java
|
||||||
|
mat3 adaptation_two_step(vec2 w1, vec2 w2, vec2 wt, mat3 cat) {
|
||||||
|
return adaptation(w1, wt, cat) * adaptation(wt, w2, cat);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat3 adaptation_two_step(vec2 w1, vec2 w2) {
|
||||||
|
return adaptation_two_step(w1, w2, E, CAT16);
|
||||||
|
}
|
||||||
|
|
||||||
|
mat3 RGB_to_RGB(Chromaticity c1, Chromaticity c2) {
|
||||||
|
mat3 m = Identity3;
|
||||||
|
if (c1 != c2) {
|
||||||
|
m *= RGB_to_XYZ(c1);
|
||||||
|
if (c1.w != c2.w) {
|
||||||
|
m *= adaptation_two_step(c1.w, c2.w);
|
||||||
|
}
|
||||||
|
m *= XYZ_to_RGB(c2);
|
||||||
|
}
|
||||||
|
return m;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 RGB_to_RGB(vec3 c, Chromaticity c1, Chromaticity c2) {
|
||||||
|
return c * RGB_to_RGB(c1, c2);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = RGB_to_RGB(color.rgb, from, to);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
104
mpv/shaders/hdr-toys/gamut-mapping/false.glsl
Normal file
104
mpv/shaders/hdr-toys/gamut-mapping/false.glsl
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// Visualizes the out of gamut colors using false color.
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC gamut mapping (false color)
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 BT2020_to_BT709(vec3 color) {
|
||||||
|
return color * mat3(
|
||||||
|
1.66049100210843540, -0.58764113878854950, -0.072849863319884740,
|
||||||
|
-0.12455047452159074, 1.13289989712595960, -0.008349422604369515,
|
||||||
|
-0.01815076335490526, -0.10057889800800737, 1.118729661362913000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
vec3 color_dst = BT2020_to_BT709(color.rgb);
|
||||||
|
vec3 color_dst_cliped = clamp(color_dst, 0.0, 1.0);
|
||||||
|
bool is_in_gamut = color_dst == color_dst_cliped;
|
||||||
|
|
||||||
|
color.rgb = RGB_to_Lab(color.rgb);
|
||||||
|
color.rgb = is_in_gamut ? vec3(color.x, vec2(0.0)) : vec3(0.5, color.yz);
|
||||||
|
color.rgb = Lab_to_RGB(color.rgb);
|
||||||
|
color.rgb = BT2020_to_BT709(color.rgb);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
88
mpv/shaders/hdr-toys/gamut-mapping/jedypod.glsl
Normal file
88
mpv/shaders/hdr-toys/gamut-mapping/jedypod.glsl
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// https://github.com/jedypod/gamut-compress
|
||||||
|
// https://github.com/ampas/aces-dev/blob/dev/transforms/ctl/lmt/LMT.Academy.ReferenceGamutCompress.ctl
|
||||||
|
|
||||||
|
//!PARAM cyan_limit
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 1.01
|
||||||
|
//!MAXIMUM 2.0
|
||||||
|
1.216
|
||||||
|
|
||||||
|
//!PARAM magenta_limit
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 1.01
|
||||||
|
//!MAXIMUM 2.0
|
||||||
|
1.035
|
||||||
|
|
||||||
|
//!PARAM yellow_limit
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 1.01
|
||||||
|
//!MAXIMUM 2.0
|
||||||
|
1.076
|
||||||
|
|
||||||
|
//!PARAM cyan_threshold
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 0.0
|
||||||
|
//!MAXIMUM 1.0
|
||||||
|
0.998
|
||||||
|
|
||||||
|
//!PARAM magenta_threshold
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 0.0
|
||||||
|
//!MAXIMUM 1.0
|
||||||
|
0.940
|
||||||
|
|
||||||
|
//!PARAM yellow_threshold
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 0.0
|
||||||
|
//!MAXIMUM 1.0
|
||||||
|
0.977
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC gamut mapping (jedypod)
|
||||||
|
|
||||||
|
// Parabolic compression function
|
||||||
|
// https://www.desmos.com/calculator/khowxlu6xh
|
||||||
|
float parabolic(float x, float t0, float x0, float y0) {
|
||||||
|
float s = (y0 - t0) / sqrt(x0 - y0);
|
||||||
|
float ox = t0 - s * s / 4.0;
|
||||||
|
float oy = t0 - s * sqrt(s * s / 4.0);
|
||||||
|
return (x < t0 ? x : s * sqrt(x - ox) + oy);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 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(
|
||||||
|
parabolic(d.x, cyan_threshold, cyan_limit, 1.0),
|
||||||
|
parabolic(d.y, magenta_threshold, magenta_limit, 1.0),
|
||||||
|
parabolic(d.z, yellow_threshold, yellow_limit, 1.0)
|
||||||
|
);
|
||||||
|
|
||||||
|
// Inverse RGB Ratios to RGB
|
||||||
|
vec3 crgb = ac - cd * abs(ac);
|
||||||
|
|
||||||
|
return crgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 BT2020_to_BT709(vec3 color) {
|
||||||
|
return color * mat3(
|
||||||
|
1.66049100210843540, -0.58764113878854950, -0.072849863319884740,
|
||||||
|
-0.12455047452159074, 1.13289989712595960, -0.008349422604369515,
|
||||||
|
-0.01815076335490526, -0.10057889800800737, 1.118729661362913000
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = BT2020_to_BT709(color.rgb);
|
||||||
|
color.rgb = gamut_compress(color.rgb);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
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;
|
||||||
|
}
|
28
mpv/shaders/hdr-toys/transfer-function/bt1886.glsl
Normal file
28
mpv/shaders/hdr-toys/transfer-function/bt1886.glsl
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.1886
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transfer function (bt.1886)
|
||||||
|
|
||||||
|
float bt1886_eotf_inv(float L, float gamma, float Lw, float Lb) {
|
||||||
|
float a = pow(pow(Lw, 1.0 / gamma) - pow(Lb, 1.0 / gamma), gamma);
|
||||||
|
float b = pow(Lb, 1.0 / gamma) / (pow(Lw, 1.0 / gamma) - pow(Lb, 1.0 / gamma));
|
||||||
|
float V = pow(max(L / a, 0.0), 1.0 / gamma) - b;
|
||||||
|
return V;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bt1886_eotf_inv(vec3 color, float gamma, float Lw, float Lb) {
|
||||||
|
return vec3(
|
||||||
|
bt1886_eotf_inv(color.r, gamma, Lw, Lb),
|
||||||
|
bt1886_eotf_inv(color.g, gamma, Lw, Lb),
|
||||||
|
bt1886_eotf_inv(color.b, gamma, Lw, Lb)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = bt1886_eotf_inv(color.rgb, 2.4, 1.0, 0.001);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
28
mpv/shaders/hdr-toys/transfer-function/bt1886_inv.glsl
Normal file
28
mpv/shaders/hdr-toys/transfer-function/bt1886_inv.glsl
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.1886
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transfer function (bt.1886, inverse)
|
||||||
|
|
||||||
|
float bt1886_eotf(float V, float gamma, float Lw, float Lb) {
|
||||||
|
float a = pow(pow(Lw, 1.0 / gamma) - pow(Lb, 1.0 / gamma), gamma);
|
||||||
|
float b = pow(Lb, 1.0 / gamma) / (pow(Lw, 1.0 / gamma) - pow(Lb, 1.0 / gamma));
|
||||||
|
float L = a * pow(max(V + b, 0.0), gamma);
|
||||||
|
return L;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bt1886_eotf(vec3 color, float gamma, float Lw, float Lb) {
|
||||||
|
return vec3(
|
||||||
|
bt1886_eotf(color.r, gamma, Lw, Lb),
|
||||||
|
bt1886_eotf(color.g, gamma, Lw, Lb),
|
||||||
|
bt1886_eotf(color.b, gamma, Lw, Lb)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = bt1886_eotf(color.rgb, 2.4, 1.0, 0.001);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
30
mpv/shaders/hdr-toys/transfer-function/bt709.glsl
Normal file
30
mpv/shaders/hdr-toys/transfer-function/bt709.glsl
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.601
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.709
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.2020
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transfer function (bt.709)
|
||||||
|
|
||||||
|
const float beta = 0.018053968510807;
|
||||||
|
const float alpha = 1.0 + 5.5 * beta;
|
||||||
|
|
||||||
|
float bt709_oetf(float L) {
|
||||||
|
return L < beta ? 4.5 * L : alpha * pow(L, 0.45) - (alpha - 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bt709_oetf(vec3 color) {
|
||||||
|
return vec3(
|
||||||
|
bt709_oetf(color.r),
|
||||||
|
bt709_oetf(color.g),
|
||||||
|
bt709_oetf(color.b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = bt709_oetf(color.rgb);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
30
mpv/shaders/hdr-toys/transfer-function/bt709_inv.glsl
Normal file
30
mpv/shaders/hdr-toys/transfer-function/bt709_inv.glsl
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.601
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.709
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.2020
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transfer function (bt.709, inverse)
|
||||||
|
|
||||||
|
const float beta = 0.018053968510807;
|
||||||
|
const float alpha = 1.0 + 5.5 * beta;
|
||||||
|
|
||||||
|
float bt709_oetf_inv(float V) {
|
||||||
|
return V < 4.5 * beta ? V / 4.5 : pow((V + (alpha - 1.0)) / alpha, 1.0 / 0.45);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 bt709_oetf_inv(vec3 color) {
|
||||||
|
return vec3(
|
||||||
|
bt709_oetf_inv(color.r),
|
||||||
|
bt709_oetf_inv(color.g),
|
||||||
|
bt709_oetf_inv(color.b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = bt709_oetf_inv(color.rgb);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
60
mpv/shaders/hdr-toys/transfer-function/hlg.glsl
Normal file
60
mpv/shaders/hdr-toys/transfer-function/hlg.glsl
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
// https://www.arib.or.jp/kikaku/kikaku_hoso/std-b67.html
|
||||||
|
// https://www.bbc.co.uk/rd/projects/high-dynamic-range
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.2100
|
||||||
|
|
||||||
|
// https://www.itu.int/pub/R-REP-BT.2390
|
||||||
|
// extended gamma model for Lw is outside 400-2000 cd/m²:
|
||||||
|
// 1.2 * pow(1.111, log2(Lw / 1000.0)) * pow(0.98, log2(Lamb / 5.0))
|
||||||
|
|
||||||
|
//!PARAM reference_white
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 0.0
|
||||||
|
//!MAXIMUM 1000.0
|
||||||
|
203.0
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transfer function (hlg)
|
||||||
|
|
||||||
|
const vec3 y_coef = vec3(0.2627002120112671, 0.6779980715188708, 0.05930171646986196);
|
||||||
|
|
||||||
|
const float Lw = 1000.0;
|
||||||
|
const float Lb = 0.0;
|
||||||
|
const float Lamb = 5.0;
|
||||||
|
|
||||||
|
const float gamma = 1.2 + 0.42 * log(Lw / 1000.0) / log(10.0) - 0.076 * log(Lamb / 5.0) / log(10.0);
|
||||||
|
const float alpha = Lw;
|
||||||
|
const float beta = sqrt(3.0 * pow((Lb / Lw), 1.0 / gamma));
|
||||||
|
|
||||||
|
const float a = 0.17883277;
|
||||||
|
const float b = 1.0 - 4.0 * a;
|
||||||
|
const float c = 0.5 - a * log(4.0 * a);
|
||||||
|
|
||||||
|
float hlg_oetf(float x) {
|
||||||
|
return x <= 1.0 / 12.0 ? sqrt(3.0 * x) : a * log(12.0 * x - b) + c;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hlg_oetf(vec3 color) {
|
||||||
|
return vec3(
|
||||||
|
hlg_oetf(color.r),
|
||||||
|
hlg_oetf(color.g),
|
||||||
|
hlg_oetf(color.b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hlg_ootf_inv(vec3 color) {
|
||||||
|
float Y = dot(color, y_coef);
|
||||||
|
return Y == 0.0 ? vec3(0.0) : pow(Y / alpha, (1.0 - gamma) / gamma) * (color / alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hlg_eotf_inv(vec3 color) {
|
||||||
|
return (hlg_oetf(hlg_ootf_inv(color)) - beta) / (1.0 - beta);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = hlg_eotf_inv(color.rgb * reference_white);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
56
mpv/shaders/hdr-toys/transfer-function/hlg_inv.glsl
Normal file
56
mpv/shaders/hdr-toys/transfer-function/hlg_inv.glsl
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// https://www.arib.or.jp/kikaku/kikaku_hoso/std-b67.html
|
||||||
|
// https://www.bbc.co.uk/rd/projects/high-dynamic-range
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.2100
|
||||||
|
|
||||||
|
//!PARAM reference_white
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 0.0
|
||||||
|
//!MAXIMUM 1000.0
|
||||||
|
203.0
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transfer function (hlg, inverse)
|
||||||
|
|
||||||
|
const vec3 y_coef = vec3(0.2627002120112671, 0.6779980715188708, 0.05930171646986196);
|
||||||
|
|
||||||
|
const float Lw = 1000.0;
|
||||||
|
const float Lb = 0.0;
|
||||||
|
const float Lamb = 5.0;
|
||||||
|
|
||||||
|
const float gamma = 1.2 + 0.42 * log(Lw / 1000.0) / log(10.0) - 0.076 * log(Lamb / 5.0) / log(10.0);
|
||||||
|
const float alpha = Lw;
|
||||||
|
const float beta = sqrt(3.0 * pow((Lb / Lw), 1.0 / gamma));
|
||||||
|
|
||||||
|
const float a = 0.17883277;
|
||||||
|
const float b = 1.0 - 4.0 * a;
|
||||||
|
const float c = 0.5 - a * log(4.0 * a);
|
||||||
|
|
||||||
|
float hlg_oetf_inv(float x) {
|
||||||
|
return x <= 1.0 / 2.0 ? pow(x, 2.0) / 3.0 : (exp((x - c) / a) + b) / 12.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hlg_oetf_inv(vec3 color) {
|
||||||
|
return vec3(
|
||||||
|
hlg_oetf_inv(color.r),
|
||||||
|
hlg_oetf_inv(color.g),
|
||||||
|
hlg_oetf_inv(color.b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hlg_ootf(vec3 color) {
|
||||||
|
float Y = dot(color, y_coef);
|
||||||
|
return alpha * pow(Y, gamma - 1.0) * color;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 hlg_eotf(vec3 color) {
|
||||||
|
return hlg_ootf(hlg_oetf_inv(max((1.0 - beta) * color + beta, 0.0)));
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = hlg_eotf(color.rgb) / reference_white;
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
43
mpv/shaders/hdr-toys/transfer-function/pq.glsl
Normal file
43
mpv/shaders/hdr-toys/transfer-function/pq.glsl
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
// https://ieeexplore.ieee.org/document/7291452
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.2100
|
||||||
|
|
||||||
|
// https://www.itu.int/pub/R-REP-BT.2390
|
||||||
|
// pq ootf: 100.0 * bt1886_eotf(bt709_oetf(59.5208 * x), 2.4, 1.0, 0.0)
|
||||||
|
|
||||||
|
//!PARAM reference_white
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 0.0
|
||||||
|
//!MAXIMUM 1000.0
|
||||||
|
203.0
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transfer function (pq)
|
||||||
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = pq_eotf_inv(color.rgb * reference_white);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
40
mpv/shaders/hdr-toys/transfer-function/pq_inv.glsl
Normal file
40
mpv/shaders/hdr-toys/transfer-function/pq_inv.glsl
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
// https://ieeexplore.ieee.org/document/7291452
|
||||||
|
// https://www.itu.int/rec/R-REC-BT.2100
|
||||||
|
|
||||||
|
//!PARAM reference_white
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM 0.0
|
||||||
|
//!MAXIMUM 1000.0
|
||||||
|
203.0
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transfer function (pq, inverse)
|
||||||
|
|
||||||
|
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(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)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = pq_eotf(color.rgb) / reference_white;
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
31
mpv/shaders/hdr-toys/transfer-function/srgb.glsl
Normal file
31
mpv/shaders/hdr-toys/transfer-function/srgb.glsl
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// https://github.com/ampas/aces-core/blob/dev/lib/Lib.Academy.DisplayEncoding.ctl
|
||||||
|
// moncurve with gamma of 2.4 and offset of 0.055 matches the EOTF found in IEC 61966-2-1:1999 (sRGB)
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transfer function (srgb)
|
||||||
|
|
||||||
|
const float gamma = 2.4;
|
||||||
|
const float offset = 0.055;
|
||||||
|
|
||||||
|
float monitor_curve_eotf_inv(float y) {
|
||||||
|
const float yb = pow(offset * gamma / ((gamma - 1.0) * (1.0 + offset)), gamma);
|
||||||
|
const float rs = pow((gamma - 1.0) / offset, gamma - 1.0) * pow((1.0 + offset) / gamma, gamma);
|
||||||
|
return y >= yb ? (1.0 + offset) * pow(y, 1.0 / gamma) - offset : y * rs;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 monitor_curve_eotf_inv(vec3 color) {
|
||||||
|
return vec3(
|
||||||
|
monitor_curve_eotf_inv(color.r),
|
||||||
|
monitor_curve_eotf_inv(color.g),
|
||||||
|
monitor_curve_eotf_inv(color.b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = monitor_curve_eotf_inv(color.rgb);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
31
mpv/shaders/hdr-toys/transfer-function/srgb_inv.glsl
Normal file
31
mpv/shaders/hdr-toys/transfer-function/srgb_inv.glsl
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
// https://github.com/ampas/aces-core/blob/dev/lib/Lib.Academy.DisplayEncoding.ctl
|
||||||
|
// moncurve with gamma of 2.4 and offset of 0.055 matches the EOTF found in IEC 61966-2-1:1999 (sRGB)
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transfer function (srgb, inverse)
|
||||||
|
|
||||||
|
const float gamma = 2.4;
|
||||||
|
const float offset = 0.055;
|
||||||
|
|
||||||
|
float monitor_curve_eotf(float x) {
|
||||||
|
const float fs = ((gamma - 1.0) / offset) * pow(offset * gamma / ((gamma - 1.0) * (1.0 + offset)), gamma);
|
||||||
|
const float xb = offset / (gamma - 1.0);
|
||||||
|
return x >= xb ? pow((x + offset) / (1.0 + offset), gamma) : x * fs;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 monitor_curve_eotf(vec3 color) {
|
||||||
|
return vec3(
|
||||||
|
monitor_curve_eotf(color.r),
|
||||||
|
monitor_curve_eotf(color.g),
|
||||||
|
monitor_curve_eotf(color.b)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = monitor_curve_eotf(color.rgb);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
11
mpv/shaders/hdr-toys/utils/clip_black.glsl
Normal file
11
mpv/shaders/hdr-toys/utils/clip_black.glsl
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC clip code value (black)
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = max(color.rgb, 0.0);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
11
mpv/shaders/hdr-toys/utils/clip_both.glsl
Normal file
11
mpv/shaders/hdr-toys/utils/clip_both.glsl
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC clip code value (black, white)
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = clamp(color.rgb, 0.0, 1.0);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
11
mpv/shaders/hdr-toys/utils/clip_white.glsl
Normal file
11
mpv/shaders/hdr-toys/utils/clip_white.glsl
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC clip code value (white)
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = min(color.rgb, 1.0);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
83
mpv/shaders/hdr-toys/utils/edge_detection.glsl
Normal file
83
mpv/shaders/hdr-toys/utils/edge_detection.glsl
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// https://anirban-karchaudhuri.medium.com/edge-detection-methods-comparison-9e4b75a9bf87
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC edge detection
|
||||||
|
|
||||||
|
#define tex HOOKED_texOff
|
||||||
|
|
||||||
|
|
||||||
|
const mat3 prewitt_x = mat3(
|
||||||
|
1.0, 0.0, -1.0,
|
||||||
|
1.0, 0.0, -1.0,
|
||||||
|
1.0, 0.0, -1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
const mat3 prewitt_y = mat3(
|
||||||
|
1.0, 1.0, 1.0,
|
||||||
|
0.0, 0.0, 0.0,
|
||||||
|
-1.0, -1.0, -1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
const mat3 sobel_x = mat3(
|
||||||
|
1.0, 0.0, -1.0,
|
||||||
|
2.0, 0.0, -2.0,
|
||||||
|
1.0, 0.0, -1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
const mat3 sobel_y = mat3(
|
||||||
|
1.0, 2.0, 1.0,
|
||||||
|
0.0, 0.0, 0.0,
|
||||||
|
-1.0, -2.0, -1.0
|
||||||
|
);
|
||||||
|
|
||||||
|
const mat3 laplacian_p = mat3(
|
||||||
|
0.0, 1.0, 0.0,
|
||||||
|
1.0, -4.0, 1.0,
|
||||||
|
0.0, 1.0, 0.0
|
||||||
|
);
|
||||||
|
|
||||||
|
const mat3 laplacian_n = mat3(
|
||||||
|
0.0, -1.0, 0.0,
|
||||||
|
-1.0, 4.0, -1.0,
|
||||||
|
0.0, -1.0, 0.0
|
||||||
|
);
|
||||||
|
|
||||||
|
const float base = 0.0;
|
||||||
|
const uvec2 k_size = uvec2(3, 3);
|
||||||
|
const vec2 k_size_h = vec2(k_size / 2);
|
||||||
|
|
||||||
|
vec3 conv(mat3 k) {
|
||||||
|
vec3 x = vec3(base);
|
||||||
|
for (uint i = 0; i < k_size.x; i++)
|
||||||
|
for (uint j = 0; j < k_size.y; j++)
|
||||||
|
x += tex(vec2(j, i) - k_size_h).rgb * k[i][j];
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 prewitt() {
|
||||||
|
vec3 x = conv(prewitt_x);
|
||||||
|
vec3 y = conv(prewitt_y);
|
||||||
|
vec3 g = abs(sqrt(x * x + y * y));
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 sobel() {
|
||||||
|
vec3 x = conv(sobel_x);
|
||||||
|
vec3 y = conv(sobel_y);
|
||||||
|
vec3 g = abs(sqrt(x * x + y * y));
|
||||||
|
return g;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 laplacian() {
|
||||||
|
vec3 x = conv(laplacian_p);
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = vec4(vec3(0.0), 1.0);
|
||||||
|
|
||||||
|
color.rgb = laplacian();
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
28
mpv/shaders/hdr-toys/utils/exposure.glsl
Normal file
28
mpv/shaders/hdr-toys/utils/exposure.glsl
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
// https://en.wikipedia.org/wiki/Exposure_value
|
||||||
|
|
||||||
|
//!PARAM exposure_value
|
||||||
|
//!TYPE float
|
||||||
|
//!MINIMUM -64
|
||||||
|
//!MAXIMUM 64
|
||||||
|
0.0
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!WHEN exposure_value
|
||||||
|
//!DESC exposure
|
||||||
|
|
||||||
|
float exposure(float x, float ev) {
|
||||||
|
return x * exp2(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 exposure(vec3 x, float ev) {
|
||||||
|
return x * exp2(ev);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = exposure(color.rgb, exposure_value);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
21
mpv/shaders/hdr-toys/utils/invert.glsl
Normal file
21
mpv/shaders/hdr-toys/utils/invert.glsl
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
// invert the signal
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC signal invert
|
||||||
|
|
||||||
|
float invert(float x, float w) {
|
||||||
|
return -x + w;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 invert(vec3 x, float w) {
|
||||||
|
return -x + w;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
color.rgb = invert(color.rgb, 1.0);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
38
mpv/shaders/hdr-toys/utils/range.glsl
Normal file
38
mpv/shaders/hdr-toys/utils/range.glsl
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// from "full" to "limited" signal range
|
||||||
|
|
||||||
|
//!PARAM black
|
||||||
|
//!TYPE float
|
||||||
|
0.0625
|
||||||
|
|
||||||
|
//!PARAM white
|
||||||
|
//!TYPE float
|
||||||
|
0.91796875
|
||||||
|
|
||||||
|
//!PARAM depth
|
||||||
|
//!TYPE float
|
||||||
|
10.0
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC signal range scaling
|
||||||
|
|
||||||
|
float range(float x, float w, float b) {
|
||||||
|
return x * (w - b) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 range(vec3 x, float w, float b) {
|
||||||
|
return x * (w - b) + b;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
float l = exp2(depth);
|
||||||
|
float d = l - 1.0;
|
||||||
|
float b = l * black / d;
|
||||||
|
float w = l * white / d;
|
||||||
|
|
||||||
|
color.rgb = range(color.rgb, w, b);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
38
mpv/shaders/hdr-toys/utils/range_inv.glsl
Normal file
38
mpv/shaders/hdr-toys/utils/range_inv.glsl
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
// from "limited" to "full" signal range
|
||||||
|
|
||||||
|
//!PARAM black
|
||||||
|
//!TYPE float
|
||||||
|
0.0625
|
||||||
|
|
||||||
|
//!PARAM white
|
||||||
|
//!TYPE float
|
||||||
|
0.91796875
|
||||||
|
|
||||||
|
//!PARAM depth
|
||||||
|
//!TYPE float
|
||||||
|
10.0
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC signal range scaling (inverse)
|
||||||
|
|
||||||
|
float range_inv(float x, float w, float b) {
|
||||||
|
return (x - b) / (w - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 range_inv(vec3 x, float w, float b) {
|
||||||
|
return (x - b) / (w - b);
|
||||||
|
}
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec4 color = HOOKED_tex(HOOKED_pos);
|
||||||
|
|
||||||
|
float l = exp2(depth);
|
||||||
|
float d = l - 1.0;
|
||||||
|
float b = l * black / d;
|
||||||
|
float w = l * white / d;
|
||||||
|
|
||||||
|
color.rgb = range_inv(color.rgb, w, b);
|
||||||
|
|
||||||
|
return color;
|
||||||
|
}
|
83
mpv/shaders/hdr-toys/utils/transform.glsl
Normal file
83
mpv/shaders/hdr-toys/utils/transform.glsl
Normal file
|
@ -0,0 +1,83 @@
|
||||||
|
// https://developer.mozilla.org/en-US/docs/Web/CSS/transform
|
||||||
|
|
||||||
|
//!PARAM scale_x
|
||||||
|
//!TYPE float
|
||||||
|
1.0
|
||||||
|
|
||||||
|
//!PARAM scale_y
|
||||||
|
//!TYPE float
|
||||||
|
1.0
|
||||||
|
|
||||||
|
//!PARAM translate_x
|
||||||
|
//!TYPE float
|
||||||
|
0.0
|
||||||
|
|
||||||
|
//!PARAM translate_y
|
||||||
|
//!TYPE float
|
||||||
|
0.0
|
||||||
|
|
||||||
|
//!PARAM skew_x
|
||||||
|
//!TYPE float
|
||||||
|
0.0
|
||||||
|
|
||||||
|
//!PARAM skew_y
|
||||||
|
//!TYPE float
|
||||||
|
0.0
|
||||||
|
|
||||||
|
//!PARAM rotate
|
||||||
|
//!TYPE float
|
||||||
|
0.0
|
||||||
|
|
||||||
|
//!PARAM background
|
||||||
|
//!TYPE ENUM int
|
||||||
|
black
|
||||||
|
border
|
||||||
|
repeat
|
||||||
|
mirror
|
||||||
|
|
||||||
|
//!HOOK OUTPUT
|
||||||
|
//!BIND HOOKED
|
||||||
|
//!DESC transform
|
||||||
|
//!WHEN scale_x 1 - scale_y 1 - + translate_x + translate_y + skew_x + skew_y + rotate +
|
||||||
|
|
||||||
|
vec4 hook() {
|
||||||
|
vec2 pos = HOOKED_pos;
|
||||||
|
vec2 size = HOOKED_size;
|
||||||
|
vec2 align = vec2(0.5, 0.5); // center
|
||||||
|
|
||||||
|
pos -= align;
|
||||||
|
|
||||||
|
if (scale_x != 1.0 || scale_y != 1.0)
|
||||||
|
pos /= vec2(scale_x, scale_y);
|
||||||
|
|
||||||
|
if (translate_x != 0.0 || translate_y != 0.0)
|
||||||
|
pos -= vec2(translate_x, translate_y) * vec2(scale_x, scale_y);
|
||||||
|
|
||||||
|
if (skew_x != 0.0 || skew_y != 0.0)
|
||||||
|
pos = mat2(1.0, -tan(radians(skew_y)), -tan(radians(skew_x)), 1.0) * pos;
|
||||||
|
|
||||||
|
if (rotate != 0.0) {
|
||||||
|
pos *= size;
|
||||||
|
float c = length(pos);
|
||||||
|
float h = atan(pos.y, pos.x) - radians(rotate);
|
||||||
|
float a = cos(h) * c;
|
||||||
|
float b = sin(h) * c;
|
||||||
|
pos = vec2(a, b);
|
||||||
|
pos = floor(pos);
|
||||||
|
pos /= size;
|
||||||
|
}
|
||||||
|
|
||||||
|
pos += align;
|
||||||
|
|
||||||
|
if (background == black)
|
||||||
|
if (pos != clamp(pos, 0.0, 1.0))
|
||||||
|
return vec4(vec3(0.0), 1.0);
|
||||||
|
else if (background == border)
|
||||||
|
pos = clamp(pos, 0.0, 1.0);
|
||||||
|
else if (background == repeat)
|
||||||
|
pos = mod(pos, 1.0);
|
||||||
|
else if (background == mirror)
|
||||||
|
pos = abs(1.0 - abs(mod(pos, 2.0) - 1.0));
|
||||||
|
|
||||||
|
return HOOKED_tex(pos);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue