Floyd-Steinberg Dither

FLoyd-Steinberg Dither (Like) 

Adaption from Shadertoy

Shader code
shader_type canvas_item;

// classic floyd steinberg
// source: https://www.shadertoy.com/view/4sjGRD

const float lookupSize = 64.0;
const float errorCarry = 0.3;
uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;

// Test picture free for use CC0 Licence
// https://free-images.com/display/artistic_conception_green_689793.html

float getGrayscale(vec2 coords, vec2 iResolution){
	vec2 uv = coords / iResolution.xy;
	uv.y = 1.0-uv.y;
	vec3 sourcePixel = texture(screen_texture, uv).rgb;
	return length(sourcePixel*vec3(0.2126,0.7152,0.0722));
}

	
void fragment() {
	vec2 iResolution = 1.0 / SCREEN_PIXEL_SIZE;
	int topGapY = int(iResolution.y - FRAGCOORD.y);
	
	int cornerGapX = int((FRAGCOORD.x < 10.0) ? FRAGCOORD.x : iResolution.x - FRAGCOORD.x);
	int cornerGapY = int((FRAGCOORD.y < 10.0) ? FRAGCOORD.y : iResolution.y - FRAGCOORD.y);
	int cornerThreshhold = ((cornerGapX == 0) || (topGapY == 0)) ? 5 : 4;
	// Place fragment code here.
		if (cornerGapX+cornerGapY < cornerThreshhold) {
				
		COLOR = vec4(0,0,0,1);
		
	} else if (topGapY < 20) {
			
			if (topGapY == 19) {
				
				COLOR = vec4(0,0,0,1);
				
			} else {
		
				COLOR = vec4(1,1,1,1);
				
			}
		
	}
	else {
		
		float xError = 0.0;
		for(float xLook=0.0; xLook<lookupSize; xLook++){
			float grayscale = getGrayscale(FRAGCOORD.xy + vec2(-lookupSize+xLook,0),iResolution);
			grayscale += xError;
			float bit = grayscale >= 0.5 ? 1.0 : 0.0;
			xError = (grayscale - bit)*errorCarry;
		}
		
		float yError = 0.0;
		for(float yLook=0.0; yLook<lookupSize; yLook++){
			float grayscale = getGrayscale(FRAGCOORD.xy + vec2(0,-lookupSize+yLook),iResolution);
			grayscale += yError;
			float bit = grayscale >= 0.5 ? 1.0 : 0.0;
			yError = (grayscale - bit)*errorCarry;
		}
		
		float finalGrayscale = getGrayscale(FRAGCOORD.xy,iResolution);
		finalGrayscale += xError*0.5 + yError*0.5;
		float finalBit = finalGrayscale >= 0.5 ? 1.0 : 0.0;
		
		COLOR = vec4(finalBit,finalBit,finalBit,1);
			
	}
	
}
Tags
shadertoy dither grayscale
This shader is a port from an existing Shadertoy project. Shadertoy shaders are by default protected under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported (CC BY-NC-SA 3.0) license unless anything else has been stated by the author. For more info, see our License terms.

More from zuwiwano

Crosshair (Godot 4)

Bayer Dithering

VHS Shader/Distortion

Related shaders

Dither Gradient Shader

Color reduction and dither

16 Bit Color (C64-Like) with Dither

Subscribe
Notify of
guest

6 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
Rpics
Rpics
1 year ago

what about node? you need to create new shader in material and paste the code

magmaus3
1 year ago

it renders for me as upside-down

Calinou
1 year ago
Reply to  magmaus3

In Godot 4, this is expected as this shader was written for Godot 3 and its upside-down viewport conventions (inherited from OpenGL).

Remove this line from the shader:

uv.y = 1.0-uv.y;
TheYellowArchitect
1 year ago

Restricted by white color? You can easily add color at the final line of COLOR. * 0.5 at first variable gives teal color. Damn, this is too good to be true. Peak Scifi horror.

rom
rom
5 months ago

Im just rendering a black texture… what im doing wrong? using 4.2.1