Multi Pass Edge

A multi-pass shader in which the second pass renders a simple outline of the geometry.

Multipass Edge

Shader

Shader "Shaders/Material/EdgeMultiPass" {
  Properties {
    _MainTex ("Albedo (RGB)", 2D) = "white" {}
    _OutlineSize ("Outline Size", float) = 0.05
    _OutlineColor ("Outline Color", Color) = (1, 1, 1, 1)
  }
  SubShader {
    Tags { "RenderType" = "Opaque" }

    // Render the normal content as a second pass overlay.
    // This is a normal texture map.
    CGPROGRAM
      #pragma surface surf Standard

      sampler2D _MainTex;

      struct Input {
        float2 uv_MainTex;
      };

      void surf (Input IN, inout SurfaceOutputStandard o) {
        fixed4 c = tex2D (_MainTex, IN.uv_MainTex);
        o.Albedo = c.rgb;
      }
    ENDCG

    // Cull rendered pixels on this surface
    Cull Front

    // Render scaled background geometry
    CGPROGRAM
      #pragma surface surf Standard vertex:vert

      float4 _OutlineColor;
      float _OutlineSize;

      // Linearly expand using surface normal
      void vert (inout appdata_full v) {
        v.vertex.xyz += v.normal * _OutlineSize;
      }

      struct Input {
        float2 uv_MainTex;
      };

      void surf (Input IN, inout SurfaceOutputStandard o) {
        o.Albedo = _OutlineColor.rgb;
      }
    ENDCG
  }
  FallBack "Diffuse"
}

Shader Notes

Notice the pair of CGPROGRAM / ENDCG blocks in this material shader.

This creates a multi-pass shader in which the geometry is processed and rendered twice; in this case the second pass is a simple coloured scaled version of the original geometry, generating a nice 'edge' around it.

Although this technique only works for small scale values, its quite effective.

The Cull Front call prevents the second pass, which renders the outline, from replacing the pixels which have already been rendered in the first pass.

In many cases, an edge lit single pass may be more useful.