Update subpixel_masks.h

fix broken yellow pixel(!) and add early returns (might speed things up slightly, dunno). Also add an explanatory comment at the top, add a 0 value for passthru/no mask and a sanity check that returns a passthru/no mask for any unexpected value.
This commit is contained in:
hizzlekizzle 2020-04-03 13:30:09 -05:00 committed by GitHub
parent 1335068b05
commit e54bbbb7e3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -1,22 +1,54 @@
/*
A collection of CRT mask effects that work with LCD subpixel structures for
small details
author: hunterk
license: public domain
How to use it:
Multiply your image by the vec3 output:
FragColor.rgb *= mask_weights(gl_FragCoord.xy, 1.0, 1);
The function needs to be tiled across the screen using the physical pixels, e.g.
gl_FragCoord (the "vec2 coord" input). In the case of slang shaders, we use
(vTexCoord.st * OutputSize.xy).
The "mask_intensity" (float value between 0.0 and 1.0) is how strong the mask
effect should be. Full-strength red, green and blue subpixels on a white pixel
are the ideal, and are achieved with an intensity of 1.0, though this darkens
the image significantly and may not always be desirable.
The "phosphor_layout" (int value between 0 and 19) determines which phophor
layout to apply. 0 is no mask/passthru.
Many of these mask arrays are adapted from cgwg's crt-geom-deluxe LUTs, and
those have their filenames included for easy identification
*/
vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
vec3 weights = vec3(1.,1.,1.); vec3 weights = vec3(1.,1.,1.);
float intens = 1.; float on = 1.;
float inv = 1.-mask_intensity; float off = 1.-mask_intensity;
vec3 green = vec3(inv, intens, inv); vec3 red = vec3(on, off, off);
vec3 magenta = vec3(intens,inv,intens); vec3 green = vec3(off, on, off);
vec3 black = vec3(inv,inv,inv); vec3 blue = vec3(off, off, on );
vec3 red = vec3(intens,inv,inv); vec3 magenta = vec3(on, off, on );
vec3 yellow = vec3(intens,inv,intens); vec3 yellow = vec3(on, on, off);
vec3 cyan = vec3(inv,intens,intens); vec3 cyan = vec3(off, on, on );
vec3 blue = vec3(inv,inv,intens); vec3 black = vec3(off, off, off);
int w, z = 0; int w, z = 0;
// This pattern is used by a few layouts, so we'll define it here
vec3 aperture_weights = mix(magenta, green, floor(mod(coord.x, 2.0))); vec3 aperture_weights = mix(magenta, green, floor(mod(coord.x, 2.0)));
if(phosphor_layout == 0) return weights;
if(phosphor_layout == 1){ else if(phosphor_layout == 1){
// classic aperture for RGB panels; good for 1080p, too small for 4K+ // classic aperture for RGB panels; good for 1080p, too small for 4K+
// aka aperture_1_2_bgr // aka aperture_1_2_bgr
weights = aperture_weights; weights = aperture_weights;
return weights;
} }
else if(phosphor_layout == 2){ else if(phosphor_layout == 2){
@ -24,6 +56,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
// aka delta_1_2x1_bgr // aka delta_1_2x1_bgr
vec3 inverse_aperture = mix(green, magenta, floor(mod(coord.x, 2.0))); vec3 inverse_aperture = mix(green, magenta, floor(mod(coord.x, 2.0)));
weights = mix(aperture_weights, inverse_aperture, floor(mod(coord.y, 2.0))); weights = mix(aperture_weights, inverse_aperture, floor(mod(coord.y, 2.0)));
return weights;
} }
else if(phosphor_layout == 3){ else if(phosphor_layout == 3){
@ -42,17 +75,20 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
// use the indexes to find which color to apply to the current pixel // use the indexes to find which color to apply to the current pixel
weights = slotmask[w][z]; weights = slotmask[w][z];
return weights;
} }
if(phosphor_layout == 4){ else if(phosphor_layout == 4){
// classic aperture for RBG panels; good for 1080p, too small for 4K+ // classic aperture for RBG panels; good for 1080p, too small for 4K+
weights = mix(yellow, blue, floor(mod(coord.x, 2.0))); weights = mix(yellow, blue, floor(mod(coord.x, 2.0)));
return weights;
} }
else if(phosphor_layout == 5){ else if(phosphor_layout == 5){
// 2x2 shadow mask for RBG panels; good for 1080p, too small for 4K+ // 2x2 shadow mask for RBG panels; good for 1080p, too small for 4K+
vec3 inverse_aperture = mix(blue, yellow, floor(mod(coord.x, 2.0))); vec3 inverse_aperture = mix(blue, yellow, floor(mod(coord.x, 2.0)));
weights = mix(mix(yellow, blue, floor(mod(coord.x, 2.0))), inverse_aperture, floor(mod(coord.y, 2.0))); weights = mix(mix(yellow, blue, floor(mod(coord.x, 2.0))), inverse_aperture, floor(mod(coord.y, 2.0)));
return weights;
} }
else if(phosphor_layout == 6){ else if(phosphor_layout == 6){
@ -62,6 +98,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
z = int(floor(mod(coord.x, 4.0))); z = int(floor(mod(coord.x, 4.0)));
weights = ap4[z]; weights = ap4[z];
return weights;
} }
else if(phosphor_layout == 7){ else if(phosphor_layout == 7){
@ -71,6 +108,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
z = int(floor(mod(coord.x, 5.0))); z = int(floor(mod(coord.x, 5.0)));
weights = ap3[z]; weights = ap3[z];
return weights;
} }
else if(phosphor_layout == 8){ else if(phosphor_layout == 8){
@ -81,6 +119,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
w = int(floor(mod(coord.x, 7.))); w = int(floor(mod(coord.x, 7.)));
weights = big_ap[w]; weights = big_ap[w];
return weights;
} }
else if(phosphor_layout == 9){ else if(phosphor_layout == 9){
@ -92,6 +131,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
w = int(floor(mod(coord.x, 4.))); w = int(floor(mod(coord.x, 4.)));
weights = big_ap_rgb[w]; weights = big_ap_rgb[w];
return weights;
} }
else if(phosphor_layout == 10){ else if(phosphor_layout == 10){
@ -102,6 +142,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
w = int(floor(mod(coord.x, 4.))); w = int(floor(mod(coord.x, 4.)));
weights = big_ap_rbg[w]; weights = big_ap_rbg[w];
return weights;
} }
else if(phosphor_layout == 11){ else if(phosphor_layout == 11){
@ -115,6 +156,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
z = int(floor(mod(coord.x, 4.0))); z = int(floor(mod(coord.x, 4.0)));
weights = delta1[w][z]; weights = delta1[w][z];
return weights;
} }
else if(phosphor_layout == 12){ else if(phosphor_layout == 12){
@ -128,6 +170,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
z = int(floor(mod(coord.x, 4.0))); z = int(floor(mod(coord.x, 4.0)));
weights = delta[w][z]; weights = delta[w][z];
return weights;
} }
else if(phosphor_layout == 13){ else if(phosphor_layout == 13){
@ -143,6 +186,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
z = int(floor(mod(coord.x, 4.0))); z = int(floor(mod(coord.x, 4.0)));
weights = delta[w][z]; weights = delta[w][z];
return weights;
} }
else if(phosphor_layout == 14){ else if(phosphor_layout == 14){
@ -153,14 +197,12 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
{black, black, black, magenta, green, black} {black, black, black, magenta, green, black}
}; };
// find the vertical index
w = int(floor(mod(coord.y, 3.0))); w = int(floor(mod(coord.y, 3.0)));
// find the horizontal index
z = int(floor(mod(coord.x, 6.0))); z = int(floor(mod(coord.x, 6.0)));
// use the indexes to find which color to apply to the current pixel
weights = slotmask[w][z]; weights = slotmask[w][z];
return weights;
} }
else if(phosphor_layout == 15){ else if(phosphor_layout == 15){
@ -176,6 +218,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
z = int(floor(mod(coord.x, 8.0))); z = int(floor(mod(coord.x, 8.0)));
weights = slot2[w][z]; weights = slot2[w][z];
return weights;
} }
else if(phosphor_layout == 16){ else if(phosphor_layout == 16){
@ -186,14 +229,12 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
{black, black, yellow, blue} {black, black, yellow, blue}
}; };
// find the vertical index
w = int(floor(mod(coord.y, 3.0))); w = int(floor(mod(coord.y, 3.0)));
// find the horizontal index
z = int(floor(mod(coord.x, 4.0))); z = int(floor(mod(coord.x, 4.0)));
// use the indexes to find which color to apply to the current pixel
weights = slotmask[w][z]; weights = slotmask[w][z];
return weights;
} }
else if(phosphor_layout == 17){ else if(phosphor_layout == 17){
@ -209,6 +250,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
z = int(floor(mod(coord.x, 10.0))); z = int(floor(mod(coord.x, 10.0)));
weights = slot2[w][z]; weights = slot2[w][z];
return weights;
} }
else if(phosphor_layout == 18){ else if(phosphor_layout == 18){
@ -224,6 +266,7 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
z = int(floor(mod(coord.x, 10.0))); z = int(floor(mod(coord.x, 10.0)));
weights = slot2[w][z]; weights = slot2[w][z];
return weights;
} }
else if(phosphor_layout == 19){ else if(phosphor_layout == 19){
@ -241,7 +284,8 @@ vec3 mask_weights(vec2 coord, float mask_intensity, int phosphor_layout){
z = int(floor(mod(coord.x, 14.0))); z = int(floor(mod(coord.x, 14.0)));
weights = slot[w][z]; weights = slot[w][z];
return weights;
} }
return weights; else return weights;
} }