First post! Finally diving into Unity, and still relatively young to shaders. I want to create something that I think would normally require multiple passes, and may be possible to do programmatically in Unity, but I’m not sure. It involves outlining the opaque pixels of a semi-transparent texture on a plane, possibly multiple planes for multiple textures. I’ll give an example:
Here we have a three part monkey: two arms and a body. I would have three PNGs for this monkey, and would want to rotate them all to make him look animated (using his shoulders as pivot points, etc). It usually ends up with easy fixes like the second or third monkey in the bottom row, where applying an outline can only be done to individual objects rather than a group.
So my question is two parts:
Can we do a stroke outline in shaders for a transparent PNG, that only outlines the filled section?
and
Can that same stroke be applied not to individual game objects, but to groups of them? Or all be set at a layer behind all objects?
Currently, the artist I am working with has duplicate assets for all objects, which would match the main objects’ movements, just a plane or two back. If this would not work for making that programmatic, is there another approach I should look at?
perhaps you could make a 2nd copy of the moving monkey a tiny bit closer and larger, make it completely black and shine the background monkey through the black monkey so that you have a slightly larger black outline and the colour monkey in the middle. I think it would be the most accurate way to do it.
I wish! Scaling a black copy like that leads to all kinds of inconsistencies with an object that has any empty space between its center and its farthest edge. A square or triangle might work, but something like a crescent will not. In the case of the monkey:
You can see that his arms do not have outlines on the inside, since scaling moves the silhouette further behind his arms rather than outside of them.
The approach I do know which can work is having 24 silhouettes that are some distance from the center in 24 different angles, leading to an outline formed by all the copies overlapping. The only problem with this is that 24 copies of every sprite is a lot, so I’m looking for a shader alternative.
An example of the 24 overlapping copies (in copies ranging from 1 to 16):
So is there a way to make copies like this, except with a two pass shader?
I think the best way to go about this is with fattened outline sprites which are rendered before your actual sprites. Create the fattened silhouettes using a stroke in Photoshop, and then render them before your coloured sprites using render queues.
Wouldn’t that double the asset count? And I would have to do that all manually, right?
I still think this can be done programmatically, and with only the original assets. If we do use outline assets though, I’ll definitely check out render queues. Thanks!
It can be done programatically in the asset pipeline in the editor phase. You can generate outlined versions of the sprites automagically (a slow process) then automate everything.
But Daniel’s approach is what I would do. Otherwise you’re going to have to draw black versions multiple times behind the colour version. This is still the fastest rendering technique. If you’re looking for a magical outline shader that will work in 2D you will find it is cripplingly slow, and probably won’t look as good.
If Daniel is recommending the art path way over shaders, he’s saying it for a very good reason: Shaders will be woefully inefficient at dealing with this issue.
It would double the asset count, yes. However, you could perform the outline image creation with a Photoshop batch operation, and make an editor script to create the appropriate prefabs or whatever.
You could try and accomplish the stroke generation in a shader, but I can’t think of a way to do that without performing a whole lot of texture lookups for every fragment. I think that would be prohibitively expensive on iOS.
Alright, so shaders are out. Can I still do it programmatically at the beginning of each scene, creating outlined silhouettes through something like the 24 render technique, and then save them to a texture that I only use for that scene? I would love to just add a component to every item that I wanted outlined.
EDIT: I’m also curious about this:
Could you explain it a little more? I would love to understand how it works, even if I’m not taking that approach for this case anymore.
there are a number of ways but the gist is you would select your texture, or textures (or even a prefab) and have a menu item called Process outline, or such and this would:
grab all the textures used
create new textures for the outline, possibly by drawing the same alpha texture to the new texture with black a tiny bit offset perhaps
create a new asset you can use
The photoshop actions method may be good too - there is a lot ot learn. Also I suspect this issue has cropped up before so do some more searches about that if you can.