unity-shader 2D精灵图描边效果

前言

今天我们来实现一个简单的2D精灵图描边效果,效果图如下:

unity-shader 2D精灵图描边效果_第1张图片

准备工作:

首先我们先打开unity新建一个场景,导入一个图片,并把该图片设置为Sprite类型,如图:

unity-shader 2D精灵图描边效果_第2张图片   unity-shader 2D精灵图描边效果_第3张图片

实现思路:

思路其实很简单,可以通过判断该像素周围是否有透明度为 0的值,如果有,则说明该像素位于边缘。

所以我们需要打开alpha blend,即: Blend SrcAlpha OneMinusSrcAlpha,并且加入渲染队列,

Tags{
     "Queue" = "Transparent"
}
Blend SrcAlpha OneMinusSrcAlpha

下面我们开始编写片元着色器,顶点着色器就是常规的顶点坐标变换,这里就不贴代码了,主要来看看片元着色器:

// ---------------------------【片元着色器】---------------------------
fixed4 frag (VertexOutput i) : SV_Target
{
    fixed4 col = tex2D(_MainTex, i.uv);
    // 采样周围4个点
    float2 up_uv = i.uv + float2(0,1) * _lineWidth * _MainTex_TexelSize.xy;
    float2 down_uv = i.uv + float2(0,-1) * _lineWidth * _MainTex_TexelSize.xy;
    float2 left_uv = i.uv + float2(-1,0) * _lineWidth * _MainTex_TexelSize.xy;
    float2 right_uv = i.uv + float2(1,0) * _lineWidth * _MainTex_TexelSize.xy;
    // 如果有一个点透明度为0 说明是边缘
    float w = tex2D(_MainTex,up_uv).a * tex2D(_MainTex,down_uv).a * tex2D(_MainTex,left_uv).a * tex2D(_MainTex,right_uv).a;

    if(w == 0){
       col.rgb = _lineColor;
    }
   
    return col;
}

_MainTex_TexelSize:贴图像素尺寸大小
我们可以通过该属性计算出周围(上下左右)的像素坐标,然后判断有没有透明度为0的值。
如果为0就返回边框颜色。

效果如下:

unity-shader 2D精灵图描边效果_第4张图片

虽然我们实现了该功能,但是我们仔细观察会发现边缘锯齿很严重,不平滑。我们可以做下优化,利用插值来平滑过渡,

最终完整Shader代码如下:

// ---------------------------【2D 描边效果】---------------------------
// create by 长生但酒狂
Shader "lcl/shader2D/outline"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _lineWidth("lineWidth",Range(0,10)) = 1
        _lineColor("lineColor",Color)=(1,1,1,1)
    }
    // ---------------------------【子着色器】---------------------------
    SubShader
    {
        // 渲染队列采用 透明
        Tags{
            "Queue" = "Transparent"
        }
        Blend SrcAlpha OneMinusSrcAlpha
        
        Pass
        {
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"
            //顶点着色器输入结构体 
            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 = UnityObjectToClipPos(v.vertex);
                o.uv = v.uv;
                return o;
            }

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

            // ---------------------------【片元着色器】---------------------------
            fixed4 frag (VertexOutput i) : SV_Target
            {
                fixed4 col = tex2D(_MainTex, i.uv);
                // 采样周围4个点
                float2 up_uv = i.uv + float2(0,1) * _lineWidth * _MainTex_TexelSize.xy;
                float2 down_uv = i.uv + float2(0,-1) * _lineWidth * _MainTex_TexelSize.xy;
                float2 left_uv = i.uv + float2(-1,0) * _lineWidth * _MainTex_TexelSize.xy;
                float2 right_uv = i.uv + float2(1,0) * _lineWidth * _MainTex_TexelSize.xy;
                // 如果有一个点透明度为0 说明是边缘
                float w = tex2D(_MainTex,up_uv).a * tex2D(_MainTex,down_uv).a * tex2D(_MainTex,left_uv).a * tex2D(_MainTex,right_uv).a;

                // if(w == 0){
                    //    col.rgb = _lineColor;
                // }
                // 和原图做插值
                col.rgb = lerp(_lineColor,col.rgb,w);
                return col;
            }
            ENDCG
        }
    }
}

最终效果图对比:

unity-shader 2D精灵图描边效果_第5张图片

最后

最后欢迎来我的GitHub Star,谢谢!
里面有我平时学习unity shader过程中实现的一些特效demo。

你可能感兴趣的:(Unity,Shader,Unity3D,unity,shader)