9-slice shader
Simple shader that implements 9-patch/9-slice behaviour.
There are situations when you can’t use 9-patch rect but have to use Sprite. This shader is exactly for theese situations.
Considerations:
Don’t overuse it. When you use shader in Sprite it will require separate draw call interfearing with batching. thus if have too many(more than few dozen I guess) of such sprites your performance can degrade.
For this to work you need to add this code to your Sprite:toolextends Sprite
func _ready(): set_notify_transform(true)
func _notification(what): if what == NOTIFICATION_TRANSFORM_CHANGED: get_material().set_shader_param("scale", scale)
Shader code
shader_type canvas_item;
uniform vec2 scale;
uniform int right;
uniform int top;
uniform int left;
uniform int bottom;
float map(float value, float originalMin, float originalMax, float newMin, float newMax) {
return (value - originalMin) / (originalMax - originalMin) * (newMax - newMin) + newMin;
}
float process_axis(float coord, float pixel, float texture_pixel, float start, float end) {
if (coord > 1.0 - end * pixel) {
return map(coord, 1.0 - end * pixel, 1.0, 1.0 - texture_pixel * end, 1.0);
} else if (coord > start * pixel) {
return map(coord, start * pixel, 1.0 - end * pixel, start * texture_pixel, 1.0 - end * texture_pixel);
} else {
return map(coord, 0.0, start * pixel, 0.0, start * texture_pixel);
}
}
void fragment() {
vec2 pixel_size = TEXTURE_PIXEL_SIZE / scale;
vec2 mappedUV = vec2(
process_axis(UV.x, pixel_size.x, TEXTURE_PIXEL_SIZE.x, float(left), float(right)),
process_axis(UV.y, pixel_size.y, TEXTURE_PIXEL_SIZE.y, float(top), float(bottom))
);
COLOR = texture(TEXTURE, mappedUV);
}


I make a simple benchmark test for the shader, it almost has same performance with the origin sprite, so maybe you don’t need worry about the performance problem:D
doesn’t work properly with AtlasTexture
Hi, it’s 2025 and I’m using Godot 4.4.1. Thanks for the shader!
The suggested code so it updates in editor might need to be changed to this with newer Godot versions:
@tool extends Sprite2D func _ready(): set_notify_transform(true) func _notification(what): if what == NOTIFICATION_TRANSFORM_CHANGED: material.set("shader_parameter/scale", scale)Also remember you might need to close and reload your scene to see the changes