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;
}

