Skip to content

Instantly share code, notes, and snippets.

@padreputativo
Last active August 25, 2021 13:20
Show Gist options
  • Save padreputativo/de376c4697156ea651f8e93a332dcd41 to your computer and use it in GitHub Desktop.
Save padreputativo/de376c4697156ea651f8e93a332dcd41 to your computer and use it in GitHub Desktop.
16mm Film Grain shader for Godot 3
shader_type canvas_item;
/* Shader converted to Godot from ShaderToy https://www.shadertoy.com/view/Xt23DD */
uniform int kMaxIterations = 24;
uniform float STEPS = 16.0;
float Linear1(float c) { return(c<=0.04045)?c/12.92:pow((c+0.055)/1.055,2.4); }
vec3 Linear3(vec3 c) { return vec3(Linear1(c.r),Linear1(c.g),Linear1(c.b)); }
float Srgb1(float c) { return(c<0.0031308?c*12.92:1.055*pow(c,0.41666)-0.055); }
vec3 Srgb3(vec3 c) { return vec3(Srgb1(c.r),Srgb1(c.g),Srgb1(c.b)); }
const vec3 photoLuma = vec3(0.2126,0.7152,0.0722);
float PhotoLuma(vec3 c) { return dot(c,photoLuma); }
//
// LARGE FILM GRAIN TEST
//
float Noise(vec2 n, float x) { n+=x; return fract(sin(dot(n.xy,vec2(12.9898, 78.233)))*43758.5453)*2.0-1.0; }
float NoiseB(vec2 n, float x) { n+=x; return fract(sin(dot(n.xy,vec2(12.9898, 78.233)))*43758.5453); }
// Step 1 in generation of the grain source texture.
float Step1(vec2 uv,float n) {
float a=1.0, b=2.0, c=-12.0, t=1.0;
return (1.0/(a*4.0+b*4.0+abs(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 grain source texture.
float Step2(vec2 uv, float n) {
float a=1.0, b=2.0, c=4.0, t=1.0;
return (1.0/(a*4.0+b*4.0+abs(c))) * (
Step1(uv+vec2(-1.0,-1.0)*t, n) * a +
Step1(uv+vec2( 0.0,-1.0)*t, n) * b +
Step1(uv+vec2( 1.0,-1.0)*t, n) * a +
Step1(uv+vec2(-1.0, 0.0)*t, n) * b +
Step1(uv+vec2( 0.0, 0.0)*t, n) * c +
Step1(uv+vec2( 1.0, 0.0)*t, n) * b +
Step1(uv+vec2(-1.0, 1.0)*t, n) * a +
Step1(uv+vec2( 0.0, 1.0)*t, n) * b +
Step1(uv+vec2( 1.0, 1.0)*t, n) * a +
0.0);
}
// Used for stills.
vec3 Step3(vec2 uv) {
float a=Step2(uv, 0.07);
float b=Step2(uv, 0.11);
float c=Step2(uv, 0.13);
return vec3(a,b,c);
}
// Used for temporal dither.
vec3 Step3T(vec2 uv, float iTime) {
float a=Step2(uv,0.07*fract(iTime));
float b=Step2(uv, 0.11*fract(iTime));
float c=Step2(uv, 0.13*fract(iTime));
return vec3(a,b,c);
}
void fragment() {
vec2 uv = FRAGCOORD.xy;
vec2 uv2 = FRAGCOORD.xy/(1.0 / SCREEN_PIXEL_SIZE).xy;
vec2 uv3 = vec2(uv2.x, 1.0-uv2.y);
uv2.y = -uv2.y;
float rep = 1.0;
//vec3 color = texture(TEXTURE, uv2*rep).rgb;
//vec3 color = textureLod(SCREEN_TEXTURE, uv2*rep, 0.0).rgb;
vec3 color = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0).rgb;
color = Linear3(color);
vec3 grain = Step3T(uv, TIME);
// Prune effect at lighter luma.
float prune = PhotoLuma(color);
prune = sqrt(prune);
prune = 1.0-prune;
prune *= sqrt(uv2.x);
vec2 off = grain.yz * 2.5 * prune;
off /= SCREEN_PIXEL_SIZE.xy;
// Adjust sampling position.
//color = texture(TEXTURE,(uv2+off)*rep).rgb;
//color = textureLod(SCREEN_TEXTURE, (uv2+off)*rep, 0.0).rgb;
color = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0).rgb;
color = Linear3(color);
if (uv2.y < 0.9) {
// TOP: Show grain.
color += color * grain.xxx * (prune*8.0/1.0);
color = Srgb3(color);
} else {
// BOTTOM: Show noise texture.
color = Step3(uv) * 1.0 * uv2.x + 0.5;
}
COLOR = vec4(color, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment