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:
tool
extends 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);
}
Live Preview
Tags
9-patch, 9-slice, nine-patch, nine-slice
The shader code and all code snippets in this post are under CC0 license and can be used freely without the author's permission. Images and videos, and assets depicted in those, do not fall under this license. For more info, see our License terms.

Related shaders

far distance water shader (sea shader)

Manga Shader

a simple reflection shader

guest

3 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
yikescloud
yikescloud
3 years ago

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

boruok
boruok
2 years ago

doesn’t work properly with AtlasTexture

Quentin Delvallet
7 months ago

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