So far we only ever wrote a color to the screen once per shader (or let unity generate multiple passes for us via surface shaders). But we have the possibility to draw our mesh multiple times in a single shader. A great way to use this is to draw outlines. First we draw our object as usual and then we draw it again, but we change the vertices a bit so it’s only visible around the original object, drawing a outline.
To understand this Tutorial it’s best if you understood surface shaders: https://ronja-tutorials.tumblr.com/post/172421924392/surface-shader-basics
The first version of this shader will be based on the simple unlit shader: https://ronja-tutorials.tumblr.com/post/172173911737/textures
We already have a shader pass in this shader, so we just duplicate that for now. Because we’re writing the same information twice, this doesn’t change how the shader looks though.
next change is to set up our properties and variables. This second pass
will only write a simple color to the screen so we don’t need the
texture. we just need the outline color and the outline thickness. We
put the properties in the properties area at the top like usual. It’s
important that we put the new variables in the second pass though.
next step is to rewrite our fragment shader to use the new variable
instead of a texture. We can simply return the color without any
additional calculations in there.
we don’t read from a texture in this pass, we can also ignore the uv
coordinates, so we remove them from our input struct, our vertex to
fragment struct and we stop passing them between the structs in the
With those changes, we can see in the editor that the objects now simply have the color the outlines should have. That’s because our second pass simply draws over everything the first pass has drawn. That’s a thing we’re going to fix later though.
Before that we ensure that the
outlines are actually outside of the base object. For that we simply
expand them along the their normals. That means we need the normals in
our input struct, then we simply add them to the position of the
vertices. We also normalize the normals and multiply them with the
outline thickness to make the outlines as thick as we want them to be.
With this we can now adjust the thickness of our hull, but it’s still hiding the base objects. The fix for that is that we don’t draw the front of the hull. Usually when we render objects we only draw the front because of performance reasons (you might have looked inside a object before and were able to look outside, that’s why). For this we can now invert that and only draw the backside. That means we can still see the object because we can look into the hull and we can see the hull behinde the object because it’s bigger than the object itself.
To tell unity to not render the frontsides of objects we add the Cull Front attribute to the hull pass outside of the hlsl area.
And with this we have the outlines how we want them.
It is pretty straightforward to also apply the outlines to a surface shader. Unity does generate the passes of the surface shader for us, but we can still use our own passes too which unity won’t touch so they operate as usual.
This means we can simply copy the outline pass
from our unlit shader into a surface shader and have it work just as we
expect it to.
differences of outlines via a inverted hull shader to a postprocessing
effect is that you can make the outlines on a material by material
basis, you don’t have to apply it to all objects. Also it’s a different
look than choosing outlines based on depth and normals. It’s best to
inform yourself about both techniques and then choose which is better
for your game.
I hope it’s now clear how shaders with multiple passes can work and how to use them to make outlines.
You can also find the source code for the shaders here: