Shader屏幕后處理效果


Shader屏幕后處理效果

邊緣檢測:


边缘检测的原理是利用一些边缘检测算子对图像进行卷积操作(卷积操作就是使用一个卷积核对一张图像的每一个像素进行一系列的操作,倦急核通常是一个四方形网格结构,例如2×2,3×3的方形区域,该区域内每个方格都有一个权重值。当对图像中的某个像素进行卷积时,我们会把卷积核的中心放置在该像素上,如下图,翻转之后再依次进行计算核中的每个元素和其覆盖的图像像素值的乘积并求和,得到的结果就是改为只的新像素值)

常见的边缘检测算子

卷积操作的神奇指出 在于选择的卷积核,用于边缘检测的卷积核(边缘检测算子)是什么?  首先想一下  如果相邻像素之间存在差别明显的颜色,亮度等属性,那么他们之间应该有一条边界。这种相邻像素之间的差值可以用梯度来表示,边缘处的梯度绝对值比较大,所以,就出现下面几种边缘检测算子;

下面请看注释:
Shader "MyShader/OutLine"
{
	Properties{
		_MainTex("MainTexture",2D) = "White"{}
		_LineColor("OutLineColor",color) = (1,1,1,1)
		_BackGroundColor("BackGroundColor",color) = (1,1,1,1)
		_EdgeOnly("EdgeOnly",float)=3
	}
		SubShader{
			Tags{"RenderType" = "Transparent"}
		Pass
		{
			Cull off
			ZTest Always
			ZWrite off
			CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
			sampler2D  _MainTex;
		float4 _MainTex_TexelSize;
		fixed4 _LineColor;
		fixed4 _BackGroundColor;
		float _EdgeOnly;
			struct a2v {
					fixed4 vertex : POSITION;
					fixed2 uv : TEXCOORD;
				};
			struct v2f {
				fixed4 pos : SV_POSITION;
				fixed2 uv[9]:TEXCOORD;//对应了使用Sobel算子采样是需要的
				//九个领域纹理坐标
			};
			fixed luminance(fixed4 color)
			{
				return color.r*0.21 + color.g*0.37 + color.b*0.44;
			}
			half sobel(v2f v)  
			{
				const half Gx[9] = { 1,2,1,
					0,0,0,
					-1,-2,-1
				};
				const half Gy[9] = { 1,0,-1,
					2,0,-2,
					1,0,-1 };
				half texColor;
				half edgeX = 0;
				half edgeY = 0;
				for (int i = 0; i < 9; i++)
				{
					texColor = luminance(tex2D(_MainTex, v.uv[i])); 
					edgeX += texColor*Gx[i];
					edgeY += texColor*Gy[i];

				}
				return 1 - abs(edgeX) - abs(edgeY);
			}
			v2f vert(a2v v)
			{
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv[0] = v.uv + _MainTex_TexelSize.xy*fixed2(-1,1);
				o.uv[1] = v.uv + _MainTex_TexelSize.xy*fixed2(0, 1);
				o.uv[2] = v.uv + _MainTex_TexelSize.xy*fixed2(1, 1);
				o.uv[3] = v.uv + _MainTex_TexelSize.xy*fixed2(-1,0);
				o.uv[4] = v.uv + _MainTex_TexelSize.xy*fixed2(0, 0);
				o.uv[5] = v.uv + _MainTex_TexelSize.xy*fixed2(1, 0);
				o.uv[6] = v.uv + _MainTex_TexelSize.xy*fixed2(-1, -1);
				o.uv[7] = v.uv + _MainTex_TexelSize.xy*fixed2(0, -1);
				o.uv[8] = v.uv + _MainTex_TexelSize.xy*fixed2(1,-1);
				return o;
			}
			fixed4 frag(v2f v):SV_Target
			{
				half edge = sobel(v);  //计算梯度值edge
			fixed4 withEdgeColor = lerp(_LineColor, tex2D(_MainTex, v.uv[0]), edge);
			fixed4 onlyEdgeColor = lerp(_LineColor, _BackGroundColor,edge);
			
			return lerp(withEdgeColor, onlyEdgeColor, _EdgeOnly);
			}
	
			
			ENDCG
		}
	}
}