Uses PRNG calls instead of texture fetches, so it tends to look more harsh and have patterning issues depending on the GPU.
54 lines
1.3 KiB
GLSL
54 lines
1.3 KiB
GLSL
/*
|
|
Complex grain shader ported over from MariENB
|
|
This is a simplified version that uses three PRNG calls
|
|
(C)2012-2022 Marisa the Magician
|
|
*/
|
|
#define overlay(a,b) (a<0.5)?(2.0*a*b):(1.0-(2.0*(1.0-a)*(1.0-b)))
|
|
#define darkmask(a,b) (a>0.5)?(2.0*a*(0.5+b)):(1.0-2.0*(1.0-a)*(1.0-((0.5+b))))
|
|
|
|
// simplified PRNG, for performance
|
|
float rnd( in vec2 sd )
|
|
{
|
|
return fract(sin(dot(sd,vec2(12.9898,78.233)))*43758.5453);
|
|
}
|
|
|
|
vec3 grain( in vec3 res, in vec2 coord )
|
|
{
|
|
float ts = Timer;
|
|
vec2 s1 = coord+vec2(0.,ts);
|
|
vec2 s2 = coord+vec2(ts,0.);
|
|
vec2 s3 = coord+vec2(ts,ts);
|
|
float n1 = rnd(s1);
|
|
float n2 = rnd(s2);
|
|
float n3 = rnd(s3);
|
|
float n4 = (n1+n2+n3)/3.;
|
|
vec3 ng = vec3(n4);
|
|
vec3 nc = vec3(n1,n2,n3);
|
|
vec3 nt = pow(clamp(mix(ng,nc,ns),.0,1.),vec3(np));
|
|
if ( nb == 1 ) res.rgb += nt*ni;
|
|
else if ( nb == 2 )
|
|
{
|
|
res.r = overlay(res.r,(nt.r*ni));
|
|
res.g = overlay(res.g,(nt.g*ni));
|
|
res.b = overlay(res.b,(nt.b*ni));
|
|
}
|
|
else if ( nb == 3 )
|
|
{
|
|
float bn = 1.-clamp((res.r+res.g+res.b)/3.,0.,1.);
|
|
bn = pow(bn,bnp);
|
|
vec3 nn = clamp(nt*bn,vec3(0.),vec3(1.));
|
|
res.r = darkmask(res.r,(nn.r*ni));
|
|
res.g = darkmask(res.g,(nn.g*ni));
|
|
res.b = darkmask(res.b,(nn.b*ni));
|
|
}
|
|
else res.rgb = mix(res.rgb,nt,ni);
|
|
return res;
|
|
}
|
|
|
|
void main()
|
|
{
|
|
vec2 coord = TexCoord;
|
|
vec4 res = texture(InputTexture,coord);
|
|
res.rgb = grain(res.rgb,coord);
|
|
FragColor = res;
|
|
}
|