Shader屏幕后处理效果
发表于2018-04-12
屏幕后处理效果即在渲染完场景得到屏幕图像后在进行处理的效果,利用Sobel 算子在屏幕空间中对图像进行边缘检测,以及图像处理中常用边缘检测算子,实现描边效果。
边缘检测的原理是利用一些边缘检测算子对图像进行卷积操作(卷积操作就是使用一个卷积核对一张图像的每一个像素进行一系列的操作,倦急核通常是一个四方形网格结构,例如2x2,3x3的方形区域,该区域内每个方格都有一个权重值。当对图像中的某个像素进行卷积时,我们会把卷积核的中心放置在该像素上,如下图,翻转之后再依次进行计算核中的每个元素和其覆盖的图像像素值的乘积并求和,得到的结果就是改为只的新像素值)
常见的边缘检测算子
卷积操作的神奇指出 在于选择的卷积核,用于边缘检测的卷积核(边缘检测算子)是什么? 首先想一下 如果相邻像素之间存在差别明显的颜色,亮度等属性,那么他们之间应该有一条边界。这种相邻像素之间的差值可以用梯度来表示,边缘处的梯度绝对值比较大,所以,就出现下面几种边缘检测算子;
下面请看注释:
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 } } }