Created
September 1, 2021 05:10
-
-
Save blackle/bb2e5cbaaf863942e177016de2e89620 to your computer and use it in GitHub Desktop.
Scanline Filter for ShaderFilter Plus Raw
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // PUBLIC DOMAIN CRT STYLED SCAN-LINE SHADER | |
| // | |
| // by Timothy Lottes | |
| // | |
| // This is more along the style of a really good CGA arcade monitor. | |
| // With RGB inputs instead of NTSC. | |
| // The shadow mask example has the mask rotated 90 degrees for less chromatic aberration. | |
| // | |
| // Left it unoptimized to show the theory behind the algorithm. | |
| // | |
| // It is an example what I personally would want as a display option for pixel art games. | |
| // Please take and use, change, or whatever. | |
| // | |
| //https://www.shadertoy.com/view/XsjSzR ported to ShaderFilter plus by Blackle Mori | |
| #pragma shaderfilter set fade__description Fade | |
| #pragma shaderfilter set fade__default 0.5 | |
| #pragma shaderfilter set fade__min 0.0 | |
| #pragma shaderfilter set fade__max 1.0 | |
| #pragma shaderfilter set fade__step 0.01 | |
| #pragma shaderfilter set fade__slider true | |
| uniform float fade; | |
| #pragma shaderfilter set scale__description Scale | |
| #pragma shaderfilter set scale__default 1.0 | |
| #pragma shaderfilter set scale__min 0.1 | |
| #pragma shaderfilter set scale__max 2.0 | |
| #pragma shaderfilter set scale__step 0.01 | |
| #pragma shaderfilter set scale__slider true | |
| uniform float scale; | |
| #pragma shaderfilter set hardScan__description Intensity of Scanlines | |
| #pragma shaderfilter set hardScan__default -10.0 | |
| #pragma shaderfilter set hardScan__min -24.0 | |
| #pragma shaderfilter set hardScan__max -4.0 | |
| #pragma shaderfilter set hardScan__step 0.1 | |
| #pragma shaderfilter set hardScan__slider true | |
| uniform float hardScan; | |
| #pragma shaderfilter set hardPix__description Hardness of pixels | |
| #pragma shaderfilter set hardPix__default -3.0 | |
| #pragma shaderfilter set hardPix__min -6.0 | |
| #pragma shaderfilter set hardPix__max -1.0 | |
| #pragma shaderfilter set hardPix__step 0.1 | |
| #pragma shaderfilter set hardPix__slider true | |
| uniform float hardPix; | |
| #pragma shaderfilter set warp_x__description Warp X | |
| #pragma shaderfilter set warp_x__default 0.03 | |
| #pragma shaderfilter set warp_x__min 0.0 | |
| #pragma shaderfilter set warp_x__max 0.1 | |
| #pragma shaderfilter set warp_x__step 0.001 | |
| #pragma shaderfilter set warp_x__slider true | |
| uniform float warp_x; | |
| #pragma shaderfilter set warp_y__description Warp Y | |
| #pragma shaderfilter set warp_y__default 0.04 | |
| #pragma shaderfilter set warp_y__min 0.0 | |
| #pragma shaderfilter set warp_y__max 0.1 | |
| #pragma shaderfilter set warp_y__step 0.001 | |
| #pragma shaderfilter set warp_y__slider true | |
| uniform float warp_y; | |
| // Hardness of scanline. | |
| // -8.0 = soft | |
| // -16.0 = medium | |
| // #define hardScan -16.0 | |
| // Hardness of pixels in scanline. | |
| // -2.0 = soft | |
| // -4.0 = hard | |
| // #define hardPix -4.0 | |
| // Amount of shadow mask. | |
| #define maskDark 0.5 | |
| #define maskLight 1.5 | |
| //------------------------------------------------------------------------ | |
| // sRGB to Linear. | |
| // Assuing using sRGB typed textures this should not be needed. | |
| float ToLinear1(float c){return(c<=0.04045)?c/12.92:pow((c+0.055)/1.055,2.4);} | |
| float3 ToLinear(float3 c){return float3(ToLinear1(c.r),ToLinear1(c.g),ToLinear1(c.b));} | |
| // Linear to sRGB. | |
| // Assuing using sRGB typed textures this should not be needed. | |
| float ToSrgb1(float c){return(c<0.0031308?c*12.92:1.055*pow(c,0.41666)-0.055);} | |
| float3 ToSrgb(float3 c){return float3(ToSrgb1(c.r),ToSrgb1(c.g),ToSrgb1(c.b));} | |
| // Nearest emulated sample given floating point position and texel offset. | |
| // Also zero's off screen. | |
| float3 Fetch(float2 pos,float2 off){ | |
| pos=round(pos/scale*builtin_uv_size/6.0+off)*scale/builtin_uv_size*6.0; | |
| if(max(abs(pos.x-0.5),abs(pos.y-0.5))>0.5)return float3(0.0,0.0,0.0); | |
| return ToLinear(( | |
| image.Sample(builtin_texture_sampler,pos).rgb | |
| +image.Sample(builtin_texture_sampler,pos+float2(0.0,0.5)/builtin_uv_size*scale*6.0).rgb | |
| +image.Sample(builtin_texture_sampler,pos-float2(0.0,0.5)/builtin_uv_size*scale*6.0).rgb)/3.0);} | |
| // Distance in emulated pixels to nearest texel. | |
| float2 Dist(float2 pos){pos=pos/scale*builtin_uv_size/6.0;return -((pos-round(pos)));} | |
| // 1D Gaussian. | |
| float Gaus(float pos,float scale){return exp2(scale*pos*pos);} | |
| // 3-tap Gaussian filter along horz line. | |
| float3 Horz3(float2 pos,float off){ | |
| float3 b=Fetch(pos,float2(-1.0,off)); | |
| float3 c=Fetch(pos,float2( 0.0,off)); | |
| float3 d=Fetch(pos,float2( 1.0,off)); | |
| float dst=Dist(pos).x; | |
| // Convert distance to weight. | |
| float scale=hardPix; | |
| float wb=Gaus(dst-1.0,scale); | |
| float wc=Gaus(dst+0.0,scale); | |
| float wd=Gaus(dst+1.0,scale); | |
| // Return filtered sample. | |
| return (b*wb+c*wc+d*wd)/(wb+wc+wd);} | |
| // 5-tap Gaussian filter along horz line. | |
| float3 Horz5(float2 pos,float off){ | |
| float3 a=Fetch(pos,float2(-2.0,off)); | |
| float3 b=Fetch(pos,float2(-1.0,off)); | |
| float3 c=Fetch(pos,float2( 0.0,off)); | |
| float3 d=Fetch(pos,float2( 1.0,off)); | |
| float3 e=Fetch(pos,float2( 2.0,off)); | |
| float dst=Dist(pos).x; | |
| // Convert distance to weight. | |
| float scale=hardPix; | |
| float wa=Gaus(dst-2.0,scale); | |
| float wb=Gaus(dst-1.0,scale); | |
| float wc=Gaus(dst+0.0,scale); | |
| float wd=Gaus(dst+1.0,scale); | |
| float we=Gaus(dst+2.0,scale); | |
| // Return filtered sample. | |
| return (a*wa+b*wb+c*wc+d*wd+e*we)/(wa+wb+wc+wd+we); | |
| } | |
| // Return scanline weight. | |
| float Scan(float2 pos,float off){ | |
| float dst=Dist(pos).y; | |
| return Gaus(dst+off,hardScan);} | |
| // Allow nearest three lines to effect pixel. | |
| float3 Tri(float2 pos){ | |
| float3 a=Horz3(pos,-1.0); | |
| float3 b=Horz5(pos, 0.0); | |
| float3 c=Horz3(pos, 1.0); | |
| float wa=Scan(pos,-1.0); | |
| float wb=Scan(pos, 0.0); | |
| float wc=Scan(pos, 1.0); | |
| return a*wa+b*wb+c*wc;} | |
| // Shadow mask. | |
| float3 Mask(float2 pos){ | |
| pos.x+=pos.y*3.0; | |
| float3 mask=float3(maskDark,maskDark,maskDark); | |
| pos.x=frac(pos.x/6.0); | |
| pos = round(pos*builtin_uv_size*scale)/builtin_uv_size/scale; | |
| if(pos.x<0.333)mask.r=maskLight; | |
| else if(pos.x<0.666)mask.g=maskLight; | |
| else mask.b=maskLight; | |
| return mask;} | |
| float2 Warp(float2 pos){ | |
| pos=pos*2.0-1.0; | |
| pos*=float2(1.0+(pos.y*pos.y)*warp_x,1.0+(pos.x*pos.x)*warp_y); | |
| return pos*0.5+0.5;} | |
| // Draw dividing bars. | |
| float Bar(float pos,float bar){pos-=bar;return pos*pos<4.0?0.0:1.0;} | |
| float4 render(float2 uv) { | |
| uv = Warp(uv); | |
| float3 col = image.Sample(builtin_texture_sampler, uv).rgb; | |
| return float4(lerp(col, ToSrgb(Tri(uv)*Mask(uv*builtin_uv_size)), fade), 1); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment