Unity-Shader - 2DSprite描边效果

实现一个简单的2D精灵图描边效果,效果如下

实现思路:

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

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

csharp 复制代码
Tags{
     "Queue" = "Transparent"
}
Blend SrcAlpha OneMinusSrcAlpha

根据图片的Alpha值边缘判定,向内扩一段距离做边缘,颜色设置为描边颜色;

片元着色阶段,向上下左右四个方向做检测,有一个点的透明度为0,判定为边缘;

csharp 复制代码
fixed4 frag(v2f i) : SV_Target
			{
				fixed4 col = tex2D(_MainTex, i.uv);
				// 采样周围4个点
				float2 up_uv = i.uv + float2(0, 1) * _LineWidth * 1 / 10 * _MainTex_ST.xy;
				float2 down_uv = i.uv + float2(0,-1) * _LineWidth * 1 / 10 * _MainTex_ST.xy;
				float2 left_uv = i.uv + float2(-1,0) * _LineWidth * 1 / 10 * _MainTex_ST.xy;
				float2 right_uv = i.uv + float2(1,0) * _LineWidth * 1 / 10 * _MainTex_ST.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 = lerp(_LineColor * _Intensity, col.rgb, w);
				}

				return col;
			}

如果图片内容恰好铺满整张图,没有alpha值,方法不适用

outline

可以和原图做插值,根据边缘判断来混合线的颜色和原图颜色

完整shader如下

csharp 复制代码
Shader "shader2D/outline"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}  // 主纹理属性,用于存储2D纹理
        _lineWidth("lineWidth",Range(0,10)) = 1  // 线宽属性,范围在0到10之间,默认值为1
        _lineColor("lineColor",Color)=(1,1,1,1)  // 线的颜色属性,RGBA格式,默认为白色
    }
    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;

                // 和原图做插值,根据边缘判断来混合线的颜色和原图颜色
                col.rgb = lerp(_lineColor,col.rgb,w);

                return col;
            }
            ENDCG
        }
    }
}
相关推荐
小贺儿开发8 小时前
Unity3D 智慧城市管理平台
数据库·人工智能·unity·智慧城市·数据可视化
June bug1 天前
【领域知识】休闲游戏一次发版全流程:Google Play + Apple App Store
unity
星夜泊客1 天前
C# 基础:为什么类可以在静态方法中创建自己的实例?
开发语言·经验分享·笔记·unity·c#·游戏引擎
dzj20211 天前
PointerEnter、PointerExit、PointerDown、PointerUp——鼠标点击物体,则开始旋转,鼠标离开或者松开物体,则停止旋转
unity·pointerdown·pointerup
心前阳光1 天前
Unity 模拟父子关系
android·unity·游戏引擎
在路上看风景1 天前
26. Mipmap
unity
咸鱼永不翻身1 天前
Unity视频资源压缩详解
unity·游戏引擎·音视频
在路上看风景1 天前
4.2 OverDraw
unity
在路上看风景1 天前
1.10 CDN缓存
unity
ellis19702 天前
Unity插件SafeArea Helper适配异形屏详解
unity