How to make better sprite outline shader?

What I want to make is simple sprite outline shader. (not inline)
Something like this. The problem is with only fragment shader, I can’t draw outline of the edge.

5690737--594148--c.PNG

You can see that there is no outline at bottom. (which is bottom end of sprite)
Fragment shader can’t draw over its vertices, of course.

So my main question is how to outline sprite including edge?
Just add padding to my sprite might work but I want to know better idea.

I tried two pass outline (with scaling up) but resulted in some other problems. (especially sprite with holes)
I’m trying new idea, scale up by vertices, and revert scaling by adjusting uv. Therefore padding within shader.
But I also using sprite atlas so uv isn’t in [0,1]. How can I get local (or normalized) uv?

You can modify the shader to detect the outline of the alpha channel. So long as you avoid branching you can isolate alpha values over 0 and less than 1 to be your outline. If you alpha is generated by a SDF you can get many nice single pass tricks going as well.

I don’t have time to write this for you, but there are no reasons why this isn’t a great approach, providing you have room on your sprite sheet or alpha channel. You could even just have Unity create SDF from the original alpha channels at import time.

You either need to do a 5 pass shader, or you need to add a pixel of padding to your sprite. There’s no good way to scale up a sprite in the shader for various reasons, mainly related to batching and there otherwise being no way to consistently know in the shader which direction to expand the sprite.

The SDF method @hippocoder mentioned is effectively adding padding to the sprite, but also storing your alpha in a special “blurred” way. It’s good for if you want to dynamically glow or have wide outlines. For this use case it’s overkill.

1 Like

Thanks for the answers! But my sprite contains some transparency so SDF might not be an option.
I’m just gonna add padding to my sprites.

And @bgolus , would you mind giving me some explanation or keyword about why scaling vertices & uv in vertex shader is a bad idea? I don’t understand why this ruins batching.

If you mean the sprite has semi-transparency, ie: sections that aren’t fully opaque or fully transparent, then yes that’s a problem for SDF.

Otherwise see this post:
https://discussions.unity.com/t/637755/4

For something like a single pixel outline you could have a 50% transparent outline built into the art that you toggle on and off by adjusting the alpha threshold.

It’s not that it ruins batching, but rather the other way around. Batching along with using a sprite atlas means it’s impossible to consistently determine what direction you need to move any particular vertex to expand it, or how to rescale the UVs afterward to accommodate those changes. The individual vertices simply lack the necessary data to know. For a single, non-atlased sprite that is never batched you have the benefit of having the sprite’s transform information, and you can set any other data needed (like the relative pixel size) as a material property. For a batched and/or atlased sprites you might be able to abuse the vertex ID & vertex tangent to make a good guess as to which direction each vertex should be expanded, but only if the sprites are never scaled and all sprites have the same pixel size. And that only works if all your sprites use square “Full Rect” render geometry. Any custom geometry or tight mesh and this all goes out the window.

Conversely, having a 1-2 pixel padding around your sprites solves all of this and ensures the outline can be exactly 1 texel.

The other alternative would be something like this thread (though you can’t guarantee the width of the outline matches the art):
https://discussions.unity.com/t/760550/17

1 Like

Thanks for the detailed answer. gonna create twitter account to follow you :0

I don’t post a lot of graphics related stuff on Twitter. The occasional retweet or “um actually” in response to someone else. It’s mostly me being cranky about random stuff. :wink:

I don’t understand why the script from OP link doesn’t work on particles…
The funny part is that it works on the editor, but not in-game.