Outlines can be a great tool for highlighting objects in a 3D environment. Most Unreal solutions I tried so far are based on Post-processing (PP) techniques to achieve objects outlines. PP solutions have been, for me, the most effective ones in terms of behaviour and appearance. Personally, I have been using most frequently Tom Looman‘s approach for multi coloured outlines (and objects highlighting).
Unfortunately, the problem with PP is its cost, which greatly impacts especially on mobile and notebooks. If you are working on VR, saving the PP cost is definitely also a good idea.
Some trivia facts about PP outlines in Unreal (this list is definitely not thorough):
– Initially, it was possible to use the Custom Depth buffer in order to generate outlines in PP. Unluckily, there is no way (that I know of) to differentiate objects, in PP, based on Custom Depth only. This limits outlines to just one single colour (e.g. cannot differentiate objects).
– With the introduction of the Custom Stencil buffer in Unreal it was possible to create multi-colour outlines, since this buffer allows to differentiate objects by assigning a stencil value to them.
– Being the outlines generated in PP, it is difficult to create custom effects based on what is going on in your Virtual Environment. This is because most information is not available in PP domain, and/or it is difficult and unconvenient to get it in there.
– Even if you are not displaying outlines, or objects which have outlines, the PP is still adding its cost to your environment.
Recently, Tom Looman mentioned on his website a solution to achieve outlines withouth using PP. Starting from the information he provides, I propose my own implementation, which is suited for the projects I am working on.
Its main limitation is that I did not add a blur effect to make the oultine “gentler”. Also, these outlines actually exist in your environment, so they will affect it (e.g. think reflection captures or similar).
Per-Mesh outline technique
PP outline materials use a Sobel edge detector plus some other filtering based on use cases in order to compute the outlines. The result of this filtering is a “mask” containing the pixels which will be coloured in order to obtain the outline on screen. The idea of this technique is to move the outline material from the PP to a material applied on a per-object basis.
Actually, the new Outline material will be applied to a mesh surrounding the mesh we want to outline. All the pixels on this outer mesh will be transparent, except for the ones needed to draw the outline.
In order to do this, the proposed solution uses an Actor Component, which can be added to the Actor we want to outline.
As soon as Begin Play fires, the component will
- Retrieve all the static meshes found on its owner (let’s call them original meshes)
- Create a copy of them (let’s call these copies outer meshes).
- Slightly scale them up, so that each outer mesh encloses its own original mesh (currently 1.3 factor scale)
- Assign an outline material to the outer meshes.
- Make the original meshes render on the Custom Depth buffer. This step is required because the outline material will perform the outline extraction on the Custom Depth buffer.
The following images show:
- Side by side, an outer mesh and its original mesh.
- The outer mesh enclosing its original mesh.
- The real setup, with the outlined object.
This image is for illustrating the shape and scale of the outer meshes. Scaling has been exaggerated in the first two pictures to highlight the difference.
The Outline Component also provides tools to Show/Hide the outline, and to change its colour. The tool is currently implemented in Blueprints, but I plan to make a C++ version and add it to the Magic Utilities Plugin.
The Outline Material
The Outline Material is using a Material Function to extract the Outline from the Custom Depth Buffer. The Material Function doesn’t look too good, and I would like to substitute it with a Custom node, or with a different implementation, if possible. Anyway, it is interesting to notice how a Custom node doing the exact same thing will probably be less optimized than the current Material Function, since Unreal optimizes Material nodes, but probably skips optimization for Custom nodes internal code.
The Material itself is rather basic, resulting in a simple, non smoothed/blurred outline:
Finally, here are some pictures of the working implementation: