Last active
August 2, 2019 04:06
-
-
Save hizzlekizzle/1f7a8e18eb08528b64e8a6540baa66ca to your computer and use it in GitHub Desktop.
Moire mitigation shader code
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
#define moire_mitigation_factor 64.0 | |
#define warpX 0.031 | |
#define warpY 0.041 | |
// Convert from linear to sRGB. | |
//float Srgb(float c){return(c<0.0031308?c*12.92:1.055*pow(c,0.41666)-0.055);} | |
vec4 Srgb(vec4 c){return pow(c, vec4(1.0 / 2.2));} | |
// Convert from sRGB to linear. | |
//float Linear(float c){return(c<=0.04045)?c/12.92:pow((c+0.055)/1.055,2.4);} | |
float Linear(float c){return pow(c, 2.2);} | |
// | |
// Semi-Poor Quality Temporal Noise | |
// | |
// Base. | |
// Ripped ad modified from: https://www.shadertoy.com/view/4djSRW | |
float Noise(vec2 p,float x){p+=x; | |
vec3 p3=fract(vec3(p.xyx)*10.1031); | |
p3+=dot(p3,p3.yzx+19.19); | |
return (fract((p3.x+p3.y)*p3.z)*2.0-1.0) / moire_mitigation_factor;} | |
// Step 1 in generation of the dither source texture. | |
float Noise1(vec2 uv,float n){ | |
float a=1.0,b=2.0,c=-12.0,t=1.0; | |
return (1.0/max(a*4.0+b*4.0,-c))*( | |
Noise(uv+vec2(-1.0,-1.0)*t,n)*a+ | |
Noise(uv+vec2( 0.0,-1.0)*t,n)*b+ | |
Noise(uv+vec2( 1.0,-1.0)*t,n)*a+ | |
Noise(uv+vec2(-1.0, 0.0)*t,n)*b+ | |
Noise(uv+vec2( 0.0, 0.0)*t,n)*c+ | |
Noise(uv+vec2( 1.0, 0.0)*t,n)*b+ | |
Noise(uv+vec2(-1.0, 1.0)*t,n)*a+ | |
Noise(uv+vec2( 0.0, 1.0)*t,n)*b+ | |
Noise(uv+vec2( 1.0, 1.0)*t,n)*a+ | |
0.0);} | |
// Step 2 in generation of the dither source texture. | |
float Noise2(vec2 uv,float n){ | |
float a=1.0,b=2.0,c=-2.0,t=1.0; | |
return (1.0/(a*4.0+b*4.0))*( | |
Noise1(uv+vec2(-1.0,-1.0)*t,n)*a+ | |
Noise1(uv+vec2( 0.0,-1.0)*t,n)*b+ | |
Noise1(uv+vec2( 1.0,-1.0)*t,n)*a+ | |
Noise1(uv+vec2(-1.0, 0.0)*t,n)*b+ | |
Noise1(uv+vec2( 0.0, 0.0)*t,n)*c+ | |
Noise1(uv+vec2( 1.0, 0.0)*t,n)*b+ | |
Noise1(uv+vec2(-1.0, 1.0)*t,n)*a+ | |
Noise1(uv+vec2( 0.0, 1.0)*t,n)*b+ | |
Noise1(uv+vec2( 1.0, 1.0)*t,n)*a+ | |
0.0);} | |
// Compute temporal dither from integer pixel position uv. | |
float Noise3(vec2 uv){return Noise2(uv,fract(iTime));} | |
// Energy preserving dither, for {int pixel pos,color,amount}. | |
vec2 Noise4(vec2 uv,vec2 c,float a){ | |
// Grain value {-1 to 1}. | |
vec2 g=vec2(Noise3(uv)*2.0); | |
// Step size for black in non-linear space. | |
float rcpStep=1.0/(256.0-1.0); | |
// Estimate amount negative which still quantizes to zero. | |
vec2 black=vec2(0.5*Linear(rcpStep)); | |
// Estimate amount above 1.0 which still quantizes to 1.0. | |
vec2 white=vec2(2.0-Linear(1.0-rcpStep)); | |
// Add grain. | |
return vec2(clamp(c+g*min(c+black,min(white-c,a)),0.0,1.0));} | |
// | |
// Pattern | |
// | |
// 4xMSAA pattern for quad given integer coordinates. | |
// | |
// . x . . | < pixel | |
// . . . x | | |
// x . . . | |
// . . x . | |
// | |
// 01 | |
// 23 | |
// | |
vec2 Quad4(vec2 pp){ | |
int q=(int(pp.x)&1)+((int(pp.y)&1)<<1); | |
if(q==0)return pp+vec2( 0.25,-0.25); | |
if(q==1)return pp+vec2( 0.25, 0.25); | |
if(q==2)return pp+vec2(-0.25,-0.25); | |
return pp+vec2(-0.25, 0.25);} | |
// Rotate {0.0,r} by a {-1.0 to 1.0}. | |
vec2 Rot(float r,float a){return vec2(r*cos(a*3.14159),r*sin(a*3.14159));} | |
// | |
// POOR QUALITY JITTERED | |
// | |
// Jittered position. | |
vec2 Jit(vec2 pp){ | |
// Start with better baseline pattern. | |
pp=Quad4(pp); | |
// Very poor quality (clumping) move in disc around pixel. | |
float n=Noise(pp,fract(iTime)); | |
float m=Noise(pp,fract(iTime*0.333))*0.5+0.5; | |
m = sqrt(m) / 4.0; | |
return pp+Rot(0.707*0.5*m,n);} | |
// | |
// POOR QUALITY JITTERED 4x | |
// | |
// Gaussian filtered jittered tap. | |
void JitGaus4(inout vec2 sumC,inout vec2 sumW,vec2 pp,vec2 mm){ | |
vec2 jj=Jit(pp); | |
vec2 c=jj; | |
vec2 vv=mm-jj; | |
float w=exp2(-1.0*dot(vv,vv)); | |
sumC+=c*vec2(w); sumW+=vec2(w);} | |
// Many tap gaussian from poor quality jittered 4/sample per pixel | |
// | |
// . x x x . | |
// x x x x x | |
// x x x x x | |
// x x x x x | |
// . x x x . | |
// | |
vec2 ResolveJitGaus4(vec2 pp){ | |
vec2 ppp=(pp); | |
vec2 sumC=vec2(0.0); | |
vec2 sumW=vec2(0.0); | |
JitGaus4(sumC,sumW,ppp+vec2(-1.0,-2.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 0.0,-2.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 1.0,-2.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2(-2.0,-1.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2(-1.0,-1.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 0.0,-1.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 1.0,-1.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 2.0,-1.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2(-2.0, 0.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2(-1.0, 0.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 0.0, 0.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 1.0, 0.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 2.0, 0.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2(-2.0, 1.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2(-1.0, 1.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 0.0, 1.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 1.0, 1.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 2.0, 1.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2(-1.0, 2.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 0.0, 2.0),pp); | |
JitGaus4(sumC,sumW,ppp+vec2( 1.0, 2.0),pp); | |
return sumC/sumW;} | |
vec2 moire_resolve(vec2 coord){ | |
vec2 pp = coord; | |
vec2 cc = vec2(0.0, 0.0); | |
cc = ResolveJitGaus4(pp); | |
cc = Noise4(pp, cc, 1.0 / 32.0); | |
cc = cc + vec2(0.0105, 0.015); | |
return cc; | |
} | |
// Distortion of scanlines, and end of screen alpha. | |
vec2 Warp(vec2 pos) | |
{ | |
pos = pos*2.0-1.0; | |
pos *= vec2(1.0 + (pos.y*pos.y)*warpX, 1.0 + (pos.x*pos.x)*warpY); | |
return pos*0.5 + 0.5; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment