Unity ShaderLab特效教程 适用于贴图、sprite和ugui的2d着色器实例 代码+详解注释 【可调节力度、uv,可选择Sobel、Roberts、Canny算子的边缘检测算法效果】

边缘检测效果的shader

【特点【:支持调整力度,可选两种卷积算子的边缘检测
【原理【:使用卷积的方法,每次检测像素时都计算他垂直或水平方向的周围像素。根据实现定义好的权重,判定是否存在水平或垂直的边缘像素。如果值足够大小则认为是边缘像素,就进行特殊处理。
【笑狗图】:
在这里插入图片描述

Shader "Custom/sobel" {
	Properties {
		_MainTex ("贴图", 2D) = "white" {}
		_Size("力度", range(0.00,2000)) = 40
        _IsSobel("Sobel or Roberts or Canny", range(0.0,3.0)) = 0
		
	}
	SubShader {
		pass{
            Tags{"LightMode"="ForwardBase" }
            Cull off
            CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #include "UnityCG.cginc"

                float _Size;
                float _IsSobel;
                sampler2D _MainTex;
                //用于配合TRANSFORM_TEX
                float4 _MainTex_ST;

                struct v2f {
                    float4 pos:SV_POSITION;
                    float2 uv:TEXCOORD0;
                };
                //顶点着色器
                v2f vert (appdata_full v) {
                    v2f o;
                    o.pos=UnityObjectToClipPos(v.vertex);
                    //将模型顶点的uv和Tiling、Offset进行运算求得最终的uv
                    o.uv = TRANSFORM_TEX(v.texcoord,_MainTex);
                    return o;
                }

                //边缘检测因子运算
                float4 Get_Sobel(sampler2D mainTex, float2 uv){
                    //Sobel算子 x
                    float g_x[9] = 
                    {-1, 0, 1,
                    -2, 0, 2,
                    -1, 0, 1};
                    //Sobel算子 y
                    float g_y[9] = 
                    {1, 2, 1,
                    0, 0, 0,
                    -1,-2,-1};  
                    //要输出的颜色
                    float GX = 0;
                    float GY = 0;

                    //灰度因子
                    float3 lum = float3(0.2125, 0.7154, 0.0721);
                    //遍历3*3 算子计算所有的像素]
                    int gCount = 0;
                    //0 1 2 该矩阵处理顺序,4是当前像素点
                    //3 4 5 
                    //6 7 8 
                    for (int i = -1; i < 2; i++)
                    {
                        for (int j = -1; j < 2; j++)
                        {
                            //获取包含当前像素与其周围在内的9个像素uv位置, uv+ (可调节的偏移)
                            float2 new_uv = float2(uv.x + j / _Size , uv.y + i / _Size);
                            //根据uv定位获取该uv位置的像素信息
                            float4 color = tex2D(mainTex, new_uv);
                            // luminance点积,求出亮度值(黑白图)
                            float _g = dot(color.rgb, lum);
                            //当前亮度值 分别乘以x、y的算子,得到边缘数据
                            GX += (_g * g_y[gCount]);
                            GY += (_g * g_x[gCount]);
                            gCount += 1;
                        }
                    }

                    //length的内部算法就是灰度公式的算法,欧几里得长度
                    float4 color = length(float2(GX, GY)); 
                    //过滤器
                    if(color.r < 0.5){
                        //区域区域涂黑
                        color = 0;
                        //透明测试,其余区域不显示
                        //clip(color.a - 1);
                    }
                    return color;
                }
                // Roberts算子
                float4 Get_Roberts(sampler2D mainTex, float2 uv){
                    //Sobel算子 x
                    float g_x[4] = 
                    {1, 0,
                    0, -1};
                    //Sobel算子 y
                    float g_y[4] = 
                    {0, 1, 
                    -1, 0};  
                    //要输出的颜色
                    float GX = 0;
                    float GY = 0;

                    //灰度因子
                    float3 lum = float3(0.2125, 0.7154, 0.0721);
                    //遍历3*3 算子计算所有的像素]
                    int gCount = 0;
                    //0 1 2 该矩阵处理顺序,4是当前像素点
                    //3 4 5 
                    //6 7 8 
                    for (int i = -1; i < 1; i++)
                    {
                        for (int j = -1; j < 1; j++)
                        {
                            //获取包含当前像素与其周围在内的9个像素uv位置, uv+ (可调节的偏移)
                            float2 new_uv = float2(uv.x + j / _Size , uv.y + i / _Size);
                            //根据uv定位获取该uv位置的像素信息
                            float4 color = tex2D(mainTex, new_uv);
                            // luminance点积,求出亮度值(黑白图)
                            float _g = dot(color.rgb, lum);
                            //当前亮度值 分别乘以x、y的算子,得到边缘数据
                            GX += (_g * g_y[gCount]);
                            GY += (_g * g_x[gCount]);
                            gCount += 1;
                        }
                    }
                    
                    //length的内部算法就是灰度公式的算法,欧几里得长度
                    float4 color = length(float2(GX, GY)); 
                    //过滤器
                    if(color.r < 0.5){
                        color = 0;
                    }
                    return color;
                }
                // Canny算子
                float4 Get_Canny(sampler2D mainTex, float2 uv){
                    //Sobel算子 x
                    float g_x[4] = 
                    {-1, 1,
                     -1, 1};
                    //Sobel算子 y
                    float g_y[4] = 
                    {1, 1, 
                    -1, -1};  
                    //要输出的颜色
                    float GX = 0;
                    float GY = 0;

                    //灰度因子
                    float3 lum = float3(0.2125, 0.7154, 0.0721);
                    //遍历3*3 算子计算所有的像素]
                    int gCount = 0;
                    //0 1 2 该矩阵处理顺序,4是当前像素点
                    //3 4 5 
                    //6 7 8 
                    for (int i = -1; i < 1; i++)
                    {
                        for (int j = -1; j < 1; j++)
                        {
                            //获取包含当前像素与其周围在内的9个像素uv位置, uv+ (可调节的偏移)
                            float2 new_uv = float2(uv.x + j / _Size , uv.y + i / _Size);
                            //根据uv定位获取该uv位置的像素信息
                            float4 color = tex2D(mainTex, new_uv);
                            // luminance点积,求出亮度值(黑白图)
                            float _g = dot(color.rgb, lum);
                            //当前亮度值 分别乘以x、y的算子,得到边缘数据
                            GX += (_g * g_y[gCount]);
                            GY += (_g * g_x[gCount]);
                            gCount += 1;
                        }
                    }
                    
                    //length的内部算法就是灰度公式的算法,欧几里得长度
                    float4 color = length(float2(GX, GY)); 
                    //过滤器
                    if(color.r < 0.5){
                        color = 0;
                    }
                    return color;
                }
                //片元着色器
                float4 frag(v2f o):SV_Target
                {
                    fixed4 outColor;
                    if(_IsSobel > 0 && _IsSobel < 1){
                        outColor = Get_Sobel(_MainTex, o.uv);    
                    }
                    if(_IsSobel > 1 && _IsSobel < 2){
                        outColor = Get_Roberts(_MainTex, o.uv);   
                    }
                    if(_IsSobel > 2 && _IsSobel < 3){
                        outColor = Get_Canny(_MainTex, o.uv);   
                    }
                    return outColor;
                }
            ENDCG
        }
    }
}


发布了138 篇原创文章 · 获赞 37 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/lengyoumo/article/details/104239967
今日推荐