From 3724e42b823b624b83b6e6eb4f24287b402834b7 Mon Sep 17 00:00:00 2001 From: Dreadset <65445861+Dreadset@users.noreply.github.com> Date: Sat, 14 Sep 2024 21:34:05 +0200 Subject: [PATCH] Universal Outline2D Shader (with fix for Godot 4.x) Created a universal Outline2D shader script and fixed error regarding uniform 'hint_color' (it's called 'source_color' since Godot 4.0). This script is a refactored combination of the shaders "outline2D_inner", "outline2D_outer" and "outline2D_inner_outer". With this, you can easily choose the desired outline in the inspector. Also added the possibility to turn the outline on and off via the inspector. --- godot/Shaders/outline2D.shader | 69 ++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 godot/Shaders/outline2D.shader diff --git a/godot/Shaders/outline2D.shader b/godot/Shaders/outline2D.shader new file mode 100644 index 0000000..2c3f66f --- /dev/null +++ b/godot/Shaders/outline2D.shader @@ -0,0 +1,69 @@ +shader_type canvas_item; + +const int Inner = 1; +const int Outer = 2; + +// TODO: Add support for struct uniforms in shaders: https://github.com/godotengine/godot/pull/93603 +//struct Outline { + //bool inner; + //bool outer; +//}; +//uniform Outline outline_type; + +/** + 1 = Inner Outline + 2 = Outer Outline + 3 = Inner + Outer Outline +*/ +uniform int outline_type: hint_range(1, 3) = 3; +uniform bool enabled = true; +uniform vec4 line_color : source_color = vec4(1); +uniform float line_thickness : hint_range(0, 10) = 1.0; + +const vec2 OFFSETS[8] = { + vec2(-1, -1), vec2(-1, 0), vec2(-1, 1), vec2(0, -1), vec2(0, 1), + vec2(1, -1), vec2(1, 0), vec2(1, 1) +}; + +vec4 apply_shader(sampler2D txtr, vec2 txtr_pixel_size, vec4 color, vec2 uv) { + bool apply_inner = bool(outline_type & Inner); + bool apply_outer = bool(outline_type & Outer); + + vec2 size = txtr_pixel_size * line_thickness / 2.0; + + float inline = 1.0; + float outline = apply_inner && !apply_outer ? 1.0 : 0.0; + for (int i = 0; i < OFFSETS.length(); i++) { + float sample = texture(txtr, uv + size * OFFSETS[i]).a; + + // outer and inner_outer outline + if (apply_outer) outline += sample; + else if (apply_inner) outline *= sample; + + if (apply_inner && apply_outer) inline *= sample; + } + + if (apply_inner && apply_outer) { + outline = min(1.0, outline) - color.a; + inline = (1.0 - inline) * color.a; + } + else if (apply_outer) outline = min(outline, 1.0); + else if (apply_inner) outline = 1.0 - outline; + + float mix_value; + if (apply_inner && apply_outer) mix_value = outline + inline; + else if (apply_inner) mix_value = outline * color.a; + else if (apply_outer) mix_value = outline - color.a; + + vec4 outlined_result = mix(color, line_color, mix_value); + // inner and inner_outer outline + if (apply_inner) { + outlined_result = mix(color, outlined_result, outlined_result.a); + } + return outlined_result; +} + +void fragment() { + if (enabled) COLOR = apply_shader(TEXTURE, TEXTURE_PIXEL_SIZE, COLOR, UV); + else COLOR = COLOR; +}