Table of Contents

🔳 CosterGraphics.Systems.OutlineSystem


🕶️ Shaders Overview

The Outline System uses three types of shaders:

  1. 🎭 Mask Shaders
    The 🎭Mask shaders are used by the Renderer Feature during the mask Render Passes to create different types of masks of the 🔳Outline3D objects that are stored each frame for later use in the outline pipeline by the final full-screen 🖼️Composite shaders that draw the outlines to the camera texture.

    Read more about the 🎭Mask Shaders of the Outline System over here:

  2. 🔁 Intermediate Buffer Shaders
    The 🔁Intermediate buffer shaders are at the moment only used by the Pro tier Jump Flood Algorithm Distance Field and Signed Distance Field outline shaders during render passes executed in between the regular 🎭Mask passes and the final 🖼️Composite pass.

    To create the Jump Flood Algorithm Distance Field textures that are required by the JFA Composite shaders, the JFA Seeds Texture Masks created during the JFA Seed Mask passes are first copied to intermediate textures that are then written to several times in a loop for as many render passes that are required to generate the field (which depends on the size of the screen). To create the JFA Distance Field outlines the system uses separate vertical and horizontal jump passes that both require a different intermediate material/shader. After the jump passes are done the final JFA UV field is stored in a JFA UV jump render texture which is used by the Composite JFA shaders via the _OutlineJFAUVJumpTextureMask property to calculate distance fields and signed distance fields with of the ouline geometry. The JFA seeds texture from which the UV field texture is originally created is also stored in a render texture for later use in the Composite shaders via the _OutlineJFAUVSeedTexture property. What is stored in the JFA UV seed textures during the mask passes are only the screen space UV positions of the masked outline objects and what is stored in the final JFA Jump texture after the intermediate horizontal and vertical jump passes are the distances from each pixel to the closes edges of the masked outline objects.

    Read more about the 🔁Intermediate Shaders of the Outline System:

  3. 🖼️ Final Full-Screen Composite Outline/Overlay Shaders
    To explain this in terms of cooking in a restaurant kitchen, the outline 🖼️Composite shaders are where the outline ingredients that were created during the masking and intermediate render and shader passes are used to cook the final outline dishes with. Each composite shader uses one or more different kinds of 'ingredients' to create the different types of outlines with.

    In regular terms, the 🖼️Composite shaders use the texture masks, (of which most are drawn with Unlit or Lit shaders via Command Buffers in the Renderer Features that render only the enabled 🔳Outline3D objects with the same 🆔FeatureIDs into masks), to blend/bake them into different types of outlines and render them to the Scene View and Game View cameras color textures via Full-Screen Shader Graph shaders.

    This setup makes it easy to create your own outline shaders for this system's Scriptable Renderer Features because any Full-Screen Shader Graph shader used for the 🖼️Composite pass of the outline systems Renderer Features has access to all of the ingredients via the Texture2D properties that are listed below.

    To keep things optimized and efficient the renderer features will only execute the passes and create the mask textures if the composite shader has the property for it.

    Read more about the 🖼️Composite Shaders of the Outline System:



🥚 The Outline System Composite Mask Texture2D Shader Properties (The Outline Recipes Ingredients)

Below are the property names of the mask textures that are available to the final Full-Screen 🖼️Composite shaders of each Tier. The system's Renderer Features only run the required Render Passes for it if the final composite shader has one of these properties added to the Shader Graph's properties. Adding any of these Texture2D properties to a full-screen composite outline shader will instruct the 🧑‍🎨Outline3DRenderFeature to run the required Render Passes to create the texture, if supported by the Tier of the feature:

Type Property Name Simple Basic Advanced Pro
Texture2D _OutlineColorTextureMask ✔️ ✔️ ✔️ ✔️
Texture2D _OutlineColorTextureMaskDepthTested ✔️ ✔️ ✔️ ✔️
Texture2D _CameraOpaqueTexture ✔️ ✔️ ✔️ ✔️
Texture2D _OutlineDepthTextureMask ✔️ ✔️ ✔️
Texture2D _OutlineNormalsTextureMask ✔️ ✔️ ✔️
Texture2D _OutlineUVTextureMask ✔️ ✔️ ✔️
Texture2D _OutlineObjectIDTextureMask ✔️ ✔️
Texture2D _OutlineJFAUVSeedsTextureMask_Inside ✔️
Texture2D _OutlineJFAUVSeedsTextureMask_Outside ✔️
Texture2D _OutlineJFAUVJumpTextureMask_Inside ✔️
Texture2D _OutlineJFAUVJumpTextureMask_Outside ✔️

Choosing the right Outline 🖼️Composite Shader

There is no real one-size-fits-all-types-of-games full-screen edge detection outline shader method so it is important to choose the right 🖼️Composite shader that uses the right edge detection methods for your project's needs.

There are a whole bunch of different types of outlines to choose from and they all have their pro's and cons but they can loosely be grouped together based on their ability to draw thin or thick outlines, the abiliy to draw the lines on the outside of the geometry or on the inside, if they are depth tested/hidden behind other objects or always visible/see-trough, if they have per-object intersections between other objects or if they have per-object colors.

Then there are also different shaders for drawing ⭕Silhouette outlines only around the perimiters of the outline geometry, and for drawing 🌐Contour outlines that go over shapes inside of the geometry masks as well.

Finally, because this is a system for drawing Screen-Space outlines and not for World-Space 'inverted hull' outlines, world-space outline thicknesses and intersection outlines in between multiple 🔳Outline3D objects don't come by default. Currently only the Advanced tier has per-object (InstanceID based) intersection outline shaders but this functionality can maybe also be added to the Pro SDF outlines as well in a future update.

Here are some tips that may help you choose the right Composite Outline shader for your project...

Choosing Outlines based on desired thickness

Drawing very wide crisp silhouette outlines can be quite computationally expensive using the most straight forward traditional edge detection method, which is to take multiple samples in a box or circle(-ish) shape around each pixel to figure out if there is an edge at that location.
With this method, when very thick outlines are desired, we can choose to either sample a lot of neighboring pixels which exponentionally increases sample size with radius or we can offset the samples taken by adding a larger offset position which doesn't increase the sample size but is basically a cheat for extra thickness that can only be used a little before it 'breaks the illusion' and starts showing unsharp pixel 'stairs' in the corners of the silhouettes.

For sampling only one pixel and its direct neighbors nine samples are required (3x3 grid) and when sampling the neighbors around the direct neighbors as well (this would be called a two pixel sampling radius) twenty five are required (5x5 grid).
So the amount of required samples increases dramatically with each increment of the sampling radius (remember it has to be done for each pixel of the screen). Increasing the sampling radius can only be done so-much before it becomes very expensive.

Another method for drawing outlines is using the Jump Flood Algorithm to 'flood fill' a texture map with the UVs of the closest edges to each pixel and to calculate a distance field or signed distance field from that which can then be used to simply draw outlines over the distance away from the masked geometry which is a very efficient way to drawy very wide outlines. Outlines generated with the JFA have the added advantage that colors can be easily blended across the distance as well, making it really easy to generate all kinds of special multi-color outline effects.

So depending on wether or not you want thin basic outlines or thick special effect outlines you can pick between the system's 'regular' Simple, Basic or Advanced Composite shaders, which all use the sampling-neighboring-pixels methods and different edge detection kernels, or you can choose the Pro JFA Distance and Signed Distance field outlines for thick to ultra thick outlines.

Keep in mind that all outline edge-detection and thickness methods used for the Composite shaders have their own pros and cons. Since all of the outlines are rendered in screen-space as a post-processing effect, it is always an aproximation of the 'real' data and the input used for the edge detection algorithms is never absolutely mathematically perfect, since texture masks with limited band-width are used to store data like normal vectors and depth values.

Because this outline system works in the context of the Unity game engine we do have access to (almost) perfect, low-noise, image data to perform the edge-detection on because we can use the Normals and Depth data, which is of course far less noisy than real digital camera images are. Even when performing edge-detection on color data coming from the URP scene's camera (the camera opaque texture) it is still much less noisy than images that were taken in the real world. This has the advantage that even cheap simple edge-detection methods can produce really nice, crisp, sharp and stable outlines when using game engine textures as input!

Choosing Outlines based on capability

Choosing Outlines based on sharpness/quality

Choosing Outlines based on rendering efficiency