Added gamma, brightness and contrast controls

This commit is contained in:
MajorPainTheCactus 2022-03-07 21:50:18 +00:00
parent 5dae9be43f
commit 248f0a775c
3 changed files with 101 additions and 43 deletions

View file

@ -35,6 +35,22 @@ alias0 = ""
float_framebuffer0 = "false"
srgb_framebuffer0 = "false"
/*
CRT Bright levels
hcrt_brightness = "0.300000"
hcrt_colour_system = "0.000000"
hcrt_white_temperature = "2800.000000"
hcrt_expand_gamut = "1.000000"
hcrt_contrast = "0.800000"
hcrt_gamma = "-0.200000"
*/
hcrt_brightness = "0.150000"
hcrt_colour_system = "0.000000"
hcrt_white_temperature = "2800.000000"
hcrt_expand_gamut = "1.000000"
hcrt_contrast = "0.000000"
hcrt_gamma = "0.000000"
hcrt_red_vertical_convergence = "-0.140000"
hcrt_green_vertical_convergence = "0.000000"
hcrt_blue_vertical_convergence = "0.000000"

View file

@ -79,6 +79,7 @@ layout(std140, set = 0, binding = 0) uniform UBO
float hcrt_colour_system;
float hcrt_colour_space;
float hcrt_white_temperature;
float hcrt_gamma;
} global;
@ -100,9 +101,9 @@ layout(std140, set = 0, binding = 0) uniform UBO
#pragma parameter hcrt_paper_white_nits " Display's Paper White Luminance" 700.0 0.0 10000.0 10.0
#pragma parameter hcrt_lcd_resolution " Display's Resolution: 4K | 8K" 0.0 0.0 1.0 1.0
#pragma parameter hcrt_lcd_subpixel " Display's Subpixel Layout: RGB | BGR" 0.0 0.0 1.0 1.0
#pragma parameter hcrt_brightness " Brightness" 0.0 -1.0 1.0 0.05
#pragma parameter hcrt_contrast " Contrast" 0.0 -1.0 1.0 0.05
#pragma parameter hcrt_expand_gamut " Original/Vivid" 0.0 0.0 1.0 1.0
#pragma parameter hcrt_brightness " Brightness" 0.0 -1.0 1.0 0.01
#pragma parameter hcrt_contrast " Contrast" 0.0 -1.0 1.0 0.01
#pragma parameter hcrt_gamma " Gamma" 0.0 -1.0 1.0 0.01
#pragma parameter hcrt_red_vertical_convergence " Red Vertical Convergence" 0.00 -10.0 10.0 0.01
#pragma parameter hcrt_green_vertical_convergence " Green Vertical Convergence" 0.00 -10.0 10.0 0.01
#pragma parameter hcrt_blue_vertical_convergence " Blue Vertical Convergence" 0.00 -10.0 10.0 0.01
@ -117,6 +118,7 @@ layout(std140, set = 0, binding = 0) uniform UBO
#pragma parameter hcrt_colour_system " CRT Colour System: PAL | NTSC-U | NTSC-J" 1.0 0.0 2.0 1.0
#pragma parameter hcrt_colour_space " Colour Space: Rec.601/Rec.709 | sRGB" 0.0 0.0 1.0 1.0
#pragma parameter hcrt_white_temperature " White Point: (PAL:D65, NTSC-U:D65, NTSC-J:D93)" 0.0 -5000.0 12000.0 100.0
#pragma parameter hcrt_expand_gamut " Original/Vivid" 0.0 0.0 1.0 1.0
#pragma parameter hcrt_developer_settings0 " VERTICAL SETTINGS:" 0.0 0.0 0.0001 0.0
#pragma parameter hcrt_red_scanline_min " Red Scanline Min" 0.50 0.0 2.0 0.01
@ -157,6 +159,7 @@ layout(std140, set = 0, binding = 0) uniform UBO
#define HCRT_CRT_COLOUR_SPACE global.hcrt_colour_space
#define HCRT_CRT_COLOUR_SYSTEM global.hcrt_colour_system
#define HCRT_WHITE_TEMPERATURE global.hcrt_white_temperature
#define HCRT_GAMMA global.hcrt_gamma
#define HCRT_RED_SCANLINE_MIN params.hcrt_red_scanline_min
#define HCRT_RED_SCANLINE_MAX params.hcrt_red_scanline_max

View file

@ -17,7 +17,7 @@ const mat3 sRGB_to_XYZ = mat3(
0.35758456587791443, 0.71516913175582890, 0.119194857776165010,
0.18045382201671600, 0.07218152284622192, 0.950390160083770800);
// Phosphor transforms found in Grade.slang
// Phosphor transforms found in Dogway's Grade.slang shader
// SMPTE-C - Measured Average Phosphor (1979-1994)
const mat3 P22_transform = mat3(
@ -77,7 +77,7 @@ vec3 WhiteBalance(float temperature, vec3 colour)
float r601r709ToLinear_1(const float channel)
{
return (channel > 0.081f) ? pow((channel + 0.099f) * (1.0f / 1.099f), 1.0f / 0.45f) : channel * (1.0f / 4.5f);
return (channel >= 0.081f) ? pow((channel + 0.099f) * (1.0f / 1.099f), (1.0f / 0.45f) + HCRT_GAMMA) : channel * (1.0f / 4.5f);
}
vec3 r601r709ToLinear(const vec3 colour)
@ -85,48 +85,19 @@ vec3 r601r709ToLinear(const vec3 colour)
return vec3(r601r709ToLinear_1(colour.r), r601r709ToLinear_1(colour.g), r601r709ToLinear_1(colour.b));
}
const vec4 kTopBrightnessControlPoints = vec4(0.0f, 1.0f, 1.0f, 1.0f);
const vec4 kMidBrightnessControlPoints = vec4(0.0f, 1.0f / 3.0f, (1.0f / 3.0f) * 2.0f, 1.0f);
const vec4 kBottomBrightnessControlPoints = vec4(0.0f, 0.0f, 0.0f, 1.0f);
float LinearTor601r709_1(const float channel)
{
return (channel >= 0.018f) ? pow(channel * 1.099f, 0.45f) - 0.099f : channel * 4.5f;
}
vec3 Brightness(const vec3 colour)
vec3 LinearTor601r709(const vec3 colour)
{
if(HCRT_BRIGHTNESS >= 0.0f)
{
return vec3(Bezier(colour.r, mix(kMidBrightnessControlPoints, kTopBrightnessControlPoints, HCRT_BRIGHTNESS)),
Bezier(colour.g, mix(kMidBrightnessControlPoints, kTopBrightnessControlPoints, HCRT_BRIGHTNESS)),
Bezier(colour.b, mix(kMidBrightnessControlPoints, kTopBrightnessControlPoints, HCRT_BRIGHTNESS)));
}
else
{
return vec3(Bezier(colour.r, mix(kMidBrightnessControlPoints, kBottomBrightnessControlPoints, abs(HCRT_BRIGHTNESS))),
Bezier(colour.g, mix(kMidBrightnessControlPoints, kBottomBrightnessControlPoints, abs(HCRT_BRIGHTNESS))),
Bezier(colour.b, mix(kMidBrightnessControlPoints, kBottomBrightnessControlPoints, abs(HCRT_BRIGHTNESS))));
}
}
const vec4 kTopContrastControlPoints = vec4(0.0f, 0.0f, 1.0f, 1.0f);
const vec4 kMidContrastControlPoints = vec4(0.0f, 1.0f / 3.0f, (1.0f / 3.0f) * 2.0f, 1.0f);
const vec4 kBottomContrastControlPoints = vec4(0.0f, 1.0f, 0.0f, 1.0f);
vec3 Contrast(const vec3 colour)
{
if(HCRT_CONTRAST >= 0.0f)
{
return vec3(Bezier(colour.r, mix(kMidContrastControlPoints, kTopContrastControlPoints, HCRT_CONTRAST)),
Bezier(colour.g, mix(kMidContrastControlPoints, kTopContrastControlPoints, HCRT_CONTRAST)),
Bezier(colour.b, mix(kMidContrastControlPoints, kTopContrastControlPoints, HCRT_CONTRAST)));
}
else
{
return vec3(Bezier(colour.r, mix(kMidContrastControlPoints, kBottomContrastControlPoints, abs(HCRT_CONTRAST))),
Bezier(colour.g, mix(kMidContrastControlPoints, kBottomContrastControlPoints, abs(HCRT_CONTRAST))),
Bezier(colour.b, mix(kMidContrastControlPoints, kBottomContrastControlPoints, abs(HCRT_CONTRAST))));
}
return vec3(LinearTor601r709_1(colour.r), LinearTor601r709_1(colour.g), LinearTor601r709_1(colour.b));
}
float sRGBToLinear_1(const float channel)
{
return (channel > 0.04045f) ? pow((channel + 0.055f) * (1.0f / 1.055f), 2.4f) : channel * (1.0f / 12.92f);
return (channel > 0.04045f) ? pow((channel + 0.055f) * (1.0f / 1.055f), 2.4f + HCRT_GAMMA) : channel * (1.0f / 12.92f);
}
vec3 sRGBToLinear(const vec3 colour)
@ -134,17 +105,85 @@ vec3 sRGBToLinear(const vec3 colour)
return vec3(sRGBToLinear_1(colour.r), sRGBToLinear_1(colour.g), sRGBToLinear_1(colour.b));
}
float LinearTosRGB_1(const float channel)
{
return (channel > 0.0031308f) ? (1.055f * pow(channel, 1.0f / 2.4f)) - 0.055f : channel * 12.92f;
}
vec3 LinearTosRGB(const vec3 colour)
{
return vec3(LinearTosRGB_1(colour.r), LinearTosRGB_1(colour.g), LinearTosRGB_1(colour.b));
}
// XYZ Yxy transforms found in Dogway's Grade.slang shader
vec3 XYZtoYxy(const vec3 XYZ)
{
const float XYZrgb = XYZ.r + XYZ.g + XYZ.b;
const float Yxyg = (XYZrgb <= 0.0f) ? 0.3805f : XYZ.r / XYZrgb;
const float Yxyb = (XYZrgb <= 0.0f) ? 0.3769f : XYZ.g / XYZrgb;
return vec3(XYZ.g, Yxyg, Yxyb);
}
vec3 YxytoXYZ(const vec3 Yxy)
{
const float Xs = Yxy.r * (Yxy.g / Yxy.b);
const float Xsz = (Yxy.r <= 0.0f) ? 0.0f : 1.0f;
const vec3 XYZ = vec3(Xsz, Xsz, Xsz) * vec3(Xs, Yxy.r, (Xs / Yxy.g) - Xs - Yxy.r);
return XYZ;
}
const vec4 kTopBrightnessControlPoints = vec4(0.0f, 1.0f, 1.0f, 1.0f);
const vec4 kMidBrightnessControlPoints = vec4(0.0f, 1.0f / 3.0f, (1.0f / 3.0f) * 2.0f, 1.0f);
const vec4 kBottomBrightnessControlPoints = vec4(0.0f, 0.0f, 0.0f, 1.0f);
float Brightness(const float luminance)
{
if(HCRT_BRIGHTNESS >= 0.0f)
{
return Bezier(luminance, mix(kMidBrightnessControlPoints, kTopBrightnessControlPoints, HCRT_BRIGHTNESS));
}
else
{
return Bezier(luminance, mix(kMidBrightnessControlPoints, kBottomBrightnessControlPoints, abs(HCRT_BRIGHTNESS)));
}
}
const vec4 kTopContrastControlPoints = vec4(0.0f, 0.0f, 1.0f, 1.0f);
const vec4 kMidContrastControlPoints = vec4(0.0f, 1.0f / 3.0f, (1.0f / 3.0f) * 2.0f, 1.0f);
const vec4 kBottomContrastControlPoints = vec4(0.0f, 1.0f, 0.0f, 1.0f);
float Contrast(const float luminance)
{
if(HCRT_CONTRAST >= 0.0f)
{
return Bezier(luminance, mix(kMidContrastControlPoints, kTopContrastControlPoints, HCRT_CONTRAST));
}
else
{
return Bezier(luminance, mix(kMidContrastControlPoints, kBottomContrastControlPoints, abs(HCRT_CONTRAST)));
}
}
vec3 ColourGrade(const vec3 colour)
{
const uint colour_system = uint(HCRT_CRT_COLOUR_SYSTEM);
const vec3 brightness = Brightness(colour);
const vec3 linear = HCRT_CRT_COLOUR_SPACE == 0.0f ? r601r709ToLinear(colour) : sRGBToLinear(colour);
const vec3 contrast = Contrast(brightness);
const vec3 xyz = sRGB_to_XYZ * linear;
const vec3 Yxy = XYZtoYxy(xyz);
const float Y_gamma = clamp(LinearTosRGB_1(Yxy.x), 0.0f, 1.0f);
const vec3 linear = HCRT_CRT_COLOUR_SPACE == 0.0f ? r601r709ToLinear(contrast) : sRGBToLinear(contrast);
const float Y_brightness = Brightness(Y_gamma);
const vec3 gamut = kPhosphorGamut[colour_system] * linear;
const float Y_contrast = Contrast(Y_brightness);
const vec3 contrast_linear = vec3(sRGBToLinear_1(Y_contrast), Yxy.y, Yxy.z);
const vec3 contrast_xyz = YxytoXYZ(contrast_linear);
const vec3 contrast = clamp(XYZ_to_sRGB * contrast_xyz, 0.0f, 1.0f);
const vec3 gamut = kPhosphorGamut[colour_system] * contrast;
const vec3 white_point = WhiteBalance(kTemperatures[colour_system] + HCRT_WHITE_TEMPERATURE, gamut);