Repeated texture overlay for tilemaps
This shader can be used to apply a repeated texture to a tilemap. It will only apply the texture to fully red parts of the tiles, so that edges can be preserved if you wish. Check out the demo project for the full set up.
Technically you can use this shader for any sprites, not just tiles, but tiles would be the most common use case.
Shader code
shader_type canvas_item;
uniform sampler2D overlay_tex: repeat_enable, filter_nearest;
uniform float scale = 0.006944444; // calculated by 1/texture size e.g. 1/144
varying vec2 world_position;
void vertex(){
// calculate the world position for use in the fragment shader
world_position = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy;
}
void fragment() {
// only apply overlay_tex on the fully red parts of the original tiles
float mix_amount = floor(COLOR.r);
// sample the overlay_tex using worldPos
vec4 overlay_color = texture(overlay_tex, world_position * scale);
// combine original color and overlay color together
COLOR = mix(COLOR, overlay_color, mix_amount);
}

this is very nice, thanks for sharing
I love your videos. Can you show us the pixelart water shader sometime?
If you get texture bleeding (texture is applied over a large area when a red pixel is adjacent to a transparent pixel) then I found there are a couple ways to address this:
use built-in method of Image.fix_alpha_edges()
everything is done already
EDIT: unrelated to shader (just raw image data of texture)
I found another fix. The core problem is that right now the shader only checks the red channel in the rbg. By checking if b and g are equal to 0.0, and a (alpha) is equal to 1.0, it fixes the problem.
The problem is that sometimes you transparent pixels, even though they have an alpha value of 0.0, can still have a r value of 1.0.
Here is a version of the shader with this fix, as well as the scale variable changed to just being the size of the texture in px (the 1/px_size formula is done for you)
shader_type canvas_item; uniform sampler2D overlay_tex : repeat_enable, filter_nearest; uniform float tex_scale = 90.0; varying vec2 world_position; void vertex() { world_position = (MODEL_MATRIX * vec4(VERTEX, 0.0, 1.0)).xy; } void fragment() { float scale = 1.0 / tex_scale; bool is_red = (COLOR.r == 1.0 && COLOR.b == 0.0 && COLOR.g == 0.0 && COLOR.a == 1.0); if (is_red) { vec4 overlay_color = texture(overlay_tex, world_position * scale); COLOR = overlay_color; } }Oh that’s really good to know. I was pretty confused back then.