Fake Floyd Stienberg Noise Dithering

I wanted to make Floyd Stienberg Dithering in Godot. But I found out it’s pretty much impossible to do, however, I can replicate the look convincingly with noise.

 

TIP: When creating the noise texture I reccomend a high resolution image with a high frequency.

Shader code
shader_type canvas_item;

uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
uniform sampler2D  uTexBlueNoise;
uniform float contrast = 1;
uniform float brightness = 0;
uniform float uTime1 = 1;
uniform float uTime2 = 2;
uniform float uTime3 = 4;
uniform float colors = 8;

float GetBlueNoiseDither( float grayscale, ivec2 pixelCoord, bool noise, vec2 ScreenUV )
{
    float blueNoiseValue = texture( uTexBlueNoise, vec2( ScreenUV.s, ScreenUV.t ) ).r;
    float blueNoiseValue2;
	float blueNoiseValue3;
	float blueNoiseValue4;
    if ( noise == true ) blueNoiseValue = sin( blueNoiseValue * 2.0 * 3.141592 + uTime1 ) * 0.5 + 0.5;
	if ( noise == true ) blueNoiseValue2 = sin( blueNoiseValue * 2.0 * 3.141592 + uTime2 ) * 0.5 + 0.5;
	if ( noise == true ) blueNoiseValue3 = sin( blueNoiseValue * 2.0 * 3.141592 + uTime3 ) * 0.5 + 0.5;
	if ( noise == true ) blueNoiseValue4 = 0.0;
    // Version 1
    //return blueNoiseValue < grayscale ? 1.0 : 0.0;
    
    // Version 2
    return (step( blueNoiseValue, grayscale ) + step( blueNoiseValue2, grayscale ) + step( blueNoiseValue3, grayscale ) + step( blueNoiseValue4, grayscale ))/4.0;
}

mat4 contrastMatrix( float _contrast ){
	float t = ( 1.0 - _contrast ) / 2.0;
    return mat4( 
		vec4(_contrast, 0, 0, 0),
		vec4(0, _contrast, 0, 0),
		vec4(0, 0, _contrast, 0),
		vec4(t, t, t, 1));
}

void fragment() {
	vec4 tex = texture(screen_texture, SCREEN_UV);
	tex.r = round(tex.r*(colors))/colors;
	tex.g = round(tex.g*(colors))/colors;
	tex.b = round(tex.b*(colors))/colors;
	
	float ditherColorR = GetBlueNoiseDither( tex.r, ivec2( SCREEN_UV.st ), true, SCREEN_UV );
	float ditherColorG = GetBlueNoiseDither( tex.g, ivec2( SCREEN_UV.st ), true, SCREEN_UV );
	float ditherColorB = GetBlueNoiseDither( tex.b, ivec2( SCREEN_UV.st ), true, SCREEN_UV );
	
	COLOR.rgba = tex.rgba * (vec4(ditherColorR,ditherColorG,ditherColorB, 1.0) * contrastMatrix(contrast) + brightness);
}
void light() {
	// Called for every pixel for every light affecting the CanvasItem.
}
Tags
90s, 90s CGI, dithering, Floyd Stienberg, retro
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

Floyd-Steinberg Dither

Arbitrary Color Reduction and Palette Ordered Dithering

Terrain Mesh Blending with Dithering

Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments