|
|
|
|
Reply From: |
Xrayez |
The demo uses 4-way kernel method for drawing outlines, in order to address smoothness problem it’s better to use 8-way kernel. To eliminate overlap, you only need to fill pixels that are transparent:
shader_type canvas_item;
uniform float outline_width = 2.0;
uniform vec4 outline_color: hint_color;
void fragment(){
vec4 col = texture(TEXTURE, UV);
vec2 ps = TEXTURE_PIXEL_SIZE;
float a;
float maxa = col.a;
float mina = col.a;
// Use 8-way kernel for smoothness
//-----------------//
// 1 X X X //
// \ | / //
// 2 X - O - X //
// / | \ //
// 3 X X X //
//-----------------//
// First row
a = texture(TEXTURE, UV + vec2(-outline_width, -outline_width)*ps).a;
maxa = max(a, maxa);
mina = min(a, mina);
a = texture(TEXTURE, UV + vec2(0, -outline_width)*ps).a;
maxa = max(a, maxa);
mina = min(a, mina);
a = texture(TEXTURE, UV + vec2(+outline_width, -outline_width)*ps).a;
maxa = max(a, maxa);
mina = min(a, mina);
// Second row
a = texture(TEXTURE, UV + vec2(-outline_width, 0)*ps).a;
maxa = max(a, maxa);
mina = min(a, mina);
a = texture(TEXTURE, UV + vec2(+outline_width, 0)*ps).a;
maxa = max(a, maxa);
mina = min(a, mina);
// Third row
a = texture(TEXTURE, UV + vec2(-outline_width, +outline_width)*ps).a;
maxa = max(a, maxa);
mina = min(a, mina);
a = texture(TEXTURE, UV + vec2(0, +outline_width)*ps).a;
maxa = max(a, maxa);
mina = min(a, mina);
a = texture(TEXTURE, UV + vec2(+outline_width, +outline_width)*ps).a;
maxa = max(a, maxa);
mina = min(a, mina);
// Fill transparent pixels only, don't overlap texture
if(col.a == 0.0) {
COLOR = mix(col, outline_color, maxa-mina);
}
else {
COLOR = mix(col, outline_color, 0);
}
}
I’m new to shaders as well so I think this can be optimized.
I’m not a hundred percent sure this would be an optimization, but it definitely shortens down the code.
shader_type canvas_item;
uniform float outline_width = 2.0;
uniform vec4 outline_color: hint_color;
void fragment(){
vec4 col = texture(TEXTURE, UV);
vec2 ps = TEXTURE_PIXEL_SIZE * outline_width; // multiply only once instead of eight times.
float a;
float maxa = col.a;
float mina = col.a;
// Use 8-way kernel for smoothness
//------------------//
// X X X //
// \ | / //
// X - O - X //
// / | \ //
// X X X //
//------------------//
for(float y = -1.0; y <= 1.0; y++) {
for(float x = -1.0; x <= 1.0; x++) {
if(vec2(x,y) == vec2(0.0)) {
continue; // ignore the center of kernel
}
a = texture(TEXTURE, UV + vec2(x,y)*ps).a;
maxa = max(a, maxa);
mina = min(a, mina);
}
}
// Fill transparent pixels only, don't overlap texture
if(col.a == 0.0) {
COLOR = mix(col, outline_color, maxa-mina);
} else {
// Note on old code: if the last mix value is always 0, why even use it?
COLOR = col;
}
}
SIsilicon | 2018-11-23 11:39
Yeah this works, and much more concise, thanks!
Xrayez | 2018-11-23 12:14
This gives the outline a slightly rectangular look, where diagonal lines produce a thicker outline than horizontal/vertical lines.
I produced better results for my game by multiplying the diagonal vectors by 0.7071 (one over the square root of two)
Poobslag | 2020-04-01 14:11