Outline Shader/ 2D图片描边

前情提要

之前公司业务上有成千上万的图片需要后期添加描边,让美术重新制作描边效果图片,工单太多啦不现实。随即使用Shader实现效果

边缘检测描边

Shader "UICustom/Outline"
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _lineWidth("lineWidth",Range(0,10)) = 1
        _lineColor("lineColor", Color) = (1,1,1,1)
    }
    SubShader
    {
        Tags { "RenderType"="Transparent" }
        Blend SrcAlpha OneMinusSrcAlpha

        Pass
        {
            HLSLPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include  "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

            struct VertexInput
            {
                float4 vertex : POSITION;
                float2 uv : TEXCOORD0;
            };

            struct VertexOutput
            {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            VertexOutput vert (VertexInput v)
            {
                VertexOutput o;
                o.vertex = TransformObjectToHClip(v.vertex);
                o.uv = v.uv;
                return o;
            }

            sampler2D _MainTex;
            float4 _MainTex_TexelSize;
            float _lineWidth;
            float4 _lineColor;

            float4 frag(VertexOutput i) : SV_Target{
                float4 col = tex2D(_MainTex,i.uv);

                // 采样周围四个点
                float2 up = i.uv + float2(0,1) * _lineWidth * _MainTex_TexelSize.xy;
                float2 down = i.uv + float2(0,-1) * _lineWidth * _MainTex_TexelSize.xy;
                float2 left = i.uv + float2(-1, 0) * _lineWidth * _MainTex_TexelSize.xy;
                float2 right = i.uv + float2(1,0) * _lineWidth * _MainTex_TexelSize.xy;

                // 边缘检测思路 透明度为零就是边缘
                float w = tex2D(_MainTex, up).a * tex2D(_MainTex, down).a * tex2D(_MainTex, left).a * tex2D(_MainTex, right).a;

                col.rgb = lerp(_lineColor, col.rgb, w);
                return col;
            }
            ENDHLSL
        }
    }
}

边缘识别的算法也可以尝试用半圆范围识别,这里只是提供简单思路

新的问题

由于UI图大量的透明通道清理不足,应该透明度为0的地方,有零星几个像素alpha值不统一(无法用alpha值小于约定值来实现,单纯是图片没有清理过)