QoS Style World Space Blue Noise Dither Effect

I followed the official Godot docs for advanced post processing and to see what it would look like I tried making my old blue-noise dither in world space instead of screen space. It doesn’t really work for my game that I’m working on, but if you like it then enjoy!

 

The tutorial in the docs is here: https://docs.godotengine.org/en/stable/tutorials/shaders/advanced_postprocessing.html

Shader code
shader_type spatial;
render_mode unshaded, cull_disabled;

uniform float world_uv_scale = 0.1;
uniform float posterize_levels = 8.0;
uniform float dither_bias = 0.01;
uniform vec3 noise_scroll_a = vec3(1.0);
uniform vec3 noise_scroll_b = vec3(-1.0);
uniform sampler2D screen_blue_noise_a : hint_default_white, filter_linear_mipmap;
uniform sampler2D screen_blue_noise_b : hint_default_white, filter_linear_mipmap;

uniform sampler2D DEPTH_TEXTURE : hint_depth_texture, filter_linear;
uniform sampler2D SCREEN_COLOUR : hint_screen_texture, filter_linear;

varying mat4 CAMERA_MATRIX;

void vertex()
{
	POSITION = vec4(VERTEX, 1.0); // forces transform to fill screen
	CAMERA_MATRIX = INV_VIEW_MATRIX;
}

float luma(vec3 col)
{
	return (col.r * 0.212) + (col.g * 0.701) + (col.b * 0.087);
}
vec3 posterize(vec3 col, float levels)
{
	float grey = luma(col);
	float lower = floor(grey * levels) / levels;
	float lowerDiff = abs(grey - lower);
	float upper = ceil(grey * levels) / levels;
	float upperDiff = abs(upper - grey);
	float level = lowerDiff <= upperDiff ? lower : upper;
	float adjustment = level * grey;
	return col * adjustment;
}


void fragment() 
{
	// generate depth information
	float depth = texture(DEPTH_TEXTURE, SCREEN_UV).x;
	vec3 ndc = vec3(SCREEN_UV * 2.0 - 1.0, depth);
	vec4 view = INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
	view.xyz /= view.w;
	float linear_depth = -view.z;
	vec4 world = CAMERA_MATRIX * INV_PROJECTION_MATRIX * vec4(ndc, 1.0);
	vec3 world_position = world.xyz / world.w;
	
	if (linear_depth > 2048.0)
	{
		// do not affect long distance depth
		discard;
	}

	// calculate world-space noise sampling
	vec3 scroll_pos_a = world_position + (noise_scroll_a * TIME);
	vec3 scroll_pos_b = world_position + (noise_scroll_b * TIME);
	vec2 world_uv_a = vec2(scroll_pos_a.x + scroll_pos_a.z, scroll_pos_a.y - scroll_pos_a.z);
	vec2 world_uv_b = vec2(scroll_pos_b.x + scroll_pos_b.z, scroll_pos_b.y - scroll_pos_b.z);
	vec4 noise_sample_a = texture(screen_blue_noise_a, world_uv_a * world_uv_scale);
	vec4 noise_sample_b = texture(screen_blue_noise_b, world_uv_b * world_uv_scale);
	
	// simple merge of noise affect
	float noise_affect = noise_sample_a.r * noise_sample_b.r;
	
	
	
	vec4 screen_col = texture(SCREEN_COLOUR, SCREEN_UV);
	float l = luma(screen_col.rgb) + dither_bias;
	if (l < noise_affect)
	{
 		vec3 colour_stack = posterize(screen_col.rgb, posterize_levels);
		ALBEDO = colour_stack;
	} else {
		ALBEDO = vec3(0.0);
	}	
	
	
}
Tags
dither, effect, postprocessing, retro, worldspace
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.

More from QueenOfSquiggles

GDQuest BOTW Grass Shader Gradient Tweaks

FNAF Faked 3D Displacement Shader

Related shaders

PSX Style Camera Shader – Distance Fog, Dithering, Color Limiter, Noise

Dither Gradient Shader

Dither opacity with GLES2 Support

Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments