![]() |
Attention | Topic was automatically imported from the old Question2Answer platform. |
![]() |
Asked By | Niko |
I’m trying to create a dark outline outside and a brighter inside for a polygon2D, for this I’m using nested viewports each containing a shader, one for the inline, other for the outline, and the last for pixealizing the polygon.
Here’s my node setup:
And here’s the final result:
But having 2 of these for each polygon and outline color is becoming expensive, how could I compress the two outline shaders into a single, double-color outline?
This is the outline shader:
shader_type canvas_item;
const vec4 outline_color = vec4(0.10, 0.01, 0.01, 1.00);
const float outline_scale = 1.0;
bool has_contrary_neighbour(vec2 uv, vec2 texture_pixel_size, sampler2D texture)
{
for (float i = -ceil(outline_scale); i <= ceil(outline_scale); i++)
{
float x = abs(i) > outline_scale ? outline_scale * sign(i) : i;
float offset = outline_scale - abs(x);
for (float j = -ceil(offset); j <= ceil(offset); j++)
{
float y = abs(j) > offset ? offset * sign(j) : j;
vec2 xy = uv + texture_pixel_size * vec2(x, y);
if ((xy != clamp(xy, vec2(0.0), vec2(1.0)) || texture(texture, xy).a == 0.0)) { return true; }
}
}
return false;
}
void fragment()
{
vec2 uv = UV;
COLOR = texture(TEXTURE, uv);
if ((COLOR.a > 0.0) && has_contrary_neighbour(uv, TEXTURE_PIXEL_SIZE, TEXTURE))
{
COLOR.rgb = outline_color.rgb;
COLOR.a += (1.0 - COLOR.a) * outline_color.a;
}
}
And this is the inline shader:
shader_type canvas_item;
const vec4 primary_color = vec4(0.8, 0.2, 0.08, 1.0);
const vec4 secondary_color = vec4(0.6, 0.06, 0.15, 1.0);
const float outline_scale = 2.0;
bool has_contrary_neighbour(vec2 uv, vec2 texture_pixel_size, sampler2D texture)
{
for (float i = -ceil(outline_scale); i <= ceil(outline_scale); i++)
{
float x = abs(i) > outline_scale ? outline_scale * sign(i) : i;
float offset = floor(sqrt(pow(outline_scale + 0.5, 2) - x * x));
for (float j = -ceil(offset); j <= ceil(offset); j++)
{
float y = abs(j) > offset ? offset * sign(j) : j;
vec2 xy = uv + texture_pixel_size * vec2(x, y);
if ((xy != clamp(xy, vec2(0.0), vec2(1.0)) || texture(texture, xy).a == 0.0)) { return true; }
}
}
return false;
}
void fragment()
{
vec2 uv = UV;
COLOR = texture(TEXTURE, uv);
if ((COLOR.a > 0.0) && has_contrary_neighbour(uv, TEXTURE_PIXEL_SIZE, TEXTURE))
{
if (UV.y < 0.5)
{
COLOR.rgb = mix(COLOR.rgb, secondary_color.rgb, secondary_color.a);
COLOR.a += (1.0 - COLOR.a) * secondary_color.a;
}
else if (UV.y > 0.5)
{
COLOR.rgb = mix(COLOR.rgb, primary_color.rgb, primary_color.a);
COLOR.a += (1.0 - COLOR.a) * primary_color.a;
}
}
}