【012-Shader-边缘检测】

// 边缘检测
/**
边缘检测实质上就是通过对图像的卷积的结果
Sobel算子:
Gx = {
    
    
    -1,0,1,
    -2,0,2,
    -1,0,1
}*A
Gy = {
    
    
    -1,-2,-1,
    0,0,0,
    1,2,1,
}*A

A 代表原始图像,Gx和 Gy分别代表经横向及纵向边缘检测的图像

通过以上公式就可以分别计算出横向 和 纵向 的梯度值,即Gx和 Gy,梯度值越大,边缘就越明显。
**/
Shader "Study/16-EdgeShader"
{
    
    
    Properties
    {
    
    
        _MainTex ("Texture", 2D) = "white" {
    
    }

        // 描边程度
		_EdgeOnly ("Edge Only", Range(0,2)) = 1.0

        // 边缘颜色
		_EdgeColor ("Edge Color", Color) = (0, 0, 0, 1)
    }
    SubShader
    {
    
    
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
        Blend SrcAlpha OneMinusSrcAlpha
        Pass
        {
    
    
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            

            sampler2D _MainTex;



            fixed _EdgeOnly;

            fixed4 _EdgeColor;            

            float4 _MainTex_TexelSize;

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

            struct v2f
            {
    
    
                half2 uv[9] : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v)
            {
    
    
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);

                half2 uv = v.uv;
                //计算周围像素的纹理坐标位置,其中4为原始点,
                o.uv[0] = uv + _MainTex_TexelSize.xy * half2(-1,-1);            
                o.uv[1] = uv + _MainTex_TexelSize.xy * half2(0,-1);
                o.uv[2] = uv + _MainTex_TexelSize.xy * half2(1,-1);

                o.uv[3] = uv + _MainTex_TexelSize.xy * half2(-1,0);
                o.uv[4] = uv + _MainTex_TexelSize.xy * half2(0,0);
                o.uv[5] = uv + _MainTex_TexelSize.xy * half2(1,0);

                o.uv[6] = uv + _MainTex_TexelSize.xy * half2(-1,1);
                o.uv[7] = uv + _MainTex_TexelSize.xy * half2(0,1);
                o.uv[8] = uv + _MainTex_TexelSize.xy * half2(1,1);
                
                return o;
            }


            
            // 转换为灰度
            /**
            灰度转换公式:
            Gray  = R*0.299 + G*0.587 + B*0.114
            **/
            fixed toGray(fixed4 col){
    
    
                return  col*fixed3(0.299,0.587,0.114);
            }

            
            // 像素间的梯度值: sobel 算子
            half sobel(v2f i){
    
    
                const half Gx[9] = {
    
    -1,  0,  1,
									-2,  0,  2,
									-1,  0,  1};
				const half Gy[9] = {
    
    -1, -2, -1,
									0,  0,  0,
									1,  2,  1};		
				
				half texColor;
				half edgeX = 0;
				half edgeY = 0;
				for (int it = 0; it < 9; it++) {
    
    
					// 转换为灰度值
					texColor = toGray(tex2D(_MainTex, i.uv[it]));

					edgeX += texColor * Gx[it];
					edgeY += texColor * Gy[it];
				}
				// 合并横向和纵向
				return abs(edgeX) + abs(edgeY);
            }

            fixed4 frag (v2f i) : SV_Target
            {
    
    

                half edge = sobel(i);
                fixed4 texCol = tex2D(_MainTex, i.uv[4]);
				fixed3 edgeColor = lerp( texCol, _EdgeColor,edge);
				edgeColor = lerp(texCol,edgeColor, _EdgeOnly);
				return fixed4(edgeColor,texCol.a) ;
            }
            ENDCG
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_18924323/article/details/124878478