Unity Shader入门精要 阅读笔记十七
2018-03-05 18:51
330 查看
前言
这里讲边缘检测这一节中的笔记内容。边缘检测这里更多的用到了图像学的一些基本内容,包括卷积核,索贝尔算子等等一些内容。整个流程还是比较清晰的。边缘检测算法
获取到屏幕渲染的颜色缓冲之后,将屏幕中的像素用索贝尔算子进行卷积操作,卷积的结果就是当前像素的一个导数。这里说导数其实可能比较难懂,说变化程度应该会好理解一些。如果这里颜色突变的厉害那么他的变化程度就会大一些,如果颜色变化比较平坦,那么变换程度就会小一些,计算的结果也会小一些。这里需要将一些索贝尔算子和图像卷积操作。
⎡⎣⎢−101−202−101⎤⎦⎥=Gx[−1−2−1000121]=Gx
⎡⎣⎢−1−2−1000121⎤⎦⎥=Gy[−101−202−101]=Gy
大家在看书写代码的时候可能会有疑问,正文中写的Gx有值的部分明明是在列上面,第二列为0,其他列有值,Gy为第二行为0.但是在代码中Gx与Gy似乎反了。
在图像处理(冈萨雷斯)这本书里是这样描述Gx与Gy的:
算子与像素相乘,第三行与第一行间的差距接近与x方向上的微分,第三列与第一列间的差接近y方向的微分。(P107,Edition 2);
同时在编码中还有一个问题,不是说卷积操作的时候需要先将算子转180度,然后再对于相乘相加吗?怎么编码的时候又直接对应相乘相机没有旋转了?
答:(图像处理(冈萨雷斯)P92,Edi 2)中提到,线性空间滤波与频率域中的卷积概念类似,因此线性空间滤波也称为“掩膜与图像的卷积”。“滤波掩膜”也被称为“卷积模板”,“卷积核”。
也就是说图像与算子的卷积实际上是一种线性空间滤波,而这种滤波的表达形式就是对应相乘相加。
这里给出mxn大小的线性滤波掩膜的表达式:
g(x,y)=∑as=−a∑bt=−bw(s,t)f(x+s,y+t)g(x,y)=∑s=−aa∑t=−bbw(s,t)f(x+s,y+t)
看到这里应该知道为什么要这样来计算了吧。
边缘检测
边缘检测代码上一波:Shader "Custom/8/8.1.2" {//边缘检测 Properties{ _MainTex("Main Texture",2D) = "white"{} _EdgeColor("Edge Color",color) = (1,1,1,1) _BackgroundColor("Background",Color) = (1,1,1,1) _EdgeOnly("edgeOnly",float) = 1 } SubShader{ Pass{ ZTest Always ZWrite Off Cull Off CGPROGRAM #pragma vertex vert #pragma fragment frag #include "UnityCG.cginc" sampler _MainTex; float4 _MainTex_TexelSize;//纹素 float4 _EdgeColor; float4 _BackgroundColor; float _EdgeOnly; struct v2f { float4 pos : SV_POSITION; float2 uv[9] : TEXCOORD0; }; fixed luminance(fixed3 color) { return 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b; } half sobel(v2f i) { //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 }; 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 }; float4 texColor; float edgex = 0; float edgey = 0; for (int it = 0; it < 9; it++) { texColor = luminance(tex2D(_MainTex, i.uv[it])); edgex += texColor * Gx[it]; edgey += texColor * Gy[it]; } return 1 - abs(edgex) - abs(edgey); } v2f vert(appdata_img v) { v2f o; o.pos = UnityObjectToClipPos(v.vertex); //求纹素 float2 uv = v.texcoord; 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; } fixed4 frag(v2f i) :SV_Target{ half edge = sobel(i); fixed4 withEdgeColor = lerp(_EdgeColor, tex2D(_MainTex, i.uv[4]), edge); fixed4 onlyEdgeColor = lerp(_EdgeColor, _BackgroundColor, edge); return lerp(withEdgeColor, onlyEdgeColor, _EdgeOnly); } ENDCG } } FallBack Off }
shader代码没有难的地方,唯一需要说的是shader中要避免if和循环语句。
相关文章推荐
- Unity Shader入门精要 阅读笔记十一
- Unity Shader入门精要 阅读笔记一
- Unity Shader入门精要 阅读笔记七
- Unity Shader入门精要 阅读笔记四
- Unity Shader入门精要 阅读笔记九
- Unity Shader入门精要学习笔记 - 第5章 开始 Unity Shader 学习之旅
- Unity Shader入门精要 阅读笔记十
- Unity Shader入门精要笔记(二):Unity Shader基础
- [置顶] Unity Shader入门精要学习笔记 - 第2章 渲染流水线
- Unity Shader入门精要 阅读笔记八
- Unity Shader入门精要学习笔记 - 第15章 使用噪声
- Unity Shader入门精要 阅读笔记 前言
- Unity Shader入门精要学习笔记 - 第14章 非真实感渲染
- Unity Shader入门精要学习笔记 - 第3章 Unity Shader 基础
- Unity Shader入门精要学习笔记 - 第9章 更复杂的光照
- Unity Shader入门精要学习笔记 - 第11章 让画面动起来
- Unity Shader入门精要笔记(十一):基础单张纹理
- Unity Shader入门精要学习笔记 - 第10章 高级纹理
- Unity Shader入门精要笔记(十三):法线纹理
- Unity Shader入门精要学习笔记 - 第15章 使用噪声