sub texel dithering for low res textures and pixel art

A stylised effect for improving standard bilinear sampling.

Shader code
shader_type spatial;

uniform sampler2D albedo : source_color, filter_linear_mipmap;

// 3-sample stochastic spiral sub-texel stylised dithered sampling,
// for low resolution textures where bilinear filter is very apparent.
vec4 texture_dither(sampler2D samp, vec2 uv) {
	float lod = textureQueryLod(samp, uv).r;
	vec2 t_size = vec2(textureSize(samp, int(lod)));
	vec2 step_len = 1.0 / (t_size * sqrt(3.0));
	vec2 step_down = step_len / 3.0;
	float step_ang = TAU / 3.0;
	// Sub-texel jitter
	float a = fract(sin(dot(round(uv * t_size * 8.0), vec2(12.9898, 78.233))) * (43758.5453)) * TAU;
	vec2 dir = vec2(cos(a), sin(a));
	mat2 rot = mat2(vec2(cos(step_ang), -sin(step_ang)), vec2(sin(step_ang),  cos(step_ang)));
	vec4 acc = vec4(0.0);
	// Spiral sampling loop
	for (int i = 0; i < 3; i++) {
		acc += textureLod(samp, uv + dir * step_len, floor(lod));
		dir *= rot;
		step_len -= step_down;
		step_down *= 0.5;
	}
	return acc / 3.0;
}

void fragment() {
	ALBEDO = texture_dither(albedo, UV).rgb;
	// uncomment for comparison with standard bilinear.
	//ALBEDO = texture(albedo, UV).rgb;
}
Tags
dithering, pixel
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 xtarsia

Related shaders

guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments