Anyone have a shader to put an outline around an image?
Forum rules
Before you make a thread asking for help, read this.
Before you make a thread asking for help, read this.
- Jasoco
- Inner party member
- Posts: 3727
- Joined: Mon Jun 22, 2009 9:35 am
- Location: Pennsylvania, USA
- Contact:
Anyone have a shader to put an outline around an image?
I’m looking for a shaded that can put an outline around the pixels in an image preferably with options to set the color and thickness if possible. Has anyone made one? I know they can be useful.
Re: Anyone have a shader to put an outline around an image?
qwooke made this in 2013. viewtopic.php?f=4&t=3733&start=200#p159576
- Jasoco
- Inner party member
- Posts: 3727
- Joined: Mon Jun 22, 2009 9:35 am
- Location: Pennsylvania, USA
- Contact:
Re: Anyone have a shader to put an outline around an image?
Neither of those are working right at all.
The qwooke one is completely broken. Or I'm not understanding how to send the information to it.
And the blog one doesn't draw the way it should. It seems to draw the outline inside the image edge instead of around the outside of the image edge which is what I need.
The qwooke one is completely broken. Or I'm not understanding how to send the information to it.
And the blog one doesn't draw the way it should. It seems to draw the outline inside the image edge instead of around the outside of the image edge which is what I need.
Re: Anyone have a shader to put an outline around an image?
The best way to do high-quality outlines is by applying a distance transform to the image, then use the resulting signed distance field to render the outline. It's an expensive operation that is not easy to do on a GPU. It's not suitable for realtime generated images and takes a lot of memory, because you need to precalculate the distance fields for each image.
Here's another less expensive technique I used before to put outlines around fonts. It samples the image multiple times and uses two passes to create an outlined image; one pass to render the outline, the second pass renders the image on top of it. It's still expensive and I haven't used this for realtime stuff, only to pre-bake outlines into textures. It may or may not be sufficiently fast for your application.
You can set varying thickness (size), color and smoothness of the outline. Lower smoothness gives crisp outlines, higher smoothness creates a glow-like effect.
Edit: formatting
Edit2: there was a bug in the alpha calculation
Here's another less expensive technique I used before to put outlines around fonts. It samples the image multiple times and uses two passes to create an outlined image; one pass to render the outline, the second pass renders the image on top of it. It's still expensive and I haven't used this for realtime stuff, only to pre-bake outlines into textures. It may or may not be sufficiently fast for your application.
You can set varying thickness (size), color and smoothness of the outline. Lower smoothness gives crisp outlines, higher smoothness creates a glow-like effect.
Code: Select all
local gfx = love.graphics
local shader = gfx.newShader([[
extern vec2 pixelsize;
extern float size = 1;
extern float smoothness = 1;
vec4 effect(vec4 color, Image texture, vec2 uv, vec2 fc) {
float a = 0;
for(float y = -size; y <= size; ++y) {
for(float x = -size; x <= size; ++x) {
a += Texel(texture, uv + vec2(x * pixelsize.x, y * pixelsize.y)).a;
}
}
a = color.a * min(1, a / (2 * size * smoothness + 1));
return vec4(color.rgb, a);
}
]])
-- the image
local canvas = gfx.newCanvas(128, 128)
canvas:renderTo(function()
gfx.setColor(1, 0, 0)
gfx.setLineWidth(20)
gfx.circle('line', 64, 64, 32)
end)
function love.draw()
gfx.setBlendMode('alpha')
-- pass 1: render outline
gfx.setColor(1, 1, 1) -- outline color
shader:send('pixelsize', { 1 / canvas:getWidth(), 1 / canvas:getHeight() })
shader:send('size', 4)
gfx.setShader(shader)
gfx.draw(canvas)
-- pass 2: render image
gfx.setBlendMode('alpha', 'premultiplied')
gfx.setShader()
gfx.setColor(1, 1, 1)
gfx.draw(canvas)
end
Edit: formatting
Edit2: there was a bug in the alpha calculation
Last edited by grump on Wed May 30, 2018 7:31 am, edited 3 times in total.
-
- Party member
- Posts: 234
- Joined: Mon Aug 29, 2016 8:51 am
Re: Anyone have a shader to put an outline around an image?
A very dirty trick is to draw two copies of the sprite behind it, one smaller for the inner glow and one larger for the outer glow.
Just do setColor to whatever you want before hand.The thickness is basically the scale.
I don't know if this will work in all scenarios tho.
Either way any of the other solutions posted here will be much better. (like grump's)
Just do setColor to whatever you want before hand.The thickness is basically the scale.
I don't know if this will work in all scenarios tho.
Either way any of the other solutions posted here will be much better. (like grump's)
Re: Anyone have a shader to put an outline around an image?
Simply inverting the sign works for me:
outline.glsl
Code: Select all
vec4 resultCol;
extern vec2 stepSize;
vec4 effect( vec4 col, Image texture, vec2 texturePos, vec2 screenPos )
{
// get color of pixels:
number alpha = -4.0*texture2D( texture, texturePos ).a;
alpha += texture2D( texture, texturePos + vec2( stepSize.x, 0.0f ) ).a;
alpha += texture2D( texture, texturePos + vec2( -stepSize.x, 0.0f ) ).a;
alpha += texture2D( texture, texturePos + vec2( 0.0f, stepSize.y ) ).a;
alpha += texture2D( texture, texturePos + vec2( 0.0f, -stepSize.y ) ).a;
// calculate resulting color
resultCol = vec4( 0.4f, 1.0f, 0.1f, alpha );
// return color for current pixel
return resultCol;
}
-
- Party member
- Posts: 730
- Joined: Sat Apr 26, 2014 7:46 pm
Re: Anyone have a shader to put an outline around an image?
When I saw this post the first thing I did was ask the people on IRC if SDF will be faster than the way already described here lol. The only reason I did not recommend it is because no one has created a way to generate a SDF in love yet. So I was going to write one first before submitting my answer.grump wrote: ↑Wed May 30, 2018 6:23 am The best way to do high-quality outlines is by applying a distance transform to the image, then use the resulting signed distance field to render the outline. It's an expensive operation that is not easy to do on a GPU. It's not suitable for realtime generated images and takes a lot of memory, because you need to precalculate the distance fields for each image.
Here's another less expensive technique I used before to put outlines around fonts. It samples the image multiple times and uses two passes to create an outlined image; one pass to render the outline, the second pass renders the image on top of it. It's still expensive and I haven't used this for realtime stuff, only to pre-bake outlines into textures. It may or may not be sufficiently fast for your application.
You can set varying thickness (size), color and smoothness of the outline. Lower smoothness gives crisp outlines, higher smoothness creates a glow-like effect.
Code: Select all
local gfx = love.graphics local shader = gfx.newShader([[ extern vec2 pixelsize; extern float size = 1; extern float smoothness = 1; vec4 effect(vec4 color, Image texture, vec2 uv, vec2 fc) { float a = 0; for(float y = -size; y <= size; ++y) { for(float x = -size; x <= size; ++x) { a += Texel(texture, uv + vec2(x * pixelsize.x, y * pixelsize.y)).a; } } a = color.a * min(1, a / (2 * size * smoothness + 1)); return vec4(color.rgb, a); } ]]) -- the image local canvas = gfx.newCanvas(128, 128) canvas:renderTo(function() gfx.setColor(1, 0, 0) gfx.setLineWidth(20) gfx.circle('line', 64, 64, 32) end) function love.draw() gfx.setBlendMode('alpha') -- pass 1: render outline gfx.setColor(1, 1, 1) -- outline color shader:send('pixelsize', { 1 / canvas:getWidth(), 1 / canvas:getHeight() }) shader:send('size', 4) gfx.setShader(shader) gfx.draw(canvas) -- pass 2: render image gfx.setBlendMode('alpha', 'premultiplied') gfx.setShader() gfx.setColor(1, 1, 1) gfx.draw(canvas) end
Edit: formatting
Edit2: there was a bug in the alpha calculation
Re: Anyone have a shader to put an outline around an image?
I implemented this for FÖNTGen, but I it doesn't work with LÖVE 11 yet. It's a pure Lua implementation that runs on a single core and while it's fast enough for the things I use it for, it's too slow to be used in realtime on a large scale.
- Jasoco
- Inner party member
- Posts: 3727
- Joined: Mon Jun 22, 2009 9:35 am
- Location: Pennsylvania, USA
- Contact:
Re: Anyone have a shader to put an outline around an image?
See that's a problem I'd not want to deal with. Also using this shader doesn't work right either. I'm sending a table with two values to it and no matter what I send it doesn't render right.pgimeno wrote: ↑Wed May 30, 2018 7:47 amSimply inverting the sign works for me:
outline.glslYou can see the outline of the next quad, though, so that's something to watch out for.Code: Select all
vec4 resultCol; extern vec2 stepSize; vec4 effect( vec4 col, Image texture, vec2 texturePos, vec2 screenPos ) { // get color of pixels: number alpha = -4.0*texture2D( texture, texturePos ).a; alpha += texture2D( texture, texturePos + vec2( stepSize.x, 0.0f ) ).a; alpha += texture2D( texture, texturePos + vec2( -stepSize.x, 0.0f ) ).a; alpha += texture2D( texture, texturePos + vec2( 0.0f, stepSize.y ) ).a; alpha += texture2D( texture, texturePos + vec2( 0.0f, -stepSize.y ) ).a; // calculate resulting color resultCol = vec4( 0.4f, 1.0f, 0.1f, alpha ); // return color for current pixel return resultCol; }
This one works perfectly though, but it also seems to require padding on the image to work right which would require a lot more effort on my part to redo all my image files. I hadn't planned on doing that. But it's a start. Even if I have to re-render all my images onto canvases with the padding automatically.bobbyjones wrote: ↑Wed May 30, 2018 7:51 amWhen I saw this post the first thing I did was ask the people on IRC if SDF will be faster than the way already described here lol. The only reason I did not recommend it is because no one has created a way to generate a SDF in love yet. So I was going to write one first before submitting my answer.grump wrote: ↑Wed May 30, 2018 6:23 am The best way to do high-quality outlines is by applying a distance transform to the image, then use the resulting signed distance field to render the outline. It's an expensive operation that is not easy to do on a GPU. It's not suitable for realtime generated images and takes a lot of memory, because you need to precalculate the distance fields for each image.
Here's another less expensive technique I used before to put outlines around fonts. It samples the image multiple times and uses two passes to create an outlined image; one pass to render the outline, the second pass renders the image on top of it. It's still expensive and I haven't used this for realtime stuff, only to pre-bake outlines into textures. It may or may not be sufficiently fast for your application.
You can set varying thickness (size), color and smoothness of the outline. Lower smoothness gives crisp outlines, higher smoothness creates a glow-like effect.
Code: Select all
local gfx = love.graphics local shader = gfx.newShader([[ extern vec2 pixelsize; extern float size = 1; extern float smoothness = 1; vec4 effect(vec4 color, Image texture, vec2 uv, vec2 fc) { float a = 0; for(float y = -size; y <= size; ++y) { for(float x = -size; x <= size; ++x) { a += Texel(texture, uv + vec2(x * pixelsize.x, y * pixelsize.y)).a; } } a = color.a * min(1, a / (2 * size * smoothness + 1)); return vec4(color.rgb, a); } ]]) -- the image local canvas = gfx.newCanvas(128, 128) canvas:renderTo(function() gfx.setColor(1, 0, 0) gfx.setLineWidth(20) gfx.circle('line', 64, 64, 32) end) function love.draw() gfx.setBlendMode('alpha') -- pass 1: render outline gfx.setColor(1, 1, 1) -- outline color shader:send('pixelsize', { 1 / canvas:getWidth(), 1 / canvas:getHeight() }) shader:send('size', 4) gfx.setShader(shader) gfx.draw(canvas) -- pass 2: render image gfx.setBlendMode('alpha', 'premultiplied') gfx.setShader() gfx.setColor(1, 1, 1) gfx.draw(canvas) end
Edit: formatting
Edit2: there was a bug in the alpha calculation
Who is online
Users browsing this forum: Google [Bot] and 3 guests