-
Notifications
You must be signed in to change notification settings - Fork 0
/
crt.ps
111 lines (85 loc) · 3.91 KB
/
crt.ps
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
#version 450
#extension GL_ARB_shading_language_420pack: enable
/*
zfast_crt_geo - A simple, fast CRT shader.
Copyright (C) 2017 Greg Hogan (SoltanGris42)
Copyright (C) 2023 Jose Linares (Dogway)
This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.
Notes: This shader does scaling with a weighted linear filter
based on the algorithm by I�igo Quilez here:
https://iquilezles.org/articles/texture/
but modified to be somewhat sharper. Then a scanline effect that varies
based on pixel brightness is applied along with a monochrome aperture mask.
This shader runs at ~60fps on the Chromecast HD (10GFlops) on a 1080p display.
(https://forums.libretro.com/t/android-googletv-compatible-shaders-nitpicky)
Dogway: I modified zfast_crt.glsl shader to include screen curvature,
vignetting, round corners and phosphor*temperature. Horizontal pixel is left out
from the Quilez' algo (read above) to provide a more S-Video like horizontal blur.
The scanlines and mask are also now performed in the recommended linear light.
For this to run smoothly on GPU deprived platforms like the Chromecast and
older consoles, I had to remove several parameters and hardcode them into the shader.
Another POV is to run the shader on handhelds like the Switch or SteamDeck so they consume less battery.
*/
// Input variables
layout(location = 0) noperspective in vec2 ss_uv;
layout(binding = 0) uniform sampler2D tex_renderedMap;
layout(location = 0) out vec4 out_pixel0;
layout(binding = 0) uniform uf_data {
float uf_time;
};
// Hardcoded parameters
const float SCANLINE_WEIGHT = 6.5;
const float MASK_DARK = 0.7;
const float MSCL = 0.5; // Assuming 1080p as a standard resolution for simplicity
const vec3 pwr = vec3(1.0/((-0.0325*SCANLINE_WEIGHT+1.0)*(-0.311*MASK_DARK+1.0))-1.2);
const mat3 P22D93 = mat3(
1.00000, 0.00000, -0.06173,
0.07111, 0.96887, -0.01136,
0.00000, 0.08197, 1.07280
);
vec3 inv_gamma(vec3 col, vec3 power) {
vec3 cir = col-1.0;
cir *= cir;
col = mix(sqrt(col), sqrt(1.0-cir), power);
return col;
}
vec2 Warp(vec2 pos) {
pos = pos*2.0-1.0;
pos *= vec2(1.0 + (pos.y*pos.y)*0.0276, 1.0 + (pos.x*pos.x)*0.0414);
return pos*0.5 + 0.5;
}
void main() {
vec2 InputSize = vec2(640.0f, 360.0f);
vec2 TextureSize = vec2(640.0f, 360.0f);
vec2 OutputSize = vec2(1920.0f, 1080.0f);
vec2 vTexCoord = ss_uv;
vec2 scale = vec2(TextureSize.xy/InputSize.xy);
vec2 vpos = vTexCoord*scale;
vec2 xy = Warp(vpos);
vec2 corn = min(xy,1.0-xy); // This is used to mask the rounded
corn.x = 0.0001/corn.x; // corners later on
xy /= scale;
vpos *= (1.0 - vpos.xy);
float vig = vpos.x * vpos.y * 46.0;
vig = min(sqrt(vig), 1.0);
// Of all the pixels that are mapped onto the texel we are
// currently rendering, which pixel are we currently rendering?
float ratio_scale = xy.y * TextureSize.y - 0.5;
// Snap to the center of the underlying texel.
float i = floor(ratio_scale) + 0.5;
// This is just like "Quilez Scaling" but sharper
float f = ratio_scale - i;
float Y = f*f;
float p = (i + 4.0*Y*f)*(1.0f/TextureSize.y);
float whichmask = floor(ss_uv.x*scale.x*OutputSize.x)*-MSCL;
float mask = 1.0 + float(fract(whichmask) < MSCL) *-MASK_DARK;
vec3 colour = texture(tex_renderedMap, vec2(xy.x, p)).rgb;
colour = max((colour*colour) * (P22D93 * vig), 0.0);
float scanLineWeight = (1.5 - SCANLINE_WEIGHT*(Y - Y*Y));
if (corn.y <= corn.x || corn.x < 0.0001)
colour = vec3(0.0);
out_pixel0.rgba = vec4(inv_gamma(colour.rgb*mix(scanLineWeight*mask, 1.0, colour.r*0.26667+colour.g*0.26667+colour.b*0.26667), pwr), 1.0);
}