Animated selection rectangle (Marching ants)
Place this shader on any 2D object to make its outline into marching ants.
Uniforms
Ant color 1, Ant color 2 – The colors of the rectangle.
Ant width – Pixel width of the ants.
Ant length – Pixel length of the ants.
Ant speed – How fast the ants should be; make it negative for counterclockwise movement.
Lots of thanks to Peony (thebloomingflower) and Karmydev for helping me with it.
Shader code
shader_type canvas_item;
uniform vec4 ant_color_1: source_color = vec4(1.0, 1.0, 1.0, 1.0);
uniform vec4 ant_color_2: source_color = vec4(0.0, 0.0, 0.0, 1.0);
uniform float ant_width = 2.0;
uniform float ant_length = 10.0;
uniform float ant_speed = 30.0;
void fragment() {
vec2 uv = UV;
vec2 fw = fwidth(uv);
float adjusted_ant_width = min(ant_width, min(0.5 / fw.x, 0.5 / fw.y));
vec2 aw = fw * adjusted_ant_width;
vec2 cond = (sign(abs(uv - 0.5) - 0.5 + aw) + 1.0) * 0.5 * ceil(((sign(uv.yx - aw.yx) + 1.0) * 0.5 * (sign(uv - 0.5) * vec2(0.5, -0.5) + 0.5) * 0.5 + (sign(1.0 - aw.yx - uv.yx) + 1.0) * 0.5 * (sign(uv - 0.5) * vec2(-0.5, 0.5)+ 0.5) * 0.5));
float dir = dot(vec2(cond.y, -cond.x), sign(uv.yx - 0.5) * uv / aw);
float ant_type = round(fract((dir * adjusted_ant_width + TIME * ant_speed) * 0.5 / ant_length));
vec4 ant_color = mix(ant_color_1, ant_color_2, ant_type);
COLOR = (cond.x + cond.y) * ant_color;
}


Really cool, thanks for sharing!
Hi, the shader looks excellent!
I am however running into an issue where zooming IN with a Camera2D makes the line of marching ants thinner and thinner until it disappears. Zooming OUT seems to make it a bit thicker. This is in Godot 4.4.
I will investigate it on my own at some point, but I thought I’d let you know 🙂
This was intentional on my end, I made this for my SVG editor where it needs it to remain consistent as I zoom in or out. If you solved this, let us know.
Maybe I’m misunderstanding you, but Isn’t this just because the shader uses fwidth(UV) to get the fragment width, keeping the ants a certain number of pixels wide instead of consistently covering certain area regardless of zoom?
It isn’t ideal but cant you just add something like:
... uniform bool percent_based = false; //uniform for switching between pixel based and percent based .... vec2 fw = fwidth(UV); if(percent_based){ fw = vec2(.001); } ....the .001 is just a hueristic value, maybe something else can be put there. And also im pretty sure if statements aren’t great in shaders but there should be some equivilent to make it not an if.
Thanks.
Can turn the ants into a gradient by adding:
replace the definition of ant_type and ant_color with the two lines above.