ok, so honestly I’ve started to veer away from the original brief (sorry!), but I’m having a lot of fun with this so I’m not going to judge myself too harshly on that
First up, the shader in its entirety, as it currently stands:
shader_type canvas_item;
uniform vec2 resolution = vec2(1200.0, 900.0);
uniform float shadow_scale;
uniform float shadow_threshold;
uniform float shadow_depth;
uniform float color_depth;
uniform float color_scale;
uniform int blur_depth : hint_range(2, 15) = 2;
uniform float brightness_compensation : hint_range(.9, 2.0) = 1.0;
vec4 blur(sampler2D blur_texture, vec2 uv)
{
vec4 color = vec4(.0);
float start_coord = .0 - (float(blur_size) * .5);
float max_coord = (float(blur_size) * .5) + 1.0;
for (float blur_x = start_coord; blur_x < max_coord; blur_x++)
{
for (float blur_y = start_coord; blur_y < max_coord; blur_y++)
{
vec2 offset = vec2(blur_x, blur_y) / resolution;
color += texture(blur_texture, uv + offset);
}
}
return color / pow(float(blur_size) + 1.0, 2.0);
}
void fragment()
{
vec2 color_res = resolution / color_scale;
vec4 base_col = blur(TEXTURE, floor(UV * color_res) / color_res);
COLOR.r = log(floor(exp(base_col.r) * color_depth) / color_depth);
COLOR.g = log(floor(exp(base_col.g) * color_depth) / color_depth);
COLOR.b = log(floor(exp(base_col.b) * color_depth) / color_depth);
vec2 shadow_res = resolution / shadow_scale;
vec4 lum_base_col = texture(TEXTURE, floor(UV * shadow_res) / shadow_res);
float lum = (0.299*lum_base_col.r + 0.587*lum_base_col.g + 0.114*lum_base_col.b);
COLOR = COLOR * (1.0 - (shadow_depth * step(lum, shadow_threshold)));
COLOR *= brightness_compensation;
}
This shader consists of two main parts: firstly, it will pixelate and reduce the colour count of the colour component of the image.
Secondly, it will look at the perceived brightness of the image at each pixel, and where the brightness falls below a user-defined threshold it will apply a shadow. This will also be pixelated, but at a scale the user can define separately from the colour component of the image.
There’s some fun quirks to it, which bear a little explaining. I’ve included a simple blur function, which I found plays really nicely with the pixelation - higher blur values will result in much larger blocks of single colours, especially at higher colour scales and lower colour counts. For comparison, let’s fuck up a beautiful photo of the coast:
So pretty! Here’s the same photo, with the colour count set to 5, scale of 12 and a blur depth of 2:
We have created a horrible ugly mess of colours. Terrible work! But what if we up the blur depth to 15?
Much cleaner! The pixels are still chunky, but at least now we can parse the image more clearly.