# Making a 3D shader outline in Godot
2021-03-07
![Example from my big project][example]
[Click for higher quality][example-png]
For my big project I needed an outline shader for indicating things with errors
and some other usecases like shown in the image above. However, no solution I
found satisified my needs (all of them had artifacts of some sort or simply
look wrong). I ended up writing my own solution which does give me a proper
outline effect.
[The code is available under the MIT license][source].
[It is also available on Github][github].
I will describe below how the shader works.
## Complications with Godot
Sadly, Godot doesn't make it easy to write a proper outline shader: it's
impossible to customize the render pipeline, which means we can't add the
extra information we need, let alone add a custom post-processing effect
directly. Luckily however, we can use a second `Viewport` with a
`ViewportContainer`, which allows us to use a custom `canvas_item` shader.
## Gathering the necessary info
To determine what kind of info we need we have to determine what exactly we are
trying to render. In this case, we want to draw a line _around_ an object. To
do that we need a method to detect the edges. What does have obvious edges? A
white blob on a black surface!
Thus, we take all the meshes that need an outline and simply render them as
plain white.
![Output of rendering the meshes as plain white][plain-white]
## Drawing the outline
We now need to detect the edges somehow. There are various ways to do this, but
the method used in the screenshot works as follows:
* If the pixel is white, discard it
* If the pixel is black, sample all nearby pixels and take the average (or in other
words: **blur the image**)
From the blurred image we use the red (or any) channel as alpha value and set the
color to whatever we like.
That's all there is to it!
## Actually drawing the outline in Godot
Of course, things aren't that simple in Godot. To actually use it, we need to
duplicate all the meshes that need an outline, put them in a `Viewport` and
mirror the transforms of the camera and the `MeshInstance`s every frame. I
already did some of the work [in the project I linked above][source].
## Caveats
The shader as it is right now may not suit all needs. In particular, it
disregards depth information as that isn't easily accessible (though it is
possible to get this info with a custom Spatial shader) so the outline is
always visible. It is also slow for thick outlines.
There are two alternative implementations present in the source code, one
of which is much faster, but the results they produce are poor.
## Addendum: drawing thick outlines
Instead of having a glow/emission outline you may want to have a thick outline.
It is easy to do this with the above shader by simply rounding the alpha value
(after multiplying it with `1.45...`). Alternatively, you can comment out
`COLOR.a = ...` in one of the alternative shaders.
[source]: https://git.salt-inc.org/Demindiro/godot-3d-outline
[github]: https://github.com/Demindiro/godot-3d-outline
[example]: godot-3d-outline-example.jpg
[example-png]: godot-3d-outline-example.png
[plain-white]: godot-3d-outline-white.png