mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-26 17:31:31 +11:00
Grade 2023 - Update
- Bugfixes and code optimizations
This commit is contained in:
parent
584f18b1c6
commit
6f97a8e547
|
@ -1,7 +1,7 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grade - CRT emulated color manipulation shader
|
Grade - CRT emulation and color manipulation shader
|
||||||
|
|
||||||
Copyright (C) 2020-2023 Dogway (Jose Linares)
|
Copyright (C) 2020-2023 Dogway (Jose Linares)
|
||||||
|
|
||||||
|
@ -67,17 +67,24 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
uint FrameCount;
|
uint FrameCount;
|
||||||
float g_vignette;
|
float g_vignette;
|
||||||
float g_Dark_to_Dim;
|
float g_Dark_to_Dim;
|
||||||
|
float g_GCompress;
|
||||||
float wp_temperature;
|
float wp_temperature;
|
||||||
float g_CRT_br;
|
float g_CRT_br;
|
||||||
float g_CRT_bg;
|
float g_CRT_bg;
|
||||||
float g_CRT_bb;
|
float g_CRT_bb;
|
||||||
|
float g_CRT_rf;
|
||||||
|
float g_CRT_sl;
|
||||||
float g_satr;
|
float g_satr;
|
||||||
float g_satg;
|
float g_satg;
|
||||||
float g_satb;
|
float g_satb;
|
||||||
|
float g_digital;
|
||||||
|
float g_analog;
|
||||||
} global;
|
} global;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grade (11-05-2023)
|
Grade (03-06-2023)
|
||||||
|
> See settings decriptions at: https://forums.libretro.com/t/dogways-grading-shader-slang/27148/442
|
||||||
|
|
||||||
> Ubershader grouping some monolithic color related shaders:
|
> Ubershader grouping some monolithic color related shaders:
|
||||||
::color-mangler (hunterk), ntsc color tuning knobs (Doriphor), white_point (hunterk, Dogway), RA Reshade LUT.
|
::color-mangler (hunterk), ntsc color tuning knobs (Doriphor), white_point (hunterk, Dogway), RA Reshade LUT.
|
||||||
> and the addition of:
|
> and the addition of:
|
||||||
|
@ -101,7 +108,7 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
### ###
|
### ###
|
||||||
### NTSC-J (Default) ###
|
### NTSC-J (Default) ###
|
||||||
### Phosphor: NTSC-J (#2) (or a NTSC-J based CRT phosphor gamut) ###
|
### Phosphor: NTSC-J (#2) (or a NTSC-J based CRT phosphor gamut) ###
|
||||||
### WP: 9300K+27MPCD (8945K) (CCT from x:0.281 y:0.311)(in practice ~8600K)###
|
### WP: 9300K+27MPCD (8945K) (CCT from x:0.281 y:0.311)(in practice ~8500K)###
|
||||||
### ###
|
### ###
|
||||||
### ###
|
### ###
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
|
@ -111,31 +118,36 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
|
||||||
#pragma parameter g_signal_type "Signal Type (0:RGB 1:Composite)" 0.0 0.0 1.0 1.0
|
#pragma parameter g_signal_type "Signal Type (0:RGB 1:Composite)" 0.0 0.0 1.0 1.0
|
||||||
#pragma parameter g_crtgamut "Phosphor (-2:CRT-95s -1:P22-80s 1:P22-90s 2:NTSC-J 3:PAL)" 0.0 -3.0 3.0 1.0
|
#pragma parameter g_crtgamut "Phosphor (-2:CRT-95s -1:P22-80s 1:P22-90s 2:NTSC-J 3:PAL)" 0.0 -3.0 3.0 1.0
|
||||||
#pragma parameter g_space_out "Diplay Color Space (-1:709 0:sRGB 1:DCI 2:2020 3:Adobe)" 0.0 -1.0 3.0 1.0
|
#pragma parameter g_space_out "Diplay Color Space (-1:709 0:sRGB 1:P3-D65 2:2020 3:Adobe)" 0.0 -1.0 3.0 1.0
|
||||||
#pragma parameter g_Dark_to_Dim "Dark to Dim adaptation" 0.0 0.0 1.0 1.0
|
#pragma parameter g_Dark_to_Dim "Dark to Dim adaptation" 1.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter g_GCompress "Gamut Compression" 0.0 0.0 1.0 1.0
|
||||||
|
|
||||||
// Analogue controls
|
// Analogue controls
|
||||||
#pragma parameter g_hue_degrees "CRT Hue" 0.0 -360.0 360.0 1.0
|
#pragma parameter g_analog "// ANALOG CONTROLS //" 0.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter wp_temperature "White Point" 6504.0 5004.0 12004.0 100.0
|
||||||
|
#pragma parameter g_hue_degrees "CRT Hue" 0.0 -180.0 180.0 1.0
|
||||||
#pragma parameter g_U_SHIFT "CRT U Shift" 0.0 -0.2 0.2 0.01
|
#pragma parameter g_U_SHIFT "CRT U Shift" 0.0 -0.2 0.2 0.01
|
||||||
#pragma parameter g_V_SHIFT "CRT V Shift" 0.0 -0.2 0.2 0.01
|
#pragma parameter g_V_SHIFT "CRT V Shift" 0.0 -0.2 0.2 0.01
|
||||||
#pragma parameter g_U_MUL "CRT U Multiplier" 1.0 0.0 2.0 0.01
|
#pragma parameter g_U_MUL "CRT U Multiplier" 1.0 0.0 2.0 0.01
|
||||||
#pragma parameter g_V_MUL "CRT V Multiplier" 1.0 0.0 2.0 0.01
|
#pragma parameter g_V_MUL "CRT V Multiplier" 1.0 0.0 2.0 0.01
|
||||||
#pragma parameter g_CRT_l "CRT Gamma" 2.50 2.30 2.60 0.01
|
#pragma parameter g_CRT_l "CRT Gamma" 2.50 2.30 2.60 0.01
|
||||||
#pragma parameter g_CRT_b "CRT Brightness" 0.0 0.0 100.0 1.0
|
#pragma parameter g_CRT_b "CRT Brightness" 50.0 0.0 100.0 1.0
|
||||||
#pragma parameter g_CRT_c "CRT Contrast" 100.0 50.0 150.0 1.0
|
#pragma parameter g_CRT_c "CRT Contrast" 50.0 0.0 100.0 1.0
|
||||||
#pragma parameter g_CRT_br "CRT Beam Red" 1.0 0.0 1.2 0.01
|
#pragma parameter g_CRT_br "CRT Beam Red" 1.0 0.0 1.2 0.01
|
||||||
#pragma parameter g_CRT_bg "CRT Beam Green" 1.0 0.0 1.2 0.01
|
#pragma parameter g_CRT_bg "CRT Beam Green" 1.0 0.0 1.2 0.01
|
||||||
#pragma parameter g_CRT_bb "CRT Beam Blue" 1.0 0.0 1.2 0.01
|
#pragma parameter g_CRT_bb "CRT Beam Blue" 1.0 0.0 1.2 0.01
|
||||||
|
#pragma parameter g_CRT_rf "CRT Lambert Refl. in %" 5.0 2.0 5.0 0.1
|
||||||
|
#pragma parameter g_CRT_sl "Surround Luminance -nits-" 0.0 0.0 100.0 1.0
|
||||||
#pragma parameter g_vignette "Vignette Toggle" 0.0 0.0 1.0 1.0
|
#pragma parameter g_vignette "Vignette Toggle" 0.0 0.0 1.0 1.0
|
||||||
#pragma parameter g_vstr "Vignette Strength" 40.0 0.0 50.0 1.0
|
#pragma parameter g_vstr "Vignette Strength" 40.0 0.0 50.0 1.0
|
||||||
#pragma parameter g_vpower "Vignette Power" 0.20 0.0 0.5 0.01
|
#pragma parameter g_vpower "Vignette Power" 0.20 0.0 0.5 0.01
|
||||||
|
|
||||||
// Digital controls
|
// Digital controls
|
||||||
|
#pragma parameter g_digital "// DIGITAL CONTROLS //" 0.0 0.0 1.0 1.0
|
||||||
#pragma parameter g_lum_fix "Sega Luma Fix" 0.0 0.0 1.0 1.0
|
#pragma parameter g_lum_fix "Sega Luma Fix" 0.0 0.0 1.0 1.0
|
||||||
#pragma parameter g_lum "Brightness" 0.0 -0.5 1.0 0.01
|
#pragma parameter g_lum "Brightness" 0.0 -0.5 1.0 0.01
|
||||||
#pragma parameter g_cntrst "Contrast" 0.0 -1.0 1.0 0.05
|
#pragma parameter g_cntrst "Contrast" 0.0 -1.0 1.0 0.05
|
||||||
#pragma parameter g_mid "Contrast Pivot" 0.5 0.0 1.0 0.01
|
#pragma parameter g_mid "Contrast Pivot" 0.5 0.0 1.0 0.01
|
||||||
#pragma parameter wp_temperature "White Point" 6504.0 5004.0 12004.0 100.0
|
|
||||||
#pragma parameter g_sat "Saturation" 0.0 -1.0 1.0 0.01
|
#pragma parameter g_sat "Saturation" 0.0 -1.0 1.0 0.01
|
||||||
#pragma parameter g_vibr "Dullness/Vibrance" 0.0 -1.0 1.0 0.05
|
#pragma parameter g_vibr "Dullness/Vibrance" 0.0 -1.0 1.0 0.05
|
||||||
#pragma parameter g_satr "Hue vs Sat Red" 0.0 -1.0 1.0 0.01
|
#pragma parameter g_satr "Hue vs Sat Red" 0.0 -1.0 1.0 0.01
|
||||||
|
@ -156,6 +168,7 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
#pragma parameter bg "Blue-Green Tint" 0.0 -1.0 1.0 0.005
|
#pragma parameter bg "Blue-Green Tint" 0.0 -1.0 1.0 0.005
|
||||||
|
|
||||||
#define M_PI 3.1415926535897932384626433832795/180.0
|
#define M_PI 3.1415926535897932384626433832795/180.0
|
||||||
|
#define RW vec3(0.950457397565471, 1.0, 1.089436035930324)
|
||||||
#define signal params.g_signal_type
|
#define signal params.g_signal_type
|
||||||
#define crtgamut params.g_crtgamut
|
#define crtgamut params.g_crtgamut
|
||||||
#define SPC params.g_space_out
|
#define SPC params.g_space_out
|
||||||
|
@ -167,6 +180,7 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
#define g_CRT_l -(100000.*log((72981.-500000./(3.*max(2.3,params.g_CRT_l)))/9058.))/945461.
|
#define g_CRT_l -(100000.*log((72981.-500000./(3.*max(2.3,params.g_CRT_l)))/9058.))/945461.
|
||||||
#define lum_fix params.g_lum_fix
|
#define lum_fix params.g_lum_fix
|
||||||
#define vignette global.g_vignette
|
#define vignette global.g_vignette
|
||||||
|
#define GCompress global.g_GCompress
|
||||||
#define vstr params.g_vstr
|
#define vstr params.g_vstr
|
||||||
#define vpower params.g_vpower
|
#define vpower params.g_vpower
|
||||||
#define g_sat params.g_sat
|
#define g_sat params.g_sat
|
||||||
|
@ -212,19 +226,20 @@ layout(set = 0, binding = 2) uniform sampler2D Source;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////// Color Space Transformations //////////////////////////
|
///////////////////////// Color Space Transformations //////////////////////////
|
||||||
|
|
||||||
// 'D65' based
|
// 'D65' based
|
||||||
mat3 RGB_to_XYZ_mat(mat3 primaries) {
|
mat3 RGB_to_XYZ_mat(mat3 primaries) {
|
||||||
|
|
||||||
vec3 RW = vec3(0.950457397565471, 1., 1.089436035930324);
|
|
||||||
|
|
||||||
vec3 T = RW * inverse(primaries);
|
vec3 T = RW * inverse(primaries);
|
||||||
|
|
||||||
mat3 TB = mat3(
|
mat3 TB = mat3(
|
||||||
T.x, 0, 0,
|
T.x, 0.0, 0.0,
|
||||||
0, T.y, 0,
|
0.0, T.y, 0.0,
|
||||||
0, 0, T.z);
|
0.0, 0.0, T.z);
|
||||||
|
|
||||||
return TB * primaries;
|
return TB * primaries;
|
||||||
}
|
}
|
||||||
|
@ -269,7 +284,6 @@ vec3 YxytoXYZ(vec3 Yxy) {
|
||||||
// For NTSC-J there's not a common agreed value, measured consumer units span from 8229.87K to 8945.623K with accounts for 8800K as well.
|
// For NTSC-J there's not a common agreed value, measured consumer units span from 8229.87K to 8945.623K with accounts for 8800K as well.
|
||||||
// Recently it's been standardized to 9300K which is closer to what master monitors (and not consumer units) were (x=0.2838 y=0.2984) (~9177.98K)
|
// Recently it's been standardized to 9300K which is closer to what master monitors (and not consumer units) were (x=0.2838 y=0.2984) (~9177.98K)
|
||||||
|
|
||||||
|
|
||||||
// "RGB to XYZ -> Temperature -> XYZ to RGB" joint matrix
|
// "RGB to XYZ -> Temperature -> XYZ to RGB" joint matrix
|
||||||
vec3 wp_adjust(vec3 RGB, float temperature, mat3 primaries, mat3 display) {
|
vec3 wp_adjust(vec3 RGB, float temperature, mat3 primaries, mat3 display) {
|
||||||
|
|
||||||
|
@ -286,9 +300,6 @@ vec3 wp_adjust(vec3 RGB, float temperature, mat3 primaries, mat3 display) {
|
||||||
wp.y = -0.275275 + 2.87396 * wp.x - 3.02034 * pow(wp.x,2) + 0.0297408 * pow(wp.x,3);
|
wp.y = -0.275275 + 2.87396 * wp.x - 3.02034 * pow(wp.x,2) + 0.0297408 * pow(wp.x,3);
|
||||||
wp.z = 1. - wp.x - wp.y;
|
wp.z = 1. - wp.x - wp.y;
|
||||||
|
|
||||||
|
|
||||||
vec3 RW = vec3(0.950457397565471, 1., 1.089436035930324); // D65 Reference White
|
|
||||||
|
|
||||||
const mat3 CAT16 = mat3(
|
const mat3 CAT16 = mat3(
|
||||||
0.401288,-0.250268, -0.002079,
|
0.401288,-0.250268, -0.002079,
|
||||||
0.650173, 1.204414, 0.048952,
|
0.650173, 1.204414, 0.048952,
|
||||||
|
@ -323,17 +334,17 @@ float EOTF_1886a(float color, float bl, float brightness, float contrast) {
|
||||||
// Brightness = 0
|
// Brightness = 0
|
||||||
// Contrast = 100
|
// Contrast = 100
|
||||||
|
|
||||||
float wl = 100.0;
|
const float wl = 100.0;
|
||||||
float b = pow(bl, 1/2.4);
|
float b = pow(bl, 1/2.4);
|
||||||
float a = pow(wl, 1/2.4)-b;
|
float a = pow(wl, 1/2.4)-b;
|
||||||
b = brightness>0 ? (brightness/286.+b/a) : b/a;
|
b = (brightness-50) / 250. + b/a; // -0.20 to +0.20
|
||||||
a = contrast!=100 ? contrast/100. : 1;
|
a = contrast!=50 ? pow(2,(contrast-50)/50.) : 1.; // 0.50 to +2.00
|
||||||
|
|
||||||
float Vc = 0.35; // Offset
|
const float Vc = 0.35; // Offset
|
||||||
float Lw = wl/100. * a; // White level
|
float Lw = wl/100. * a; // White level
|
||||||
float Lb = clamp(b * a,0.01,Vc); // Black level
|
float Lb = min( b * a,Vc); // Black level
|
||||||
float a1 = 2.6; // Shoulder gamma
|
const float a1 = 2.6; // Shoulder gamma
|
||||||
float a2 = 3.0; // Knee gamma
|
const float a2 = 3.0; // Knee gamma
|
||||||
float k = Lw /pow(1 + Lb, a1);
|
float k = Lw /pow(1 + Lb, a1);
|
||||||
float sl = k * pow(Vc + Lb, a1-a2); // Slope for knee gamma
|
float sl = k * pow(Vc + Lb, a1-a2); // Slope for knee gamma
|
||||||
|
|
||||||
|
@ -458,36 +469,83 @@ float SatMask(float color_r, float color_g, float color_b)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//---------------------- Range Expansion/Compression -------------------
|
//---------------------- Gamut Compression -------------------
|
||||||
|
|
||||||
// 0-235 YUV PAL
|
|
||||||
// 0-235 YUV NTSC-J
|
|
||||||
// 16-235 YUV NTSC
|
|
||||||
|
|
||||||
// to Studio Swing/Broadcast Safe/SMPTE legal/Limited Range
|
// RGB 'Desaturate' Gamut Compression (by Jed Smith: https://github.com/jedypod/gamut-compress)
|
||||||
vec3 PCtoTV(vec3 col, float luma_swing, float Umax, float Vmax, float max_swing)
|
vec3 GamutCompression (vec3 rgb, float grey) {
|
||||||
{
|
|
||||||
col *= 255.;
|
|
||||||
vec2 UVmax = (max_swing == 1.0) ? vec2(Umax,Vmax) * 224. : vec2(Umax,Vmax) * 239.;
|
|
||||||
|
|
||||||
col.x = (luma_swing == 1.0) ? ((col.x * 219.) / 255.) + 16. : col.x;
|
// Limit/Thres order is Cyan, Magenta, Yellow
|
||||||
col.yz = (((col.yz - 128.) * (UVmax * 2.)) / 255.) + UVmax;
|
vec3 beam = max(vec3(0.0),vec3(beamg,(beamb+beamr)/2,(beamr+beamg)/2));
|
||||||
return col.xyz / 255.;
|
vec3 sat = max(vec3(0.0),vec3(satg, (satb +satr) /2,(satr +satg) /2)+1); // center at 1
|
||||||
|
float temp = max(0,abs(global.wp_temperature-7000)-1000)/825.0+1; // center at 1
|
||||||
|
vec3 WPD = global.wp_temperature < 7000 ? vec3(1,temp,(temp-1)/2+1) : vec3((temp-1)/2+1,temp,1);
|
||||||
|
sat = max(0.0,g_sat+1)*(sat*beam) * WPD;
|
||||||
|
|
||||||
|
mat2x3 LimThres = \
|
||||||
|
mat2x3( 0.100000,0.100000,0.100000,
|
||||||
|
0.125000,0.125000,0.125000);
|
||||||
|
if (SPC < 1.0) {
|
||||||
|
|
||||||
|
LimThres = \
|
||||||
|
crtgamut == 3.0 ? mat2x3( 0.000000,0.044065,0.000000,
|
||||||
|
0.000000,0.095638,0.000000) : \
|
||||||
|
crtgamut == 2.0 ? mat2x3( 0.006910,0.092133,0.000000,
|
||||||
|
0.039836,0.121390,0.000000) : \
|
||||||
|
crtgamut == 1.0 ? mat2x3( 0.018083,0.059489,0.017911,
|
||||||
|
0.066570,0.105996,0.066276) : \
|
||||||
|
crtgamut ==-1.0 ? mat2x3( 0.014947,0.098571,0.017911,
|
||||||
|
0.060803,0.123793,0.066276) : \
|
||||||
|
crtgamut ==-2.0 ? mat2x3( 0.004073,0.030307,0.012697,
|
||||||
|
0.028222,0.083075,0.056029) : \
|
||||||
|
crtgamut ==-3.0 ? mat2x3( 0.018424,0.053469,0.016841,
|
||||||
|
0.067146,0.102294,0.064393) : LimThres;
|
||||||
|
} else if (SPC==1.0) {
|
||||||
|
|
||||||
|
LimThres = \
|
||||||
|
crtgamut == 3.0 ? mat2x3( 0.000000,0.234229,0.007680,
|
||||||
|
0.000000,0.154983,0.042446) : \
|
||||||
|
crtgamut == 2.0 ? mat2x3( 0.078526,0.108432,0.006143,
|
||||||
|
0.115731,0.127194,0.037039) : \
|
||||||
|
crtgamut == 1.0 ? mat2x3( 0.021531,0.237184,0.013466,
|
||||||
|
0.072018,0.155438,0.057731) : \
|
||||||
|
crtgamut ==-1.0 ? mat2x3( 0.051640,0.103332,0.013550,
|
||||||
|
0.101092,0.125474,0.057912) : \
|
||||||
|
crtgamut ==-2.0 ? mat2x3( 0.032717,0.525361,0.023928,
|
||||||
|
0.085609,0.184491,0.075381) : \
|
||||||
|
crtgamut ==-3.0 ? mat2x3( 0.000000,0.377522,0.043076,
|
||||||
|
0.000000,0.172390,0.094873) : LimThres;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Amount of outer gamut to affect
|
||||||
|
vec3 th = 1.0-vec3(LimThres[1])*(0.4*sat+0.3);
|
||||||
|
|
||||||
// to Full Swing/Full Range
|
// Distance limit: How far beyond the gamut boundary to compress
|
||||||
vec3 TVtoPC(vec3 col, float luma_swing, float Umax, float Vmax, float max_swing)
|
vec3 dl = 1.0+vec3(LimThres[0])*sat;
|
||||||
{
|
|
||||||
col *= 255.;
|
|
||||||
vec2 UVmax = (max_swing == 1.0) ? vec2(Umax,Vmax) * 224. : vec2(Umax,Vmax) * 239.;
|
|
||||||
|
|
||||||
col.x = (luma_swing == 1.0) ? ((col.x - 16.) / 219.) * 255. : col.x;
|
// Calculate scale so compression function passes through distance limit: (x=dl, y=1)
|
||||||
col.yz = (((col.yz - UVmax) / (UVmax * 2.)) * 255.) + 128.;
|
vec3 s = (vec3(1)-th)/sqrt(max(vec3(1.001), dl)-1.0);
|
||||||
return col.xyz / 255.;
|
|
||||||
|
// Achromatic axis
|
||||||
|
float ac = max(rgb.x, max(rgb.y, rgb.z));
|
||||||
|
|
||||||
|
// Inverse RGB Ratios: distance from achromatic axis
|
||||||
|
vec3 d = ac==0.0?vec3(0.0):(ac-rgb)/abs(ac);
|
||||||
|
|
||||||
|
// Compressed distance. Parabolic compression function: https://www.desmos.com/calculator/nvhp63hmtj
|
||||||
|
vec3 cd;
|
||||||
|
vec3 sf = s*sqrt(d-th+s*s/4.0)-s*sqrt(s*s/4.0)+th;
|
||||||
|
cd.x = (d.x < th.x) ? d.x : sf.x;
|
||||||
|
cd.y = (d.y < th.y) ? d.y : sf.y;
|
||||||
|
cd.z = (d.z < th.z) ? d.z : sf.z;
|
||||||
|
|
||||||
|
// Inverse RGB Ratios to RGB
|
||||||
|
// and Mask with "luma"
|
||||||
|
return mix(rgb, ac-cd.xyz*abs(ac), pow(grey,1/2.4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
|
//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -498,6 +556,10 @@ vec3 TVtoPC(vec3 col, float luma_swing, float Umax, float Vmax, float max_swing)
|
||||||
//----------------------- Y'UV color model -----------------------
|
//----------------------- Y'UV color model -----------------------
|
||||||
|
|
||||||
|
|
||||||
|
// 0-235 YUV PAL
|
||||||
|
// 0-235 YUV NTSC-J
|
||||||
|
// 16-235 YUV NTSC
|
||||||
|
|
||||||
|
|
||||||
// Bymax 0.885515
|
// Bymax 0.885515
|
||||||
// Rymax 0.701088
|
// Rymax 0.701088
|
||||||
|
@ -512,13 +574,14 @@ const mat3 YByRy =
|
||||||
|
|
||||||
// Umax 0.435812284313725
|
// Umax 0.435812284313725
|
||||||
// Vmax 0.615857694117647
|
// Vmax 0.615857694117647
|
||||||
|
// R'G'B' full to Y'UV limited
|
||||||
// YUV is defined with headroom and footroom (TV range),
|
// YUV is defined with headroom and footroom (TV range),
|
||||||
// we need to limit the excursion to 16-235.
|
// UV excursion is limited to Umax and Vmax
|
||||||
// This is still R'G'B' full to YUV full though
|
// Y excursion is limited to 16-235 for NTSC-U and 0-235 for PAL and NTSC-J
|
||||||
vec3 r601_YUV(vec3 RGB) {
|
vec3 r601_YUV(vec3 RGB, float NTSC_U) {
|
||||||
|
|
||||||
float sclU = ((0.5*(235-16)+16)/255.); // This yields Luma grey at around 0.49216 or 125.5 in 8-bit
|
const float sclU = ((0.5*(235-16)+16)/255.); // This yields Luma grey at around 0.49216 or 125.5 in 8-bit
|
||||||
float sclV = (240-16) /255. ; // This yields Chroma range at around 0.87843 or 224 in 8-bit
|
const float sclV = (240-16) /255. ; // This yields Chroma range at around 0.87843 or 224 in 8-bit
|
||||||
|
|
||||||
mat3 conv_mat = mat3(
|
mat3 conv_mat = mat3(
|
||||||
vec3(YByRy[0]),
|
vec3(YByRy[0]),
|
||||||
|
@ -527,21 +590,39 @@ vec3 r601_YUV(vec3 RGB) {
|
||||||
|
|
||||||
// -0.147111592156863 -0.288700692156863 0.435812284313725
|
// -0.147111592156863 -0.288700692156863 0.435812284313725
|
||||||
// 0.615857694117647 -0.515290478431373 -0.100567215686275
|
// 0.615857694117647 -0.515290478431373 -0.100567215686275
|
||||||
return RGB.rgb * conv_mat;
|
|
||||||
|
vec3 YUV = RGB.rgb * conv_mat;
|
||||||
|
YUV.x = NTSC_U==1.0 ? YUV.x * 219.0 + 16.0 : YUV.x * 235.0;
|
||||||
|
return vec3(YUV.x/255.0,YUV.yz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec3 YUV_r601(vec3 YUV) {
|
// Y'UV limited to R'G'B' full
|
||||||
|
vec3 YUV_r601(vec3 YUV, float NTSC_U) {
|
||||||
|
|
||||||
mat3 conv_mat = mat3(
|
const mat3 conv_mat = mat3(
|
||||||
1.0000000, -0.000000029378826483, 1.1383928060531616,
|
1.0000000, -0.000000029378826483, 1.1383928060531616,
|
||||||
1.0000000, -0.396552562713623050, -0.5800843834877014,
|
1.0000000, -0.396552562713623050, -0.5800843834877014,
|
||||||
1.0000000, 2.031872510910034000, 0.0000000000000000);
|
1.0000000, 2.031872510910034000, 0.0000000000000000);
|
||||||
|
|
||||||
|
YUV.x = (YUV.x - (NTSC_U == 1.0 ? 16.0/255.0 : 0.0 )) * (255.0/(NTSC_U == 1.0 ? 219.0 : 235.0));
|
||||||
return YUV.xyz * conv_mat;
|
return YUV.xyz * conv_mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FP32 to 8-bit mid-tread uniform quantization
|
||||||
|
float Quantize8(float col) {
|
||||||
|
col = min(255.0,floor(col * 255.0 + 0.5));
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 Quantize8_f3(vec3 col) {
|
||||||
|
col.r = Quantize8(col.r);
|
||||||
|
col.g = Quantize8(col.g);
|
||||||
|
col.b = Quantize8(col.b);
|
||||||
|
return col.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------- LMS --------------------------
|
//------------------------- LMS --------------------------
|
||||||
|
@ -589,7 +670,7 @@ const mat3 SMPTE470BG_ph =
|
||||||
// NTSC-J P22
|
// NTSC-J P22
|
||||||
// Mix between averaging KV-20M20, KDS VS19, Dell D93, 4-TR-B09v1_0.pdf and Phosphor Handbook 'P22'
|
// Mix between averaging KV-20M20, KDS VS19, Dell D93, 4-TR-B09v1_0.pdf and Phosphor Handbook 'P22'
|
||||||
// ILLUMINANT: D93->[0.281000,0.311000] (CCT of 8945.436K)
|
// ILLUMINANT: D93->[0.281000,0.311000] (CCT of 8945.436K)
|
||||||
// ILLUMINANT: D97->[0.285000,0.285000] (CCT of 9696K) for Nanao MS-2930s series
|
// ILLUMINANT: D97->[0.285000,0.285000] (CCT of 9696K) for Nanao MS-2930s series (in practice prolly more like ~9177.98K)
|
||||||
const mat3 P22_J_ph =
|
const mat3 P22_J_ph =
|
||||||
mat3(
|
mat3(
|
||||||
0.625, 0.280, 0.152,
|
0.625, 0.280, 0.152,
|
||||||
|
@ -625,6 +706,7 @@ const mat3 CRT_95s_ph =
|
||||||
|
|
||||||
//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
|
//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
|
||||||
|
|
||||||
|
|
||||||
//----------------------- Display Primaries -----------------------
|
//----------------------- Display Primaries -----------------------
|
||||||
|
|
||||||
// sRGB (IEC 61966-2-1) and ITU-R BT.709-6 (originally CCIR Rec.709)
|
// sRGB (IEC 61966-2-1) and ITU-R BT.709-6 (originally CCIR Rec.709)
|
||||||
|
@ -667,34 +749,34 @@ void main()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Retro Sega Systems: Genesis, 32x, CD and Saturn 2D had color palettes designed in TV levels to save on transformations.
|
// Retro Sega Systems: Genesis, 32x, CD and Saturn 2D had color palettes designed in TV levels to save on transformations.
|
||||||
float lum_exp = (lum_fix == 1.0) ? (255./239.) : 1.;
|
float lum_exp = (lum_fix == 1.0) ? (255.0/239.0) : 1.0;
|
||||||
|
|
||||||
vec3 src = texture(Source, vTexCoord.xy).rgb * lum_exp;
|
vec3 src = texture(Source, vTexCoord.xy).rgb * lum_exp;
|
||||||
|
|
||||||
// Clipping Logic / Gamut Limiting
|
// Clipping Logic / Gamut Limiting
|
||||||
vec2 UVmax = vec2(0.435812284313725, 0.615857694117647);
|
bool NTSC_U = crtgamut < 2.0;
|
||||||
|
|
||||||
|
vec2 UVmax = vec2(Quantize8(0.435812284313725), Quantize8(0.615857694117647));
|
||||||
|
vec2 Ymax = NTSC_U ? vec2(16.0, 235.0) : vec2(0.0, 235.0);
|
||||||
|
|
||||||
|
|
||||||
// Assumes framebuffer in Rec.601 full range with baked gamma
|
// Assumes framebuffer in Rec.601 full range with baked gamma
|
||||||
vec3 col = clamp(r601_YUV(src), vec3(0.0, -UVmax.x, -UVmax.y) , \
|
// Quantize to 8-bit to replicate CRT's circuit board arithmetics
|
||||||
vec3(1.0, UVmax.x, UVmax.y));
|
vec3 col = clamp(Quantize8_f3(r601_YUV(src, NTSC_U ? 1.0 : 0.0)), vec3(Ymax.x, -UVmax.x, -UVmax.y), \
|
||||||
|
vec3(Ymax.y, UVmax.x, UVmax.y))/255.0;
|
||||||
col = crtgamut < 2.0 ? PCtoTV(col, 1.0, UVmax.x, UVmax.y, 1.0) : col;
|
|
||||||
|
|
||||||
|
|
||||||
// YUV Analogue Color Controls (HUE + Color Shift + Color Burst)
|
// YUV Analogue Color Controls (HUE + Color Shift + Color Burst)
|
||||||
float hue_radians = hue_degrees * M_PI;
|
float hue_radians = hue_degrees * M_PI;
|
||||||
float hue = atan(col.z, col.y) + hue_radians;
|
float hue = atan(col.z, col.y) + hue_radians;
|
||||||
float chroma = sqrt(col.z * col.z + col.y * col.y);
|
float chroma = sqrt(col.z * col.z + col.y * col.y); // Euclidean Distance
|
||||||
col = vec3(col.x, chroma * cos(hue), chroma * sin(hue));
|
|
||||||
|
|
||||||
col.y = (mod((col.y + 1.0) + U_SHIFT, 2.0) - 1.0) * U_MUL;
|
col.y = (mod((chroma * cos(hue) + 1.0) + U_SHIFT, 2.0) - 1.0) * U_MUL;
|
||||||
col.z = (mod((col.z + 1.0) + V_SHIFT, 2.0) - 1.0) * V_MUL;
|
col.z = (mod((chroma * sin(hue) + 1.0) + V_SHIFT, 2.0) - 1.0) * V_MUL;
|
||||||
|
|
||||||
// Back to RGB
|
// Back to R'G'B' full
|
||||||
col = crtgamut < 2.0 ? TVtoPC(col, 1.0, UVmax.x, UVmax.y, 1.0) : col;
|
col = signal > 0.0 ? max(Quantize8_f3(YUV_r601(col.xyz, NTSC_U ? 1.0 : 0.0))/255.0, 0.0) : src;
|
||||||
col = clamp(YUV_r601(col), 0., 1.);
|
|
||||||
|
|
||||||
// CRT EOTF. To Display Referred Linear: Undo developer baked CRT gamma (from 2.40 at default 0.1 CRT black level, to 2.61 at 0.0 CRT black level)
|
// CRT EOTF. To Display Referred Linear: Undo developer baked CRT gamma (from 2.40 at default 0.1 CRT black level, to 2.60 at 0.0 CRT black level)
|
||||||
col = EOTF_1886a_f3(col, g_CRT_l, params.g_CRT_b, params.g_CRT_c);
|
col = EOTF_1886a_f3(col, g_CRT_l, params.g_CRT_b, params.g_CRT_c);
|
||||||
|
|
||||||
|
|
||||||
|
@ -726,7 +808,6 @@ void main()
|
||||||
if (crtgamut == 2.0) { m_in = P22_J_ph; } else
|
if (crtgamut == 2.0) { m_in = P22_J_ph; } else
|
||||||
if (crtgamut == 3.0) { m_in = SMPTE470BG_ph; }
|
if (crtgamut == 3.0) { m_in = SMPTE470BG_ph; }
|
||||||
|
|
||||||
m_in = (global.LUT1_toggle == 0.0) ? m_in : sRGB_prims;
|
|
||||||
|
|
||||||
// Display color space
|
// Display color space
|
||||||
mat3 m_ou;
|
mat3 m_ou;
|
||||||
|
@ -764,7 +845,7 @@ void main()
|
||||||
float hue_radians_b = 100.0 * M_PI;
|
float hue_radians_b = 100.0 * M_PI;
|
||||||
float hue_b = cos(hue_at + hue_radians_b);
|
float hue_b = cos(hue_at + hue_radians_b);
|
||||||
|
|
||||||
float msk = dot(clamp(vec3(hue_r, hue_g, hue_b) * chroma * 2, 0., 1.), -vec3(satr, satg, satb));
|
float msk = dot(clamp(vec3(hue_r, hue_g, hue_b) * chroma * 2, 0.0, 1.0), -vec3(satr, satg, satb));
|
||||||
src_h = mix(col, vec3(dot(coeff, col)), msk);
|
src_h = mix(col, vec3(dot(coeff, col)), msk);
|
||||||
|
|
||||||
float sat_msk = (vibr < 0.0) ? 1.0 - abs(SatMask(src_h.x, src_h.y, src_h.z) - 1.0) * abs(vibr) : \
|
float sat_msk = (vibr < 0.0) ? 1.0 - abs(SatMask(src_h.x, src_h.y, src_h.z) - 1.0) * abs(vibr) : \
|
||||||
|
@ -781,14 +862,18 @@ void main()
|
||||||
msatz , msatz , msatz + sat);
|
msatz , msatz , msatz + sat);
|
||||||
|
|
||||||
|
|
||||||
src_h = mix(src_h, adjust * src_h, clamp(sat_msk, 0., 1.));
|
src_h = mix(src_h, adjust * src_h, clamp(sat_msk, 0.0, 1.0));
|
||||||
src_h = clamp(src_h*vec3(beamr,beamg,beamb),0.0,1.0);
|
src_h *= vec3(beamr,beamg,beamb);
|
||||||
|
|
||||||
|
|
||||||
|
// RGB 'Desaturate' Gamut Compression (by Jed Smith: https://github.com/jedypod/gamut-compress)
|
||||||
|
coeff = RGB_to_XYZ_mat(m_ou)[1];
|
||||||
|
src_h = GCompress==1.0 ? clamp(GamutCompression(src_h, dot(coeff.xyz, src_h)), 0.0, 1.0) : clamp(src_h, 0.0, 1.0);
|
||||||
|
|
||||||
|
|
||||||
// Sigmoidal Luma Contrast under 'Yxy' decorrelated model (in gamma space)
|
// Sigmoidal Luma Contrast under 'Yxy' decorrelated model (in gamma space)
|
||||||
vec3 Yxy = XYZtoYxy(RGB_to_XYZ(src_h, m_ou));
|
vec3 Yxy = XYZtoYxy(RGB_to_XYZ(src_h, m_ou));
|
||||||
float toGamma = clamp(moncurve_r(Yxy.r, 2.40, 0.055), 0., 1.);
|
float toGamma = clamp(moncurve_r(Yxy.r, 2.40, 0.055), 0.0, 1.0);
|
||||||
toGamma = (Yxy.r > 0.5) ? contrast_sigmoid_inv(toGamma, 2.3, 0.5) : toGamma;
|
toGamma = (Yxy.r > 0.5) ? contrast_sigmoid_inv(toGamma, 2.3, 0.5) : toGamma;
|
||||||
float sigmoid = (cntrst > 0.0) ? contrast_sigmoid(toGamma, cntrst, mid) : contrast_sigmoid_inv(toGamma, cntrst, mid);
|
float sigmoid = (cntrst > 0.0) ? contrast_sigmoid(toGamma, cntrst, mid) : contrast_sigmoid_inv(toGamma, cntrst, mid);
|
||||||
vec3 contrast = vec3(moncurve_f(sigmoid, 2.40, 0.055), Yxy.g, Yxy.b);
|
vec3 contrast = vec3(moncurve_f(sigmoid, 2.40, 0.055), Yxy.g, Yxy.b);
|
||||||
|
@ -797,12 +882,11 @@ void main()
|
||||||
|
|
||||||
|
|
||||||
// Lift + Gain -PP Digital Controls- (Could do in Yxy but performance reasons)
|
// Lift + Gain -PP Digital Controls- (Could do in Yxy but performance reasons)
|
||||||
src_h = clamp(rolled_gain_v3(contrast, clamp(lum, -0.49, 0.99)), 0., 1.);
|
src_h = clamp(rolled_gain_v3(contrast, clamp(lum, -0.49, 0.99)), 0.0, 1.0);
|
||||||
src_h += (lift / 20.0) * (1.0 - contrast);
|
src_h += (lift / 20.0) * (1.0 - contrast);
|
||||||
|
|
||||||
|
|
||||||
|
// Vignetting (in linear space, so after EOTF^-1 it's power shaped; 0.5 thres converts to ~0.75)
|
||||||
// Vignetting & Black Level (in linear space, so after EOTF^-1 it's power shaped; 0.5 thres converts to ~0.75)
|
|
||||||
vec2 vpos = vTexCoord*(global.OriginalSize.xy/global.SourceSize.xy);
|
vec2 vpos = vTexCoord*(global.OriginalSize.xy/global.SourceSize.xy);
|
||||||
|
|
||||||
vpos *= 1.0 - vpos.xy;
|
vpos *= 1.0 - vpos.xy;
|
||||||
|
@ -824,5 +908,9 @@ void main()
|
||||||
clamp(pow( src_D, vec3(1./(2.20 + 0.20))), 0., 1.) ;
|
clamp(pow( src_D, vec3(1./(2.20 + 0.20))), 0., 1.) ;
|
||||||
|
|
||||||
|
|
||||||
|
// External Flare for Surround Illuminant 2700K (Soft White) at F0 (Lambertian reflectance); defines offset thus also black lift
|
||||||
|
vec3 Flare = 0.01 * (global.g_CRT_rf/5.0)*(0.049433*global.g_CRT_sl - 0.188367) * vec3(0.459993/0.410702,1.0,0.129305/0.410702);
|
||||||
|
TRC = global.g_CRT_sl > 0.0 ? min(TRC+Flare,1.0) : TRC;
|
||||||
|
|
||||||
FragColor = vec4(TRC, 1.0);
|
FragColor = vec4(TRC, 1.0);
|
||||||
}
|
}
|
|
@ -1,7 +1,7 @@
|
||||||
#version 450
|
#version 450
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grade - CRT emulated color manipulation shader
|
Grade - CRT emulation and color manipulation shader
|
||||||
|
|
||||||
Copyright (C) 2020-2023 Dogway (Jose Linares)
|
Copyright (C) 2020-2023 Dogway (Jose Linares)
|
||||||
|
|
||||||
|
@ -67,13 +67,18 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
uint FrameCount;
|
uint FrameCount;
|
||||||
float g_vignette;
|
float g_vignette;
|
||||||
float g_Dark_to_Dim;
|
float g_Dark_to_Dim;
|
||||||
|
float g_GCompress;
|
||||||
float wp_temperature;
|
float wp_temperature;
|
||||||
float g_CRT_br;
|
float g_CRT_br;
|
||||||
float g_CRT_bg;
|
float g_CRT_bg;
|
||||||
float g_CRT_bb;
|
float g_CRT_bb;
|
||||||
|
float g_CRT_rf;
|
||||||
|
float g_CRT_sl;
|
||||||
float g_satr;
|
float g_satr;
|
||||||
float g_satg;
|
float g_satg;
|
||||||
float g_satb;
|
float g_satb;
|
||||||
|
float g_digital;
|
||||||
|
float g_analog;
|
||||||
float LUT_Size1;
|
float LUT_Size1;
|
||||||
float LUT1_toggle;
|
float LUT1_toggle;
|
||||||
float LUT_Size2;
|
float LUT_Size2;
|
||||||
|
@ -81,7 +86,9 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
} global;
|
} global;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Grade (11-05-2023)
|
Grade (03-06-2023)
|
||||||
|
> See settings decriptions at: https://forums.libretro.com/t/dogways-grading-shader-slang/27148/442
|
||||||
|
|
||||||
> Ubershader grouping some monolithic color related shaders:
|
> Ubershader grouping some monolithic color related shaders:
|
||||||
::color-mangler (hunterk), ntsc color tuning knobs (Doriphor), white_point (hunterk, Dogway), RA Reshade LUT.
|
::color-mangler (hunterk), ntsc color tuning knobs (Doriphor), white_point (hunterk, Dogway), RA Reshade LUT.
|
||||||
> and the addition of:
|
> and the addition of:
|
||||||
|
@ -105,7 +112,7 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
### ###
|
### ###
|
||||||
### NTSC-J (Default) ###
|
### NTSC-J (Default) ###
|
||||||
### Phosphor: NTSC-J (#2) (or a NTSC-J based CRT phosphor gamut) ###
|
### Phosphor: NTSC-J (#2) (or a NTSC-J based CRT phosphor gamut) ###
|
||||||
### WP: 9300K+27MPCD (8945K) (CCT from x:0.281 y:0.311)(in practice ~8600K)###
|
### WP: 9300K+27MPCD (8945K) (CCT from x:0.281 y:0.311)(in practice ~8500K)###
|
||||||
### ###
|
### ###
|
||||||
### ###
|
### ###
|
||||||
##########################################################################################
|
##########################################################################################
|
||||||
|
@ -115,31 +122,36 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
|
|
||||||
#pragma parameter g_signal_type "Signal Type (0:RGB 1:Composite)" 1.0 0.0 1.0 1.0
|
#pragma parameter g_signal_type "Signal Type (0:RGB 1:Composite)" 1.0 0.0 1.0 1.0
|
||||||
#pragma parameter g_crtgamut "Phosphor (-2:CRT-95s -1:P22-80s 1:P22-90s 2:NTSC-J 3:PAL)" 2.0 -3.0 3.0 1.0
|
#pragma parameter g_crtgamut "Phosphor (-2:CRT-95s -1:P22-80s 1:P22-90s 2:NTSC-J 3:PAL)" 2.0 -3.0 3.0 1.0
|
||||||
#pragma parameter g_space_out "Diplay Color Space (-1:709 0:sRGB 1:DCI 2:2020 3:Adobe)" 0.0 -1.0 3.0 1.0
|
#pragma parameter g_space_out "Diplay Color Space (-1:709 0:sRGB 1:P3-D65 2:2020 3:Adobe)" 0.0 -1.0 3.0 1.0
|
||||||
#pragma parameter g_Dark_to_Dim "Dark to Dim adaptation" 1.0 0.0 1.0 1.0
|
#pragma parameter g_Dark_to_Dim "Dark to Dim adaptation" 1.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter g_GCompress "Gamut Compression" 1.0 0.0 1.0 1.0
|
||||||
|
|
||||||
// Analogue controls
|
// Analogue controls
|
||||||
#pragma parameter g_hue_degrees "CRT Hue" 0.0 -360.0 360.0 1.0
|
#pragma parameter g_analog "// ANALOG CONTROLS //" 0.0 0.0 1.0 1.0
|
||||||
|
#pragma parameter wp_temperature "White Point" 8504.0 5004.0 12004.0 100.0
|
||||||
|
#pragma parameter g_hue_degrees "CRT Hue" 0.0 -180.0 180.0 1.0
|
||||||
#pragma parameter g_U_SHIFT "CRT U Shift" 0.0 -0.2 0.2 0.01
|
#pragma parameter g_U_SHIFT "CRT U Shift" 0.0 -0.2 0.2 0.01
|
||||||
#pragma parameter g_V_SHIFT "CRT V Shift" 0.0 -0.2 0.2 0.01
|
#pragma parameter g_V_SHIFT "CRT V Shift" 0.0 -0.2 0.2 0.01
|
||||||
#pragma parameter g_U_MUL "CRT U Multiplier" 1.0 0.0 2.0 0.01
|
#pragma parameter g_U_MUL "CRT U Multiplier" 1.0 0.0 2.0 0.01
|
||||||
#pragma parameter g_V_MUL "CRT V Multiplier" 1.0 0.0 2.0 0.01
|
#pragma parameter g_V_MUL "CRT V Multiplier" 1.0 0.0 2.0 0.01
|
||||||
#pragma parameter g_CRT_l "CRT Gamma" 2.50 2.30 2.60 0.01
|
#pragma parameter g_CRT_l "CRT Gamma" 2.50 2.30 2.60 0.01
|
||||||
#pragma parameter g_CRT_b "CRT Brightness" 0.0 0.0 100.0 1.0
|
#pragma parameter g_CRT_b "CRT Brightness" 50.0 0.0 100.0 1.0
|
||||||
#pragma parameter g_CRT_c "CRT Contrast" 100.0 50.0 150.0 1.0
|
#pragma parameter g_CRT_c "CRT Contrast" 50.0 0.0 100.0 1.0
|
||||||
#pragma parameter g_CRT_br "CRT Beam Red" 1.0 0.0 1.2 0.01
|
#pragma parameter g_CRT_br "CRT Beam Red" 1.0 0.0 1.2 0.01
|
||||||
#pragma parameter g_CRT_bg "CRT Beam Green" 1.0 0.0 1.2 0.01
|
#pragma parameter g_CRT_bg "CRT Beam Green" 1.0 0.0 1.2 0.01
|
||||||
#pragma parameter g_CRT_bb "CRT Beam Blue" 1.0 0.0 1.2 0.01
|
#pragma parameter g_CRT_bb "CRT Beam Blue" 1.0 0.0 1.2 0.01
|
||||||
|
#pragma parameter g_CRT_rf "CRT Lambert Refl. in %" 5.0 2.0 5.0 0.1
|
||||||
|
#pragma parameter g_CRT_sl "Surround Luminance -nits-" 34.0 0.0 100.0 1.0
|
||||||
#pragma parameter g_vignette "Vignette Toggle" 1.0 0.0 1.0 1.0
|
#pragma parameter g_vignette "Vignette Toggle" 1.0 0.0 1.0 1.0
|
||||||
#pragma parameter g_vstr "Vignette Strength" 50.0 0.0 50.0 1.0
|
#pragma parameter g_vstr "Vignette Strength" 50.0 0.0 50.0 1.0
|
||||||
#pragma parameter g_vpower "Vignette Power" 0.50 0.0 0.5 0.01
|
#pragma parameter g_vpower "Vignette Power" 0.50 0.0 0.5 0.01
|
||||||
|
|
||||||
// Digital controls
|
// Digital controls
|
||||||
|
#pragma parameter g_digital "// DIGITAL CONTROLS //" 0.0 0.0 1.0 1.0
|
||||||
#pragma parameter g_lum_fix "Sega Luma Fix" 0.0 0.0 1.0 1.0
|
#pragma parameter g_lum_fix "Sega Luma Fix" 0.0 0.0 1.0 1.0
|
||||||
#pragma parameter g_lum "Brightness" 0.0 -0.5 1.0 0.01
|
#pragma parameter g_lum "Brightness" 0.0 -0.5 1.0 0.01
|
||||||
#pragma parameter g_cntrst "Contrast" 0.0 -1.0 1.0 0.05
|
#pragma parameter g_cntrst "Contrast" 0.0 -1.0 1.0 0.05
|
||||||
#pragma parameter g_mid "Contrast Pivot" 0.5 0.0 1.0 0.01
|
#pragma parameter g_mid "Contrast Pivot" 0.5 0.0 1.0 0.01
|
||||||
#pragma parameter wp_temperature "White Point" 8604.0 5004.0 12004.0 100.0
|
|
||||||
#pragma parameter g_sat "Saturation" 0.0 -1.0 1.0 0.01
|
#pragma parameter g_sat "Saturation" 0.0 -1.0 1.0 0.01
|
||||||
#pragma parameter g_vibr "Dullness/Vibrance" 0.0 -1.0 1.0 0.05
|
#pragma parameter g_vibr "Dullness/Vibrance" 0.0 -1.0 1.0 0.05
|
||||||
#pragma parameter g_satr "Hue vs Sat Red" 0.0 -1.0 1.0 0.01
|
#pragma parameter g_satr "Hue vs Sat Red" 0.0 -1.0 1.0 0.01
|
||||||
|
@ -164,6 +176,7 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
#pragma parameter LUT2_toggle "LUT 2 Toggle" 0.0 0.0 1.0 1.0
|
#pragma parameter LUT2_toggle "LUT 2 Toggle" 0.0 0.0 1.0 1.0
|
||||||
|
|
||||||
#define M_PI 3.1415926535897932384626433832795/180.0
|
#define M_PI 3.1415926535897932384626433832795/180.0
|
||||||
|
#define RW vec3(0.950457397565471, 1.0, 1.089436035930324)
|
||||||
#define signal params.g_signal_type
|
#define signal params.g_signal_type
|
||||||
#define crtgamut params.g_crtgamut
|
#define crtgamut params.g_crtgamut
|
||||||
#define SPC params.g_space_out
|
#define SPC params.g_space_out
|
||||||
|
@ -175,6 +188,7 @@ layout(std140, set = 0, binding = 0) uniform UBO
|
||||||
#define g_CRT_l -(100000.*log((72981.-500000./(3.*max(2.3,params.g_CRT_l)))/9058.))/945461.
|
#define g_CRT_l -(100000.*log((72981.-500000./(3.*max(2.3,params.g_CRT_l)))/9058.))/945461.
|
||||||
#define lum_fix params.g_lum_fix
|
#define lum_fix params.g_lum_fix
|
||||||
#define vignette global.g_vignette
|
#define vignette global.g_vignette
|
||||||
|
#define GCompress global.g_GCompress
|
||||||
#define vstr params.g_vstr
|
#define vstr params.g_vstr
|
||||||
#define vpower params.g_vpower
|
#define vpower params.g_vpower
|
||||||
#define g_sat params.g_sat
|
#define g_sat params.g_sat
|
||||||
|
@ -222,19 +236,20 @@ layout(set = 0, binding = 4) uniform sampler2D SamplerLUT2;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
///////////////////////// Color Space Transformations //////////////////////////
|
///////////////////////// Color Space Transformations //////////////////////////
|
||||||
|
|
||||||
// 'D65' based
|
// 'D65' based
|
||||||
mat3 RGB_to_XYZ_mat(mat3 primaries) {
|
mat3 RGB_to_XYZ_mat(mat3 primaries) {
|
||||||
|
|
||||||
vec3 RW = vec3(0.950457397565471, 1., 1.089436035930324);
|
|
||||||
|
|
||||||
vec3 T = RW * inverse(primaries);
|
vec3 T = RW * inverse(primaries);
|
||||||
|
|
||||||
mat3 TB = mat3(
|
mat3 TB = mat3(
|
||||||
T.x, 0, 0,
|
T.x, 0.0, 0.0,
|
||||||
0, T.y, 0,
|
0.0, T.y, 0.0,
|
||||||
0, 0, T.z);
|
0.0, 0.0, T.z);
|
||||||
|
|
||||||
return TB * primaries;
|
return TB * primaries;
|
||||||
}
|
}
|
||||||
|
@ -279,7 +294,6 @@ vec3 YxytoXYZ(vec3 Yxy) {
|
||||||
// For NTSC-J there's not a common agreed value, measured consumer units span from 8229.87K to 8945.623K with accounts for 8800K as well.
|
// For NTSC-J there's not a common agreed value, measured consumer units span from 8229.87K to 8945.623K with accounts for 8800K as well.
|
||||||
// Recently it's been standardized to 9300K which is closer to what master monitors (and not consumer units) were (x=0.2838 y=0.2984) (~9177.98K)
|
// Recently it's been standardized to 9300K which is closer to what master monitors (and not consumer units) were (x=0.2838 y=0.2984) (~9177.98K)
|
||||||
|
|
||||||
|
|
||||||
// "RGB to XYZ -> Temperature -> XYZ to RGB" joint matrix
|
// "RGB to XYZ -> Temperature -> XYZ to RGB" joint matrix
|
||||||
vec3 wp_adjust(vec3 RGB, float temperature, mat3 primaries, mat3 display) {
|
vec3 wp_adjust(vec3 RGB, float temperature, mat3 primaries, mat3 display) {
|
||||||
|
|
||||||
|
@ -296,9 +310,6 @@ vec3 wp_adjust(vec3 RGB, float temperature, mat3 primaries, mat3 display) {
|
||||||
wp.y = -0.275275 + 2.87396 * wp.x - 3.02034 * pow(wp.x,2) + 0.0297408 * pow(wp.x,3);
|
wp.y = -0.275275 + 2.87396 * wp.x - 3.02034 * pow(wp.x,2) + 0.0297408 * pow(wp.x,3);
|
||||||
wp.z = 1. - wp.x - wp.y;
|
wp.z = 1. - wp.x - wp.y;
|
||||||
|
|
||||||
|
|
||||||
vec3 RW = vec3(0.950457397565471, 1., 1.089436035930324); // D65 Reference White
|
|
||||||
|
|
||||||
const mat3 CAT16 = mat3(
|
const mat3 CAT16 = mat3(
|
||||||
0.401288,-0.250268, -0.002079,
|
0.401288,-0.250268, -0.002079,
|
||||||
0.650173, 1.204414, 0.048952,
|
0.650173, 1.204414, 0.048952,
|
||||||
|
@ -333,17 +344,17 @@ float EOTF_1886a(float color, float bl, float brightness, float contrast) {
|
||||||
// Brightness = 0
|
// Brightness = 0
|
||||||
// Contrast = 100
|
// Contrast = 100
|
||||||
|
|
||||||
float wl = 100.0;
|
const float wl = 100.0;
|
||||||
float b = pow(bl, 1/2.4);
|
float b = pow(bl, 1/2.4);
|
||||||
float a = pow(wl, 1/2.4)-b;
|
float a = pow(wl, 1/2.4)-b;
|
||||||
b = brightness>0 ? (brightness/286.+b/a) : b/a;
|
b = (brightness-50) / 250. + b/a; // -0.20 to +0.20
|
||||||
a = contrast!=100 ? contrast/100. : 1;
|
a = contrast!=50 ? pow(2,(contrast-50)/50.) : 1.; // 0.50 to +2.00
|
||||||
|
|
||||||
float Vc = 0.35; // Offset
|
const float Vc = 0.35; // Offset
|
||||||
float Lw = wl/100. * a; // White level
|
float Lw = wl/100. * a; // White level
|
||||||
float Lb = clamp(b * a,0.01,Vc); // Black level
|
float Lb = min( b * a,Vc); // Black level
|
||||||
float a1 = 2.6; // Shoulder gamma
|
const float a1 = 2.6; // Shoulder gamma
|
||||||
float a2 = 3.0; // Knee gamma
|
const float a2 = 3.0; // Knee gamma
|
||||||
float k = Lw /pow(1 + Lb, a1);
|
float k = Lw /pow(1 + Lb, a1);
|
||||||
float sl = k * pow(Vc + Lb, a1-a2); // Slope for knee gamma
|
float sl = k * pow(Vc + Lb, a1-a2); // Slope for knee gamma
|
||||||
|
|
||||||
|
@ -482,36 +493,84 @@ vec4 mixfix_v4(vec4 a, vec4 b, float c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
//---------------------- Range Expansion/Compression -------------------
|
|
||||||
|
|
||||||
// 0-235 YUV PAL
|
//---------------------- Gamut Compression -------------------
|
||||||
// 0-235 YUV NTSC-J
|
|
||||||
// 16-235 YUV NTSC
|
|
||||||
|
|
||||||
// to Studio Swing/Broadcast Safe/SMPTE legal/Limited Range
|
|
||||||
vec3 PCtoTV(vec3 col, float luma_swing, float Umax, float Vmax, float max_swing)
|
|
||||||
{
|
|
||||||
col *= 255.;
|
|
||||||
vec2 UVmax = (max_swing == 1.0) ? vec2(Umax,Vmax) * 224. : vec2(Umax,Vmax) * 239.;
|
|
||||||
|
|
||||||
col.x = (luma_swing == 1.0) ? ((col.x * 219.) / 255.) + 16. : col.x;
|
// RGB 'Desaturate' Gamut Compression (by Jed Smith: https://github.com/jedypod/gamut-compress)
|
||||||
col.yz = (((col.yz - 128.) * (UVmax * 2.)) / 255.) + UVmax;
|
vec3 GamutCompression (vec3 rgb, float grey) {
|
||||||
return col.xyz / 255.;
|
|
||||||
|
// Limit/Thres order is Cyan, Magenta, Yellow
|
||||||
|
vec3 beam = max(vec3(0.0),vec3(beamg,(beamb+beamr)/2,(beamr+beamg)/2));
|
||||||
|
vec3 sat = max(vec3(0.0),vec3(satg, (satb +satr) /2,(satr +satg) /2)+1); // center at 1
|
||||||
|
float temp = max(0,abs(global.wp_temperature-7000)-1000)/825.0+1; // center at 1
|
||||||
|
vec3 WPD = global.wp_temperature < 7000 ? vec3(1,temp,(temp-1)/2+1) : vec3((temp-1)/2+1,temp,1);
|
||||||
|
sat = max(0.0,g_sat+1)*(sat*beam) * WPD;
|
||||||
|
|
||||||
|
mat2x3 LimThres = \
|
||||||
|
mat2x3( 0.100000,0.100000,0.100000,
|
||||||
|
0.125000,0.125000,0.125000);
|
||||||
|
if (SPC < 1.0) {
|
||||||
|
|
||||||
|
LimThres = \
|
||||||
|
crtgamut == 3.0 ? mat2x3( 0.000000,0.044065,0.000000,
|
||||||
|
0.000000,0.095638,0.000000) : \
|
||||||
|
crtgamut == 2.0 ? mat2x3( 0.006910,0.092133,0.000000,
|
||||||
|
0.039836,0.121390,0.000000) : \
|
||||||
|
crtgamut == 1.0 ? mat2x3( 0.018083,0.059489,0.017911,
|
||||||
|
0.066570,0.105996,0.066276) : \
|
||||||
|
crtgamut ==-1.0 ? mat2x3( 0.014947,0.098571,0.017911,
|
||||||
|
0.060803,0.123793,0.066276) : \
|
||||||
|
crtgamut ==-2.0 ? mat2x3( 0.004073,0.030307,0.012697,
|
||||||
|
0.028222,0.083075,0.056029) : \
|
||||||
|
crtgamut ==-3.0 ? mat2x3( 0.018424,0.053469,0.016841,
|
||||||
|
0.067146,0.102294,0.064393) : LimThres;
|
||||||
|
} else if (SPC==1.0) {
|
||||||
|
|
||||||
|
LimThres = \
|
||||||
|
crtgamut == 3.0 ? mat2x3( 0.000000,0.234229,0.007680,
|
||||||
|
0.000000,0.154983,0.042446) : \
|
||||||
|
crtgamut == 2.0 ? mat2x3( 0.078526,0.108432,0.006143,
|
||||||
|
0.115731,0.127194,0.037039) : \
|
||||||
|
crtgamut == 1.0 ? mat2x3( 0.021531,0.237184,0.013466,
|
||||||
|
0.072018,0.155438,0.057731) : \
|
||||||
|
crtgamut ==-1.0 ? mat2x3( 0.051640,0.103332,0.013550,
|
||||||
|
0.101092,0.125474,0.057912) : \
|
||||||
|
crtgamut ==-2.0 ? mat2x3( 0.032717,0.525361,0.023928,
|
||||||
|
0.085609,0.184491,0.075381) : \
|
||||||
|
crtgamut ==-3.0 ? mat2x3( 0.000000,0.377522,0.043076,
|
||||||
|
0.000000,0.172390,0.094873) : LimThres;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Amount of outer gamut to affect
|
||||||
|
vec3 th = 1.0-vec3(LimThres[1])*(0.4*sat+0.3);
|
||||||
|
|
||||||
// to Full Swing/Full Range
|
// Distance limit: How far beyond the gamut boundary to compress
|
||||||
vec3 TVtoPC(vec3 col, float luma_swing, float Umax, float Vmax, float max_swing)
|
vec3 dl = 1.0+vec3(LimThres[0])*sat;
|
||||||
{
|
|
||||||
col *= 255.;
|
|
||||||
vec2 UVmax = (max_swing == 1.0) ? vec2(Umax,Vmax) * 224. : vec2(Umax,Vmax) * 239.;
|
|
||||||
|
|
||||||
col.x = (luma_swing == 1.0) ? ((col.x - 16.) / 219.) * 255. : col.x;
|
// Calculate scale so compression function passes through distance limit: (x=dl, y=1)
|
||||||
col.yz = (((col.yz - UVmax) / (UVmax * 2.)) * 255.) + 128.;
|
vec3 s = (vec3(1)-th)/sqrt(max(vec3(1.001), dl)-1.0);
|
||||||
return col.xyz / 255.;
|
|
||||||
|
// Achromatic axis
|
||||||
|
float ac = max(rgb.x, max(rgb.y, rgb.z));
|
||||||
|
|
||||||
|
// Inverse RGB Ratios: distance from achromatic axis
|
||||||
|
vec3 d = ac==0.0?vec3(0.0):(ac-rgb)/abs(ac);
|
||||||
|
|
||||||
|
// Compressed distance. Parabolic compression function: https://www.desmos.com/calculator/nvhp63hmtj
|
||||||
|
vec3 cd;
|
||||||
|
vec3 sf = s*sqrt(d-th+s*s/4.0)-s*sqrt(s*s/4.0)+th;
|
||||||
|
cd.x = (d.x < th.x) ? d.x : sf.x;
|
||||||
|
cd.y = (d.y < th.y) ? d.y : sf.y;
|
||||||
|
cd.z = (d.z < th.z) ? d.z : sf.z;
|
||||||
|
|
||||||
|
// Inverse RGB Ratios to RGB
|
||||||
|
// and Mask with "luma"
|
||||||
|
return mix(rgb, ac-cd.xyz*abs(ac), pow(grey,1/2.4));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
|
//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -522,6 +581,10 @@ vec3 TVtoPC(vec3 col, float luma_swing, float Umax, float Vmax, float max_swing)
|
||||||
//----------------------- Y'UV color model -----------------------
|
//----------------------- Y'UV color model -----------------------
|
||||||
|
|
||||||
|
|
||||||
|
// 0-235 YUV PAL
|
||||||
|
// 0-235 YUV NTSC-J
|
||||||
|
// 16-235 YUV NTSC
|
||||||
|
|
||||||
|
|
||||||
// Bymax 0.885515
|
// Bymax 0.885515
|
||||||
// Rymax 0.701088
|
// Rymax 0.701088
|
||||||
|
@ -536,13 +599,14 @@ const mat3 YByRy =
|
||||||
|
|
||||||
// Umax 0.435812284313725
|
// Umax 0.435812284313725
|
||||||
// Vmax 0.615857694117647
|
// Vmax 0.615857694117647
|
||||||
|
// R'G'B' full to Y'UV limited
|
||||||
// YUV is defined with headroom and footroom (TV range),
|
// YUV is defined with headroom and footroom (TV range),
|
||||||
// we need to limit the excursion to 16-235.
|
// UV excursion is limited to Umax and Vmax
|
||||||
// This is still R'G'B' full to YUV full though
|
// Y excursion is limited to 16-235 for NTSC-U and 0-235 for PAL and NTSC-J
|
||||||
vec3 r601_YUV(vec3 RGB) {
|
vec3 r601_YUV(vec3 RGB, float NTSC_U) {
|
||||||
|
|
||||||
float sclU = ((0.5*(235-16)+16)/255.); // This yields Luma grey at around 0.49216 or 125.5 in 8-bit
|
const float sclU = ((0.5*(235-16)+16)/255.); // This yields Luma grey at around 0.49216 or 125.5 in 8-bit
|
||||||
float sclV = (240-16) /255. ; // This yields Chroma range at around 0.87843 or 224 in 8-bit
|
const float sclV = (240-16) /255. ; // This yields Chroma range at around 0.87843 or 224 in 8-bit
|
||||||
|
|
||||||
mat3 conv_mat = mat3(
|
mat3 conv_mat = mat3(
|
||||||
vec3(YByRy[0]),
|
vec3(YByRy[0]),
|
||||||
|
@ -551,21 +615,39 @@ vec3 r601_YUV(vec3 RGB) {
|
||||||
|
|
||||||
// -0.147111592156863 -0.288700692156863 0.435812284313725
|
// -0.147111592156863 -0.288700692156863 0.435812284313725
|
||||||
// 0.615857694117647 -0.515290478431373 -0.100567215686275
|
// 0.615857694117647 -0.515290478431373 -0.100567215686275
|
||||||
return RGB.rgb * conv_mat;
|
|
||||||
|
vec3 YUV = RGB.rgb * conv_mat;
|
||||||
|
YUV.x = NTSC_U==1.0 ? YUV.x * 219.0 + 16.0 : YUV.x * 235.0;
|
||||||
|
return vec3(YUV.x/255.0,YUV.yz);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
vec3 YUV_r601(vec3 YUV) {
|
// Y'UV limited to R'G'B' full
|
||||||
|
vec3 YUV_r601(vec3 YUV, float NTSC_U) {
|
||||||
|
|
||||||
mat3 conv_mat = mat3(
|
const mat3 conv_mat = mat3(
|
||||||
1.0000000, -0.000000029378826483, 1.1383928060531616,
|
1.0000000, -0.000000029378826483, 1.1383928060531616,
|
||||||
1.0000000, -0.396552562713623050, -0.5800843834877014,
|
1.0000000, -0.396552562713623050, -0.5800843834877014,
|
||||||
1.0000000, 2.031872510910034000, 0.0000000000000000);
|
1.0000000, 2.031872510910034000, 0.0000000000000000);
|
||||||
|
|
||||||
|
YUV.x = (YUV.x - (NTSC_U == 1.0 ? 16.0/255.0 : 0.0 )) * (255.0/(NTSC_U == 1.0 ? 219.0 : 235.0));
|
||||||
return YUV.xyz * conv_mat;
|
return YUV.xyz * conv_mat;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// FP32 to 8-bit mid-tread uniform quantization
|
||||||
|
float Quantize8(float col) {
|
||||||
|
col = min(255.0,floor(col * 255.0 + 0.5));
|
||||||
|
return col;
|
||||||
|
}
|
||||||
|
|
||||||
|
vec3 Quantize8_f3(vec3 col) {
|
||||||
|
col.r = Quantize8(col.r);
|
||||||
|
col.g = Quantize8(col.g);
|
||||||
|
col.b = Quantize8(col.b);
|
||||||
|
return col.rgb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
//------------------------- LMS --------------------------
|
//------------------------- LMS --------------------------
|
||||||
|
@ -613,7 +695,7 @@ const mat3 SMPTE470BG_ph =
|
||||||
// NTSC-J P22
|
// NTSC-J P22
|
||||||
// Mix between averaging KV-20M20, KDS VS19, Dell D93, 4-TR-B09v1_0.pdf and Phosphor Handbook 'P22'
|
// Mix between averaging KV-20M20, KDS VS19, Dell D93, 4-TR-B09v1_0.pdf and Phosphor Handbook 'P22'
|
||||||
// ILLUMINANT: D93->[0.281000,0.311000] (CCT of 8945.436K)
|
// ILLUMINANT: D93->[0.281000,0.311000] (CCT of 8945.436K)
|
||||||
// ILLUMINANT: D97->[0.285000,0.285000] (CCT of 9696K) for Nanao MS-2930s series
|
// ILLUMINANT: D97->[0.285000,0.285000] (CCT of 9696K) for Nanao MS-2930s series (in practice prolly more like ~9177.98K)
|
||||||
const mat3 P22_J_ph =
|
const mat3 P22_J_ph =
|
||||||
mat3(
|
mat3(
|
||||||
0.625, 0.280, 0.152,
|
0.625, 0.280, 0.152,
|
||||||
|
@ -649,6 +731,7 @@ const mat3 CRT_95s_ph =
|
||||||
|
|
||||||
//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
|
//*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/*/
|
||||||
|
|
||||||
|
|
||||||
//----------------------- Display Primaries -----------------------
|
//----------------------- Display Primaries -----------------------
|
||||||
|
|
||||||
// sRGB (IEC 61966-2-1) and ITU-R BT.709-6 (originally CCIR Rec.709)
|
// sRGB (IEC 61966-2-1) and ITU-R BT.709-6 (originally CCIR Rec.709)
|
||||||
|
@ -691,32 +774,32 @@ void main()
|
||||||
{
|
{
|
||||||
|
|
||||||
// Retro Sega Systems: Genesis, 32x, CD and Saturn 2D had color palettes designed in TV levels to save on transformations.
|
// Retro Sega Systems: Genesis, 32x, CD and Saturn 2D had color palettes designed in TV levels to save on transformations.
|
||||||
float lum_exp = (lum_fix == 1.0) ? (255./239.) : 1.;
|
float lum_exp = (lum_fix == 1.0) ? (255.0/239.0) : 1.0;
|
||||||
|
|
||||||
vec3 src = texture(Source, vTexCoord.xy).rgb * lum_exp;
|
vec3 src = texture(Source, vTexCoord.xy).rgb * lum_exp;
|
||||||
|
|
||||||
// Clipping Logic / Gamut Limiting
|
// Clipping Logic / Gamut Limiting
|
||||||
vec2 UVmax = vec2(0.435812284313725, 0.615857694117647);
|
bool NTSC_U = crtgamut < 2.0;
|
||||||
|
|
||||||
|
vec2 UVmax = vec2(Quantize8(0.435812284313725), Quantize8(0.615857694117647));
|
||||||
|
vec2 Ymax = NTSC_U ? vec2(16.0, 235.0) : vec2(0.0, 235.0);
|
||||||
|
|
||||||
|
|
||||||
// Assumes framebuffer in Rec.601 full range with baked gamma
|
// Assumes framebuffer in Rec.601 full range with baked gamma
|
||||||
vec3 col = clamp(r601_YUV(src), vec3(0.0, -UVmax.x, -UVmax.y) , \
|
// Quantize to 8-bit to replicate CRT's circuit board arithmetics
|
||||||
vec3(1.0, UVmax.x, UVmax.y));
|
vec3 col = clamp(Quantize8_f3(r601_YUV(src, NTSC_U ? 1.0 : 0.0)), vec3(Ymax.x, -UVmax.x, -UVmax.y), \
|
||||||
|
vec3(Ymax.y, UVmax.x, UVmax.y))/255.0;
|
||||||
col = crtgamut < 2.0 ? PCtoTV(col, 1.0, UVmax.x, UVmax.y, 1.0) : col;
|
|
||||||
|
|
||||||
|
|
||||||
// YUV Analogue Color Controls (HUE + Color Shift + Color Burst)
|
// YUV Analogue Color Controls (HUE + Color Shift + Color Burst)
|
||||||
float hue_radians = hue_degrees * M_PI;
|
float hue_radians = hue_degrees * M_PI;
|
||||||
float hue = atan(col.z, col.y) + hue_radians;
|
float hue = atan(col.z, col.y) + hue_radians;
|
||||||
float chroma = sqrt(col.z * col.z + col.y * col.y);
|
float chroma = sqrt(col.z * col.z + col.y * col.y); // Euclidean Distance
|
||||||
col = vec3(col.x, chroma * cos(hue), chroma * sin(hue));
|
|
||||||
|
|
||||||
col.y = (mod((col.y + 1.0) + U_SHIFT, 2.0) - 1.0) * U_MUL;
|
col.y = (mod((chroma * cos(hue) + 1.0) + U_SHIFT, 2.0) - 1.0) * U_MUL;
|
||||||
col.z = (mod((col.z + 1.0) + V_SHIFT, 2.0) - 1.0) * V_MUL;
|
col.z = (mod((chroma * sin(hue) + 1.0) + V_SHIFT, 2.0) - 1.0) * V_MUL;
|
||||||
|
|
||||||
// Back to RGB
|
// Back to R'G'B' full
|
||||||
col = crtgamut < 2.0 ? TVtoPC(col, 1.0, UVmax.x, UVmax.y, 1.0) : col;
|
col = signal > 0.0 ? max(Quantize8_f3(YUV_r601(col.xyz, NTSC_U ? 1.0 : 0.0))/255.0, 0.0) : src;
|
||||||
col = clamp(YUV_r601(col), 0., 1.);
|
|
||||||
|
|
||||||
// Look LUT - (in SPC space)
|
// Look LUT - (in SPC space)
|
||||||
float red = (col.r * (global.LUT_Size1 - 1.0) + 0.4999) / (global.LUT_Size1 * global.LUT_Size1);
|
float red = (col.r * (global.LUT_Size1 - 1.0) + 0.4999) / (global.LUT_Size1 * global.LUT_Size1);
|
||||||
|
@ -729,7 +812,7 @@ void main()
|
||||||
vec3 vcolor = (global.LUT1_toggle == 0.0) ? col : mixfix(color1, color2, mixer);
|
vec3 vcolor = (global.LUT1_toggle == 0.0) ? col : mixfix(color1, color2, mixer);
|
||||||
|
|
||||||
|
|
||||||
// CRT EOTF. To Display Referred Linear: Undo developer baked CRT gamma (from 2.40 at default 0.1 CRT black level, to 2.61 at 0.0 CRT black level)
|
// CRT EOTF. To Display Referred Linear: Undo developer baked CRT gamma (from 2.40 at default 0.1 CRT black level, to 2.60 at 0.0 CRT black level)
|
||||||
col = EOTF_1886a_f3(vcolor, g_CRT_l, params.g_CRT_b, params.g_CRT_c);
|
col = EOTF_1886a_f3(vcolor, g_CRT_l, params.g_CRT_b, params.g_CRT_c);
|
||||||
|
|
||||||
|
|
||||||
|
@ -799,7 +882,7 @@ void main()
|
||||||
float hue_radians_b = 100.0 * M_PI;
|
float hue_radians_b = 100.0 * M_PI;
|
||||||
float hue_b = cos(hue_at + hue_radians_b);
|
float hue_b = cos(hue_at + hue_radians_b);
|
||||||
|
|
||||||
float msk = dot(clamp(vec3(hue_r, hue_g, hue_b) * chroma * 2, 0., 1.), -vec3(satr, satg, satb));
|
float msk = dot(clamp(vec3(hue_r, hue_g, hue_b) * chroma * 2, 0.0, 1.0), -vec3(satr, satg, satb));
|
||||||
src_h = mix(col, vec3(dot(coeff, col)), msk);
|
src_h = mix(col, vec3(dot(coeff, col)), msk);
|
||||||
|
|
||||||
float sat_msk = (vibr < 0.0) ? 1.0 - abs(SatMask(src_h.x, src_h.y, src_h.z) - 1.0) * abs(vibr) : \
|
float sat_msk = (vibr < 0.0) ? 1.0 - abs(SatMask(src_h.x, src_h.y, src_h.z) - 1.0) * abs(vibr) : \
|
||||||
|
@ -816,14 +899,18 @@ void main()
|
||||||
msatz , msatz , msatz + sat);
|
msatz , msatz , msatz + sat);
|
||||||
|
|
||||||
|
|
||||||
src_h = mix(src_h, adjust * src_h, clamp(sat_msk, 0., 1.));
|
src_h = mix(src_h, adjust * src_h, clamp(sat_msk, 0.0, 1.0));
|
||||||
src_h = clamp(src_h*vec3(beamr,beamg,beamb),0.0,1.0);
|
src_h *= vec3(beamr,beamg,beamb);
|
||||||
|
|
||||||
|
|
||||||
|
// RGB 'Desaturate' Gamut Compression (by Jed Smith: https://github.com/jedypod/gamut-compress)
|
||||||
|
coeff = RGB_to_XYZ_mat(m_ou)[1];
|
||||||
|
src_h = GCompress==1.0 ? clamp(GamutCompression(src_h, dot(coeff.xyz, src_h)), 0.0, 1.0) : clamp(src_h, 0.0, 1.0);
|
||||||
|
|
||||||
|
|
||||||
// Sigmoidal Luma Contrast under 'Yxy' decorrelated model (in gamma space)
|
// Sigmoidal Luma Contrast under 'Yxy' decorrelated model (in gamma space)
|
||||||
vec3 Yxy = XYZtoYxy(RGB_to_XYZ(src_h, m_ou));
|
vec3 Yxy = XYZtoYxy(RGB_to_XYZ(src_h, m_ou));
|
||||||
float toGamma = clamp(moncurve_r(Yxy.r, 2.40, 0.055), 0., 1.);
|
float toGamma = clamp(moncurve_r(Yxy.r, 2.40, 0.055), 0.0, 1.0);
|
||||||
toGamma = (Yxy.r > 0.5) ? contrast_sigmoid_inv(toGamma, 2.3, 0.5) : toGamma;
|
toGamma = (Yxy.r > 0.5) ? contrast_sigmoid_inv(toGamma, 2.3, 0.5) : toGamma;
|
||||||
float sigmoid = (cntrst > 0.0) ? contrast_sigmoid(toGamma, cntrst, mid) : contrast_sigmoid_inv(toGamma, cntrst, mid);
|
float sigmoid = (cntrst > 0.0) ? contrast_sigmoid(toGamma, cntrst, mid) : contrast_sigmoid_inv(toGamma, cntrst, mid);
|
||||||
vec3 contrast = vec3(moncurve_f(sigmoid, 2.40, 0.055), Yxy.g, Yxy.b);
|
vec3 contrast = vec3(moncurve_f(sigmoid, 2.40, 0.055), Yxy.g, Yxy.b);
|
||||||
|
@ -832,12 +919,11 @@ void main()
|
||||||
|
|
||||||
|
|
||||||
// Lift + Gain -PP Digital Controls- (Could do in Yxy but performance reasons)
|
// Lift + Gain -PP Digital Controls- (Could do in Yxy but performance reasons)
|
||||||
src_h = clamp(rolled_gain_v3(contrast, clamp(lum, -0.49, 0.99)), 0., 1.);
|
src_h = clamp(rolled_gain_v3(contrast, clamp(lum, -0.49, 0.99)), 0.0, 1.0);
|
||||||
src_h += (lift / 20.0) * (1.0 - contrast);
|
src_h += (lift / 20.0) * (1.0 - contrast);
|
||||||
|
|
||||||
|
|
||||||
|
// Vignetting (in linear space, so after EOTF^-1 it's power shaped; 0.5 thres converts to ~0.75)
|
||||||
// Vignetting & Black Level (in linear space, so after EOTF^-1 it's power shaped; 0.5 thres converts to ~0.75)
|
|
||||||
vec2 vpos = vTexCoord*(global.OriginalSize.xy/global.SourceSize.xy);
|
vec2 vpos = vTexCoord*(global.OriginalSize.xy/global.SourceSize.xy);
|
||||||
|
|
||||||
vpos *= 1.0 - vpos.xy;
|
vpos *= 1.0 - vpos.xy;
|
||||||
|
@ -859,6 +945,11 @@ void main()
|
||||||
clamp(pow( src_D, vec3(1./(2.20 + 0.20))), 0., 1.) ;
|
clamp(pow( src_D, vec3(1./(2.20 + 0.20))), 0., 1.) ;
|
||||||
|
|
||||||
|
|
||||||
|
// External Flare for Surround Illuminant 2700K (Soft White) at F0 (Lambertian reflectance); defines offset thus also black lift
|
||||||
|
vec3 Flare = 0.01 * (global.g_CRT_rf/5.0)*(0.049433*global.g_CRT_sl - 0.188367) * vec3(0.459993/0.410702,1.0,0.129305/0.410702);
|
||||||
|
TRC = global.g_CRT_sl > 0.0 ? min(TRC+Flare,1.0) : TRC;
|
||||||
|
|
||||||
|
|
||||||
// Technical LUT - (in SPC space)
|
// Technical LUT - (in SPC space)
|
||||||
float red_2 = (TRC.r * (global.LUT_Size2 - 1.0) + 0.4999) / (global.LUT_Size2 * global.LUT_Size2);
|
float red_2 = (TRC.r * (global.LUT_Size2 - 1.0) + 0.4999) / (global.LUT_Size2 * global.LUT_Size2);
|
||||||
float green_2 = (TRC.g * (global.LUT_Size2 - 1.0) + 0.4999) / global.LUT_Size2;
|
float green_2 = (TRC.g * (global.LUT_Size2 - 1.0) + 0.4999) / global.LUT_Size2;
|
||||||
|
|
Loading…
Reference in a new issue