Search Unity

Question Pixel perfect outline for UI text

Discussion in 'Shaders' started by Azurexis, May 14, 2020.

  1. Azurexis

    Azurexis

    Joined:
    Oct 26, 2018
    Posts:
    7
    Heyo!

    I'm trying to make a shader to have a pixel perfect outline. What I'm trying to achieve is the right outlining:



    It basically is the left font with a bunch of different offsets. I managed to make it work in 4 directions, and in 8 direction, like this:



    I tried following various tutorials but couldn't get the top example to work.
    This is the shader code I have for the 8-direction outline:

    Code (CSharp):
    1. Shader "Outline/Sharp"
    2. {
    3.     Properties
    4.     {
    5.         _MainTex("Texture", 2D) = "white" {}
    6.         _OutlineColor("Outline Color", Color) = (1,1,1,1)
    7.     }
    8.         SubShader
    9.         {
    10.             Tags
    11.             {
    12.                 "RenderType" = "Transparent"
    13.             }
    14.  
    15.             Blend SrcAlpha OneMinusSrcAlpha
    16.  
    17.             Pass
    18.             {
    19.                 CGPROGRAM
    20.                 #pragma vertex vert
    21.                 #pragma fragment frag
    22.  
    23.                 #include "UnityCG.cginc"
    24.  
    25.                 struct appdata
    26.                 {
    27.                     float4 vertex : POSITION;
    28.                     float2 uv : TEXCOORD0;
    29.                 };
    30.  
    31.                 struct v2f
    32.                 {
    33.                     float2 uv : TEXCOORD0;
    34.                     float4 vertex : SV_POSITION;
    35.                 };
    36.  
    37.                 sampler2D _MainTex;
    38.                 float4 _MainTex_ST;
    39.                 float4 _MainTex_TexelSize;
    40.  
    41.                 fixed4 _OutlineColor;
    42.  
    43.                 v2f vert(appdata v)
    44.                 {
    45.                     v2f o;
    46.                     o.vertex = UnityObjectToClipPos(v.vertex);
    47.                     o.uv = TRANSFORM_TEX(v.uv, _MainTex);
    48.                     return o;
    49.                 }
    50.  
    51.                 fixed4 frag(v2f i) : SV_Target
    52.                 {
    53.                     fixed4 col = tex2D(_MainTex, i.uv);
    54.  
    55.                     fixed upLeftPixel = tex2D(_MainTex, i.uv + float2(-_MainTex_TexelSize.x, _MainTex_TexelSize.y)).a;
    56.                     fixed leftPixel = tex2D(_MainTex, i.uv + float2(-_MainTex_TexelSize.x, 0)).a;
    57.                     fixed bottomLeftPixel = tex2D(_MainTex, i.uv + float2(-_MainTex_TexelSize.x, -_MainTex_TexelSize.y)).a;
    58.                     fixed upPixel = tex2D(_MainTex, i.uv + float2(0, _MainTex_TexelSize.y)).a;
    59.                     fixed upRightPixel = tex2D(_MainTex, i.uv + float2(_MainTex_TexelSize.x, _MainTex_TexelSize.y)).a;
    60.                     fixed rightPixel = tex2D(_MainTex, i.uv + float2(_MainTex_TexelSize.x, 0)).a;
    61.                     fixed bottomRightPixel = tex2D(_MainTex, i.uv + float2(_MainTex_TexelSize.x, -_MainTex_TexelSize.y)).a;
    62.                     fixed bottomPixel = tex2D(_MainTex, i.uv + float2(0, -_MainTex_TexelSize.y)).a;
    63.  
    64.                     fixed outline = max(max(max(upLeftPixel, bottomLeftPixel), max(upRightPixel, bottomRightPixel)), max(max(leftPixel, upPixel), max(rightPixel, bottomPixel))) - col.a;
    65.  
    66.                     return lerp(col, _OutlineColor, outline);
    67.                 }
    68.                 ENDCG
    69.             }
    70.         }
    71. }
    When I change this line

    Code (CSharp):
    1. fixed bottomPixel = tex2D(_MainTex, i.uv + float2(0, -_MainTex_TexelSize.y)).a;
    To this:

    Code (CSharp):
    1. fixed bottomPixel = tex2D(_MainTex, i.uv + float2(0, -_MainTex_TexelSize.y * 2)).a;
    The offset gets drawn, but instead of the bottom it gets drawn on the top side of the text. What I don't understand is, why does this work with 1px offset but not with a 2px one?