πŸ”³ CosterGraphics.Systems.OutlineSystem

The Majestic Outlion in All of its Splendor

A full-screen, URP-based outline effect for 3D GameObjects using a ScriptableRendererFeature, ScriptableRenderPasses, and the Outline3D component.

This system allows you to draw sharp, controllable outlines around specific objects without requiring custom shaders on the objects themselves and without using 'inverted hull' mesh copies. Outline texture masks are generated in dedicated mask passes and then calculated and composited in screen-space using configurable materials and full-screen Shader Graph shaders.



🌍 Overview

The OutlineSystem consists of three core components:

  1. Outline3D : MonoBehaviour
    A MonoBehaviour added to any GameObject you want to outline.
    It marks the object for inclusion into the outline mask pass.

  2. Outline3DRendererFeature : ScriptableRendererFeature
    A custom URP Renderer Feature that:

    • collects all objects with the Outline3D component
    • renders them to an off-screen mask
    • applies a full-screen composite pass to draw the outline
  3. Outline Materials / Shader Graph Shaders
    A ShaderGraph (e.g., SG_OutlineComposite) and material used by the renderer feature to generate the final outline.
    Common parameters include:

    • Outline thickness
    • Outline color
    • Blur/soften
    • Edge detection or dilation strength

🧩 Outline System Components

Outline3D (MonoBehaviour)

Marks a GameObject as outline-eligible.

Responsibilities:

  • Registers itself with the renderer feature
  • Provides access to its Renderers
  • Stores per-object outline settings (color, thickness, etc.)

Outline3DURPRendererFeature (ScriptableRendererFeature)

Handles all inspection, rendering and compositing work.

Typical passes:

1. Mask Pass

  • Draws all Outline3D objects into a dedicated mask texture
  • Produces a binary white silhouette
  • Optional: also capture depth or normals for improved accuracy

2. Composite Pass

  • Full-screen pass
  • Samples mask
  • Dilates / colors / blends
  • Writes result onto camera color buffer


🎨 ShaderGraph β€” Composite Shader Tips

For best results:

  • Use a dilation kernel (e.g., sampling 8 neighbors)
  • Multiply dilation by OutlineThickness
  • Multiply output color by OutlineColor
  • Add result to camera color input

For smoother outlines:

  • Add a tiny blur after dilation
  • Or apply inner + outer double-pass dilation


πŸ“Œ Example Usage

    public class Enemy : MonoBehaviour
    {
        private Outline3D outline;

        void Start()
        {
            outline = gameObject.AddComponent<Outline3D>();
            outline.Color = Color.red;
            outline.Thickness = 2f;
        }
    } 

πŸ“ Additional Notes

  • Outlines are purely a full-screen post-process, so they won’t modify materials or meshes.
  • The system supports any number of outlined objects.
  • Performance is excellent because the mask renders only simple unlit silhouettes.
  • You can extend this system with multiple outline layers, glow effects, or animated outline thickness.

🧩 Depth Bias in the Mask Pass

When generating the mask texture for the outline system, the mask geometry is rendered in a dedicated pass. This pass typically uses LessEqual depth testing so the mask correctly follows the exact visible surfaces of the scene geometry. However, rendering with LessEqual introduces a subtle but important problem:

❗ Floating-Point Precision (ULP) Issues

Depth buffers store values using quantized floating-point precision. Two fragments that should have the same depth often differ by a few ULPs (Units in the Last Place).
This tiny difference means:

  • Pixels that should pass LessEqual sometimes fail the test
  • Mask edges show holes, flickering, or thin broken borders
  • Outlines become unstable or contain noise

Using Less is not an option because the mask geometry needs to render when depths are exactly equal, not only when strictly closer.

🎯 The Solution: Apply a Small Depth Bias

During the Mask Pass, the renderer applies a tiny depth bias, which nudges the mask geometry slightly toward the camera. This guarantees that its depth values are always marginally smaller than the underlying scene depth, eliminating ULP inconsistencies.

The effect:

  • βœ” The mask always passes depth testing
  • βœ” Edges become stable and clean
  • βœ” No gaps or flickering
  • βœ” No dependency on floating-point precision behavior

βš™οΈ How the Bias Is Applied

URP allows setting a temporary global depth bias:

cmd.SetGlobalDepthBias(slopeBias, depthBias);

A typical configuration:

  • slopeBias = 0
  • depthBias = -1f (very small offset toward the camera)

After the mask pass completes, the bias is reset:

    cmd.SetGlobalDepthBias(0, 0);

πŸ”’ Why This Is Safe

  • The bias is scoped only to the mask pass.
  • Resetting immediately ensures no effect on:
    • Unity’s built-in rendering
    • Other renderer features
    • Shadows, lighting, or post-processing
  • The outline system gains stable, predictable mask rendering with no side effects.

🧠 Summary

Using a tiny depth bias is a deliberate and necessary fix to overcome floating-point limitations in depth testing. It ensures the mask is rendered reliably and produces clean, artifact-free outlines without altering the main rendering pipeline.



Basic, Advanced & Pro Feature Comparison

Outline System Basic Features:

  • Outline3D MonoBehaviour Component (Outline3D)
  • Color Mask Based Silhouette Outlines
  • Depth & Normals Based Contour outlines
  • Hybrid Silhouette & Contour Outlines

Outline System Advanced Features:

  • Advanced Outline3D MonoBehavour Component (Outline3DAdv)
  • Advanced Outline3D Renderer Features (Outline3DAdvRendererFeature)
  • Renderer Feature IDs (Render different objects with different types of outlines easily)
  • ObjectID Based Outlines
  • Advanced Edge Detection Kernel Based Outlines (Cross, Gaussian, Laplacian, Sobel, Scharr)
  • Comes with Shader Graph Sub-Graphs for each of the kernels to create your own Composite shader with
  • Advanced depth masked outline shaders using depth tested and non depth tested masks

Outline System Pro Features:

  • OutlineFeature Profile Scriptable Objects System (Replaces Feature IDs?)
  • Ray Marched Distance Field Based Outlines
  • Other pro stuff