Godot Version
v4.2.stable
Question
I have the following shader:
shader_type canvas_item;
uniform sampler2D SCREEN_TEXTURE : hint_screen_texture, filter_linear_mipmap;
uniform float SCREEN_CURVE_RADIUS = 5;
uniform float SCREEN_CORNER_RADIUS = 0.1;
uniform float BRIGHTNESS = 1.5;
uniform float PIXEL_SHARPNESS = 2.0;
uniform float LINE_SHARPNESS = 6.0;
uniform float MASK_STRENGTH = 0.15;
uniform bool CURVE_SCREEN = true;
uniform bool SCANLINES = true;
uniform bool SHADOW_MASK = true;
uniform bool LIGHT_EFFECTS = true;
uniform float TILES = 2.0;
//const vec2 IRES = vec2(16, 9) * 60.0;
uniform float RESOLUTION = 50;
const vec2 IRES = vec2(16, 9);
#define TARGET_RES (IRES * RESOLUTION * TILES)
vec3 ACESFilm(vec3 x) {
return clamp((x*(2.51*x + 0.03)) / (x*(2.43*x + 0.59) + 0.14), 0.0, 1.0);
}
vec2 curveScreen(vec2 uv) {
float r = 3.14159265 * 0.5 / SCREEN_CURVE_RADIUS;
float d = 1.0 - cos(uv.x * r) * cos(uv.y * r); // distance to screen
float s = cos(r); // scale factor to re-fit window
return uv / (1.0 - d) * s;
}
float discardCorners(vec2 pos) {
pos = abs(pos);
pos.x = pos.x * 1.333 - 0.333; // 4:3 aspect ratio correction
if (min(pos.x, pos.y) < 1.0 - SCREEN_CORNER_RADIUS) return 1.0; // not near corner -- break early
float d = distance(pos, vec2(1.0 - SCREEN_CORNER_RADIUS));
return float(d < SCREEN_CORNER_RADIUS);
}
vec3 getSample(vec2 pos, vec2 off) {
//get nearest emulated sample
pos = floor(pos * TARGET_RES) + vec2(0.5) + off;
vec3 col = vec3(0.0);
if (pos.x >= 0.0 && pos.x <= TARGET_RES.x * 2.0 && pos.y >= 0.0 && pos.y <= TARGET_RES.y) {
col = texelFetch(SCREEN_TEXTURE, ivec2(pos), 0).rgb;
col = pow(((col + 0.055) / 1.055), vec3(2.4)); // SRGB => linear
}
return col;
}
vec3 getScanline(vec2 pos, float off) {
// 3-tap gaussian filter to get colour at arbitrary point along scanline
float d = 0.5 - fract(pos.x * TARGET_RES.x);
vec3 ca = getSample(pos, vec2(-1.0, off));
vec3 cb = getSample(pos, vec2(0.0, off));
vec3 cc = getSample(pos, vec2(1.0, off));
float wa = gaussian(d - 1.0, PIXEL_SHARPNESS);
float wb = gaussian(d, PIXEL_SHARPNESS);
float wc = gaussian(d + 1.0, PIXEL_SHARPNESS);
return (ca * wa + cb * wb + cc * wc) / (wa + wb + wc);
}
vec3 getScreenColour(vec2 pos) {
// Get influence of 3 nearest scanlines
float d = 0.5 - fract(pos.y * TARGET_RES.y);
vec3 ca = getScanline(pos, -1.0);
vec3 cb = getScanline(pos, 0.0);
vec3 cc = getScanline(pos, 1.0);
float wa = gaussian(d - 1.0, LINE_SHARPNESS);
float wb = gaussian(d, LINE_SHARPNESS);
float wc = gaussian(d + 1.0, LINE_SHARPNESS);
return (ca * wa + cb * wb + cc * wc);
}
vec3 SlotMask_PixelPerfect(vec2 pos, float resolution_y) {
//pos /= 1.0 + floor( resolution_y / 1440.0 );
pos /= 1.0 + floor(resolution_y / (IRES.y * RESOLUTION * 15.0));
float glow = 0.5;
float f = mod(pos.x, 3.0);
vec3 col = vec3(float(f <= 1.0), float(f > 1.0 && f <= 2.0), float(f > 2.0));
col += vec3(float(f < 1.5 || f >= 2.5), float(f > 0.5 && f <= 2.5), float(f > 1.5 || f <= 0.5)) * glow;
col *= (mod(pos.y + (fract(pos.x / 6.0) > 0.5 ? 1.5 : 0.0), 3.0) < 1.0) ? glow : 1.0;
col /= 1.0 + glow;
return col;
}
void fragment() {
//vec2 uv = FRAGCOORD.xy / (1.0 / SCREEN_PIXEL_SIZE).xy;
vec2 uv = FRAGCOORD.xy / TARGET_RES;
vec2 pos = uv;
pos = pos * 2.0 - 1.0;
//pos.x *= (1.0 / SCREEN_PIXEL_SIZE).x/(1.0 / SCREEN_PIXEL_SIZE).y*(IRES.y/IRES.x);
pos.x *= SCREEN_PIXEL_SIZE.y / SCREEN_PIXEL_SIZE.x * (IRES.y / IRES.x);
if (CURVE_SCREEN) pos = curveScreen(pos);
if (max(abs(pos.x), abs(pos.y)) < 1.0) {
// skip everything if we're beyond the screen edge
vec3 col = vec3(1.0);
if (CURVE_SCREEN) col *= discardCorners(pos);
if (LIGHT_EFFECTS) col *= 1.0 - sqrt(length(pos) * 0.25); // vignette
pos = pos * 0.5 + 0.5;
if (SCANLINES) col *= getScreenColour(pos);
else col *= getSample(pos, vec2(0.0));
if (SHADOW_MASK) {
vec3 shadowmask = SlotMask_PixelPerfect(FRAGCOORD.xy, (1.0 / SCREEN_PIXEL_SIZE).y);
col *= mix(vec3(1.0 - MASK_STRENGTH), vec3(1.0 + MASK_STRENGTH), shadowmask);
}
if (LIGHT_EFFECTS) {
col *= BRIGHTNESS;
col = ACESFilm(col);
}
col = pow(col, vec3(1.0 / 2.4)) * 1.055 - 0.055; // linear => SRGB
COLOR = vec4(col, 1.0);
}
}
What I’m hoping is that by changing the resolution, as the name implies, I will change how clear the “virtual monitor” looks. But what happens instead is that the shader will zoom in or out of the upper right corner of the viewport, instead of showing whatever is behind the ColorRect but just with a different resolution.
Has anyone got any idea as to why?