mirror of
https://github.com/italicsjenga/slang-shaders.git
synced 2024-11-30 11:21:32 +11:00
238 lines
8.4 KiB
Plaintext
238 lines
8.4 KiB
Plaintext
#version 450
|
|
|
|
/*
|
|
A shader that tries to emulate a sony PVM type aperture grille screen but with full brightness.
|
|
|
|
The novel thing about this shader is that it relies on the HDR shaders to brighten up the image so that when
|
|
we apply this shader which emulates the apperture grille the resulting screen isn't left too dark.
|
|
|
|
I think you'd need a HDR 1000 monitor to get close to CRT levels of brightness but my HDR 700 does an alright job of it.
|
|
|
|
Please Enable HDR in RetroArch NOTE: when the hdr10 and inverse_tonemap shaders are envoked the Peak Luminance and Paper White Luminance in the menu do nothing instead set those values through the shader parameters instead
|
|
|
|
Set Peak Luminance to the peak luminance of your monitor and set Paper White Luminance to roughly half dependent on the game and the monitor.
|
|
|
|
Also try to use a integer scaling - its just better - overscaling is fine.
|
|
|
|
This shader doesn't do any geometry warping or bouncing of light around inside the screen etc - I think these effects just add unwanted noise, I know people disagree. Please feel free to make you own and add them
|
|
|
|
Dont use this shader directly - use the crt\crt-sony-pvm-4k-hdr.slangp to have the proper chain of effects.
|
|
*/
|
|
|
|
#pragma format A2B10G10R10_UNORM_PACK32
|
|
|
|
layout(push_constant) uniform Push
|
|
{
|
|
vec4 SourceSize;
|
|
vec4 OriginalSize;
|
|
vec4 OutputSize;
|
|
uint FrameCount;
|
|
float ScanlineWidth;
|
|
float ResolutionPattern;
|
|
float Sharpness;
|
|
} params;
|
|
|
|
#pragma parameter ScanlineWidth "Scanline Width" 0.95 0.0 1.0 0.01
|
|
#pragma parameter ResolutionPattern "Resolution Pattern" 2.0 0.0 8.0 1.0
|
|
#pragma parameter Sharpness "Sharpness" 1.8 0.0 5.0 0.1
|
|
|
|
layout(std140, set = 0, binding = 0) uniform UBO
|
|
{
|
|
mat4 MVP;
|
|
} global;
|
|
|
|
#pragma stage vertex
|
|
layout(location = 0) in vec4 Position;
|
|
layout(location = 1) in vec2 TexCoord;
|
|
layout(location = 0) out vec2 vTexCoord;
|
|
|
|
void main()
|
|
{
|
|
gl_Position = global.MVP * Position;
|
|
vTexCoord = TexCoord * vec2(1.00001); // To resolve rounding issues when sampling
|
|
}
|
|
|
|
#pragma stage fragment
|
|
layout(location = 0) in vec2 vTexCoord;
|
|
layout(location = 0) out vec4 FragColor;
|
|
layout(set = 0, binding = 2) uniform sampler2D Source;
|
|
layout(set = 0, binding = 3) uniform sampler2D StockPass;
|
|
|
|
float ModInteger(float a, float b)
|
|
{
|
|
float m = a - floor((a + 0.5) / b) * b;
|
|
return floor(m + 0.5);
|
|
}
|
|
|
|
#define kPi 3.1415926536
|
|
#define kEuler 2.718281828459
|
|
#define kMax 1.0
|
|
|
|
#define kGuassianMin vec3(1.1)
|
|
#define kGuassianMax vec3(3.0)
|
|
|
|
#define kRed vec3(1.0, 0.0, 0.0)
|
|
#define kGreen vec3(0.0, 1.0, 0.0)
|
|
#define kBlue vec3(0.0, 0.0, 1.0)
|
|
#define kMagenta vec3(1.0, 0.0, 1.0)
|
|
#define kYellow vec3(1.0, 1.0, 0.0)
|
|
#define kCyan vec3(0.0, 1.0, 1.0)
|
|
#define kBlack vec3(0.0, 0.0, 0.0)
|
|
#define kWhite vec3(1.0, 1.0, 1.0)
|
|
|
|
float Ramp(const float gaussian, float colour)
|
|
{
|
|
return clamp(gaussian * colour, 0.0, 1.0);
|
|
}
|
|
|
|
vec3 Ramp3(const vec3 gaussian, vec3 colour)
|
|
{
|
|
return clamp(gaussian * colour, vec3(0.0), vec3(1.0));
|
|
}
|
|
|
|
void main()
|
|
{
|
|
float ScanlineSize = params.OutputSize.y / params.SourceSize.y;
|
|
|
|
const vec2 InPixels = (vTexCoord * params.OutputSize.xy);
|
|
|
|
const float ScanlinePosition = (floor(vTexCoord.y * params.SourceSize.y) * ScanlineSize) + (ScanlineSize * 0.5);
|
|
|
|
float ScanlineDistance = ScanlinePosition - (floor(InPixels.y) + 0.5);
|
|
|
|
ScanlineDistance /= ScanlineSize * params.ScanlineWidth;
|
|
ScanlineDistance = clamp(abs(ScanlineDistance * 2.0), 0.0, 1.0);
|
|
|
|
const float Gaussian = pow(kEuler, -0.5 * pow(ScanlineDistance/0.3, 2.0)); /* Gaussian distribution */
|
|
|
|
float HorizInterp = (vTexCoord.x * params.SourceSize.x) - (floor(vTexCoord.x * params.SourceSize.x));
|
|
HorizInterp = clamp(((HorizInterp - 0.5) * params.Sharpness) + 0.5, 0.0f, 1.0);
|
|
|
|
const vec2 SourceTexCoord0 = vec2(vTexCoord.x, ScanlinePosition / params.OutputSize.y);
|
|
|
|
vec3 HDRColour0 = texture(Source, SourceTexCoord0).xyz;
|
|
vec3 SDRColour0 = texture(StockPass, SourceTexCoord0).xyz;
|
|
|
|
const vec2 SourceTexCoord1 = vec2(vTexCoord.x + (1.0 / params.SourceSize.x), ScanlinePosition / params.OutputSize.y);
|
|
|
|
const vec3 HDRColour1 = texture(Source, SourceTexCoord1).xyz;
|
|
const vec3 SDRColour1 = texture(StockPass, SourceTexCoord1).xyz;
|
|
|
|
const vec3 HDRColour = mix(HDRColour0, HDRColour1, vec3(HorizInterp));
|
|
const vec3 SDRColour = mix(SDRColour0, SDRColour1, vec3(HorizInterp));
|
|
|
|
vec3 Luminance = Ramp3(vec3(Gaussian), (SDRColour * kGuassianMax) + kGuassianMin);
|
|
|
|
vec3 OutputColour;
|
|
|
|
/* Various resolution patterns - remember your LCD 4K screen will likely be 16:9 whereas
|
|
the CRT TV will likely be 4:3 and so higher TVL values will be required on your 16:9 screen
|
|
to get an equivalent TVL seen on a 4:3 CRT TV.
|
|
Pattern 1's 960TVL at 16:9 is about right for a 800TVL at 4:3.
|
|
*/
|
|
|
|
uint ResolutionPattern = uint(params.ResolutionPattern);
|
|
|
|
switch(ResolutionPattern)
|
|
{
|
|
case 0: /* 2 pattern - 1440TVL (16:9) horiz resolution (too high?) on a 4K screen */
|
|
{
|
|
const uint PatternSize = 2;
|
|
const vec3 Mask[2] = vec3[]( kYellow, kCyan );
|
|
|
|
uint PatternX = uint(ModInteger(floor(InPixels.x), PatternSize));
|
|
OutputColour = Luminance * HDRColour * Mask[PatternX];
|
|
|
|
break;
|
|
}
|
|
case 1: /* 3 pattern - 960TVL (16:9) horiz resolution on a 4K screen */
|
|
{
|
|
const uint PatternSize = 3;
|
|
const vec3 Mask[3] = vec3[]( kRed, kGreen, kBlue );
|
|
|
|
uint PatternX = uint(ModInteger(floor(InPixels.x), PatternSize));
|
|
OutputColour = Luminance * HDRColour * Mask[PatternX];
|
|
|
|
break;
|
|
}
|
|
case 2: /* 4 pattern - 720TVL (16:9) horiz resolution on a 4K screen */
|
|
{
|
|
const uint PatternSize = 4;
|
|
const vec3 Mask[4] = vec3[]( kRed, kYellow, kCyan, kBlue );
|
|
|
|
uint PatternX = uint(ModInteger(floor(InPixels.x), PatternSize));
|
|
OutputColour = Luminance * HDRColour * Mask[PatternX];
|
|
|
|
break;
|
|
}
|
|
case 3: /* 5 BRG pattern - 576TVL (16:9) horiz resolution on a 4K screen */
|
|
{
|
|
const uint PatternSize = 5;
|
|
const vec3 Mask[5] = vec3[]( kRed, kMagenta, kBlue, kGreen, kGreen );
|
|
|
|
uint PatternX = uint(ModInteger(floor(InPixels.x), PatternSize));
|
|
OutputColour = Luminance * HDRColour * Mask[PatternX];
|
|
|
|
break;
|
|
}
|
|
case 4: /* 5 pattern - 576TVL (16:9) horiz resolution on a 4K screen */
|
|
{
|
|
const uint PatternSize = 5;
|
|
const vec3 Mask[5] = vec3[]( kRed, kYellow, kGreen, kCyan, kBlue );
|
|
|
|
uint PatternX = uint(ModInteger(floor(InPixels.x), PatternSize));
|
|
OutputColour = Luminance * HDRColour * Mask[PatternX];
|
|
|
|
break;
|
|
}
|
|
case 5: /* 6 pattern - 480TVL (16:9) horiz resolution on a 4K screen */
|
|
{
|
|
const uint PatternSize = 6;
|
|
const vec3 Mask[6] = vec3[]( kRed, kRed, kGreen, kGreen, kBlue, kBlue );
|
|
|
|
uint PatternX = uint(ModInteger(floor(InPixels.x), PatternSize));
|
|
OutputColour = Luminance * HDRColour * Mask[PatternX];
|
|
|
|
break;
|
|
}
|
|
case 6: /* 7 pattern - 410TVL (16:9) horiz resolution on a 4K screen */
|
|
{
|
|
const uint PatternSize = 7;
|
|
const vec3 Mask[7] = vec3[]( kRed, kRed, kYellow, kGreen, kCyan, kBlue, kBlue );
|
|
|
|
uint PatternX = uint(ModInteger(floor(InPixels.x), PatternSize));
|
|
OutputColour = Luminance * HDRColour * Mask[PatternX];
|
|
|
|
break;
|
|
}
|
|
case 7: /* 9 pattern - 640TVL (16:9) horiz resolution on a *8K* screen */
|
|
{
|
|
const uint PatternSize = 9;
|
|
const vec3 Mask[9] = vec3[]( kBlack, kRed, kRed, kBlack, kGreen, kGreen, kBlack, kBlue, kBlue );
|
|
|
|
uint PatternX = uint(ModInteger(floor(InPixels.x), PatternSize));
|
|
OutputColour = Luminance * HDRColour * Mask[PatternX];
|
|
|
|
break;
|
|
}
|
|
case 8: /* 12 pattern - 480TVL (16:9) horiz resolution on a *8K* screen */
|
|
{
|
|
const uint PatternSize = 12;
|
|
const vec3 Mask[12] = vec3[]( kBlack, kRed, kRed, kRed, kBlack, kGreen, kGreen, kGreen, kBlack, kBlue, kBlue, kBlue );
|
|
|
|
uint PatternX = uint(ModInteger(floor(InPixels.x), PatternSize));
|
|
OutputColour = Luminance * HDRColour * Mask[PatternX];
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
OutputColour = vec3(0.0);
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
FragColor = vec4(OutputColour, 1.0);
|
|
}
|