2023-01-15 01:35:38 +11:00
|
|
|
#version 450
|
|
|
|
|
|
|
|
/*
|
2023-01-21 22:23:33 +11:00
|
|
|
crt-1tap v1.1 by fishku
|
2023-01-15 01:35:38 +11:00
|
|
|
Copyright (C) 2023
|
2023-01-21 22:23:33 +11:00
|
|
|
Public domain license (CC0)
|
2023-01-15 01:35:38 +11:00
|
|
|
|
|
|
|
Extremely fast and lightweight dynamic scanline shader.
|
|
|
|
Contrasty and sharp output. Easy to configure.
|
|
|
|
Can be combined with other shaders.
|
|
|
|
|
|
|
|
How it works: Uses a single texture "tap" per pixel, hence the name.
|
|
|
|
Exploits bilinear interpolation plus local coordinate distortion to shape
|
|
|
|
the scanline. A pseudo-sigmoid function with a configurable slope at the
|
|
|
|
inflection point is used to control horizontal smoothness.
|
|
|
|
Uses a clamped linear function to anti-alias the edge of the scanline while
|
|
|
|
avoiding further branching. The final thickness is shaped with a gamma-like
|
|
|
|
operation to control overall image contrast.
|
|
|
|
The scanline subpixel position can be controlled to achieve the best
|
|
|
|
sharpness and uniformity of the output given different input sizes, e.g.,
|
|
|
|
for even and odd integer scaling.
|
|
|
|
|
|
|
|
Changelog:
|
2023-01-21 22:23:33 +11:00
|
|
|
v1.1: Update license; Better defaults; Don't compute alpha.
|
2023-01-15 01:35:38 +11:00
|
|
|
v1.0: Initial release.
|
|
|
|
*/
|
|
|
|
|
|
|
|
// clang-format off
|
2023-01-21 22:23:33 +11:00
|
|
|
#pragma parameter CRT1TAP_SETTINGS "=== CRT-1tap settings ===" 0.0 0.0 1.0 1.0
|
2023-01-15 01:35:38 +11:00
|
|
|
#pragma parameter MIN_THICK "MIN_THICK: Scanline thickness of dark pixels." 0.3 0.0 1.4 0.05
|
|
|
|
#pragma parameter MAX_THICK "MAX_THICK: Scanline thickness of bright pixels." 1.05 0.0 1.4 0.05
|
|
|
|
#pragma parameter V_SHARP "V_SHARP: Vertical sharpness of the scanline" 0.2 0.0 1.0 0.05
|
|
|
|
#pragma parameter H_SHARP "H_SHARP: Horizontal sharpness of pixel transitions." 0.15 0.0 1.0 0.05
|
2023-01-21 22:23:33 +11:00
|
|
|
#pragma parameter SUBPX_POS "SUBPX_POS: Scanline subpixel position." 0.15 -0.5 0.5 0.01
|
2023-01-15 01:35:38 +11:00
|
|
|
#pragma parameter THICK_FALLOFF "THICK_FALLOFF: Reduction of thinner scanlines." 0.65 0.2 2.0 0.05
|
|
|
|
// clang-format on
|
|
|
|
|
|
|
|
layout(push_constant) uniform Push {
|
|
|
|
vec4 OutputSize;
|
|
|
|
vec4 SourceSize;
|
|
|
|
float MIN_THICK;
|
|
|
|
float MAX_THICK;
|
|
|
|
float V_SHARP;
|
|
|
|
float H_SHARP;
|
|
|
|
float SUBPX_POS;
|
|
|
|
float THICK_FALLOFF;
|
|
|
|
}
|
|
|
|
param;
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma stage fragment
|
|
|
|
layout(location = 0) in vec2 vTexCoord;
|
|
|
|
layout(location = 0) out vec4 FragColor;
|
|
|
|
layout(set = 0, binding = 1) uniform sampler2D Source;
|
|
|
|
layout(set = 0, binding = 2) uniform sampler2D Original;
|
|
|
|
|
|
|
|
void main() {
|
|
|
|
float src_x_int;
|
|
|
|
const float src_x_fract =
|
|
|
|
modf(vTexCoord.x * param.SourceSize.x - 0.5f, src_x_int);
|
|
|
|
|
|
|
|
float src_y_int;
|
|
|
|
const float src_y_fract =
|
|
|
|
modf(vTexCoord.y * param.SourceSize.y - param.SUBPX_POS, src_y_int);
|
|
|
|
|
|
|
|
// Function similar to smoothstep and sigmoid.
|
|
|
|
const float s = sign(src_x_fract - 0.5f);
|
|
|
|
const float o = (1.0f + s) * 0.5f;
|
|
|
|
const float src_x =
|
|
|
|
src_x_int + o -
|
|
|
|
0.5f * s *
|
2023-01-21 22:23:33 +11:00
|
|
|
pow(2.0f * (o - s * src_x_fract), mix(1.0f, 6.0f, param.H_SHARP));
|
2023-01-15 01:35:38 +11:00
|
|
|
|
2023-01-21 22:23:33 +11:00
|
|
|
const vec3 signal =
|
2023-01-15 01:35:38 +11:00
|
|
|
texture(Source, vec2((src_x + 0.5f) * param.SourceSize.z,
|
2023-01-21 22:23:33 +11:00
|
|
|
(src_y_int + 0.5f) * param.SourceSize.w))
|
|
|
|
.rgb;
|
2023-01-15 01:35:38 +11:00
|
|
|
|
|
|
|
// Vectorize operations for speed.
|
2023-01-21 22:23:33 +11:00
|
|
|
const float eff_v_sharp = 3.0f + 50.0f * param.V_SHARP * param.V_SHARP;
|
|
|
|
FragColor.rgb =
|
|
|
|
signal *
|
|
|
|
clamp(eff_v_sharp *
|
|
|
|
((pow(mix(param.MIN_THICK.xxx, param.MAX_THICK.xxx, signal),
|
|
|
|
param.THICK_FALLOFF.xxx) *
|
|
|
|
0.5f) -
|
|
|
|
abs(src_y_fract - 0.5f)),
|
|
|
|
0.0f, 1.0f);
|
2023-01-15 01:35:38 +11:00
|
|
|
}
|