日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

unity 给图片边缘_Unity Shader 屏幕后效果——边缘检测

發(fā)布時間:2025/4/5 编程问答 36 豆豆
生活随笔 收集整理的這篇文章主要介紹了 unity 给图片边缘_Unity Shader 屏幕后效果——边缘检测 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

關(guān)于屏幕后效果的控制類詳細見之前寫的另一篇博客:

這篇主要是基于之前的控制類,實現(xiàn)另一種常見的屏幕后效果——邊緣檢測。

概念和原理部分:

首先,我們需要知道在圖形學(xué)中經(jīng)常處理像素的一種操作——卷積。

卷積操作的實質(zhì)在于,對于圖像中的每個像素與其周圍的像素進行的重新融合計算行為,以得到不同的像素處理效果,例如銳化圖像,模糊圖像,檢測邊緣等。

卷積操作通過不同的像素融合算法能得到各不相同的效果,這主要依賴于卷積核。

可以把卷積核看作是一個n行n列方陣,原始像素則位于方陣的中心。

邊緣檢測的卷積核也叫邊緣檢測算子,以Sobel算子為例,形如:

需要特別注意的是,這里的Sobel算子是基于坐標軸以屏幕左上為原點,右下分別為+x,+y方向的,而不是類似于uv坐標軸的以屏幕左下為原點,右上分別為+x,+y方向的。這一點需要特別注意,不然后面的程序很容易寫錯。

其中Gx和Gy分別是縱向和橫向兩個方向的邊緣線檢測,你可以通過去掉矩陣中的零元素來想象,因為零元素不會對像素產(chǎn)生任何影響。也就是說,Gx是為了計算橫向的梯度值,Gy為了計算縱向的梯度值。

橫向的梯度值檢測出來的是縱向的邊緣線,縱向的梯度值檢測出來的是橫向的邊緣線。這一點非常容易混淆,需要特別注意。

利用邊緣檢測算子除了融合像素外,主要是為了計算出像素的梯度值。

一個像素和周圍的像素之間梯度值很高,意味著它與周圍的像素差異很大,我們可以想象這個像素和周圍的像素格格不入,存在一個無法逾越的階梯;那么就可以這么認為,這個像素可以作為一條邊界中的值。

對圖像中的每個像素都如此處理,最終就能得到圖像的邊緣。這也就是邊緣檢測的實質(zhì)內(nèi)容。

計算方法:

1.得到每個像素周圍的8個像素的坐標位置以便與Sobel算子進行計算,類似于:(排列方式應(yīng)該與Sobel算子的坐標軸保持一致)

uv[0]

uv[1]

uv[2]

uv[3]

uv[4](原始像素點)

uv[5]

uv[6]

uv[7]

uv[8]

但因為uv坐標的原點在左下角,因此在計算uv[0]-uv[8]時,若依據(jù)uv[4]為原始像素點,則它們的偏移可以表示為如下情況:

(-1,1)uv[0]

(0,1)uv[1]

(1,1)uv[2]

(-1,0)uv[3]

(0,0)uv[4]

(1,0)uv[5]

(-1,-1)uv[6]

(0,-1)uv[7]

(1,-1)uv[8]

2.通過偏移值可以很快計算出目標像素的周圍像素位置坐標信息,隨后與Gx和Gy對應(yīng)元素分別進行橫向和縱向的梯度值計算,也就是分別進行縱向和橫向的邊緣檢測:

具體計算方法為:先對卷積核進行180度翻轉(zhuǎn),得到新的矩陣,隨后各項對應(yīng)元素相乘并相加,注意,不要與矩陣的乘法計算混淆。

但因為Sobel算子是否執(zhí)行翻轉(zhuǎn)操作對計算結(jié)果沒有任何影響,故對于Sobel算子來說,翻轉(zhuǎn)操作可以省略。

Gx和Gy計算結(jié)束后再將它們開平方和;但往往為了簡化GPU的計算量,可以直接取各自的絕對值再相加,得到最終的梯度值G。

3.計算出梯度值后對原始的采樣結(jié)果進行關(guān)于G的插值操作以得到最終的圖像。

程序?qū)崿F(xiàn):

首先是參數(shù)調(diào)控的腳本:

1 usingUnityEngine;2

3 public classEdgeDetectionCtrl : ScreenEffectBase4 {5 private const string _EdgeOnly = "_EdgeOnly";6 private const string _EdgeColor = "_EdgeColor";7 private const string _BackgroundColor = "_BackgroundColor";8

9 [Range(0,1)]10 public float edgeOnly = 0.0f;11

12 public Color edgeColor =Color.black;13

14 public Color backgroundColor =Color.white;15

16 private voidOnRenderImage(RenderTexture source, RenderTexture destination)17 {18 if (Material!=null)19 {20 Material.SetFloat(_EdgeOnly, edgeOnly);21 Material.SetColor(_EdgeColor, edgeColor);22 Material.SetColor(_BackgroundColor, backgroundColor);23 Graphics.Blit(source, destination, Material);24 }25 else

26 Graphics.Blit(source, destination);27 }28 }

同樣是繼承自ScreenEffectBase基類,三個參數(shù)的意義分別如下:

edgeOnly(shader中:_EdgeOnly):邊緣線的疊加程度,0表示完全疊加,1表示只顯示邊緣線,不顯示原圖

edgeColor(shader中:_EdgeColor):邊緣線的顏色

backgroundColor(shader中:_BackgroundColor):背景顏色,當只顯示邊緣線時,可以很清晰看出

基類腳本見:

下面是Shader腳本:

1 Shader "MyUnlit/EdgeDetection"

2 {3 Properties4 {5 _MainTex ("Texture", 2D) = "white"{}6 }7 SubShader8 {9 Tags { "RenderType"="Opaque"}10

11 Pass12 {13 ZTest always14 Cull off15 ZWrite off16

17 CGPROGRAM18 #pragma vertex vert

19 #pragma fragment frag

20

21 #pragma multi_compile_fog

22

23 #include "UnityCG.cginc"

24

25 structappdata26 {27 float4 vertex : POSITION;28 float2 uv : TEXCOORD0;29 };30

31 structv2f32 {33 half2 uv[9] : TEXCOORD0;34 UNITY_FOG_COORDS(1)35 float4 pos : SV_POSITION;36 };37

38 sampler2D _MainTex;39 //紋理映射到[0,1]之后的大小,用于計算相鄰區(qū)域的紋理坐標

40 half4 _MainTex_TexelSize;41 //定義控制腳本中對應(yīng)的參數(shù)

42 fixed_EdgeOnly;43 fixed4 _EdgeColor;44 fixed4 _BackgroundColor;45

46 v2f vert (appdata v)47 {48 v2f o;49 o.pos =UnityObjectToClipPos(v.vertex);50

51 half2 uv =v.uv;52 half2 size =_MainTex_TexelSize;53 //計算周圍像素的紋理坐標位置,其中4為原始點,右側(cè)乘積因子為偏移的像素單位,坐標軸為左下角原點,右上為+x,+y方向,與uv的坐標軸匹配

54 o.uv[0] = uv + size * half2(-1, 1);55 o.uv[1] = uv + size * half2(0, 1);56 o.uv[2] = uv + size * half2(1, 1);57 o.uv[3] = uv + size * half2(-1, 0);58 o.uv[4] = uv + size * half2(0, 0);59 o.uv[5] = uv + size * half2(1, 0);60 o.uv[6] = uv + size * half2(-1, -1);61 o.uv[7] = uv + size * half2(0, -1);62 o.uv[8] = uv + size * half2(1, -1);63

64 UNITY_TRANSFER_FOG(o,o.pos);65 returno;66 }67 //計算對應(yīng)像素的最低灰度值并返回

68 fixed minGrayCompute(v2f i,intidx)69 {70 returnLuminance(tex2D(_MainTex, i.uv[idx]));71 }72 //利用Sobel算子計算最終梯度值

73 half sobel(v2f i)74 {75 const half Gx[9] ={76 - 1,0,1,77 - 2,0,2,78 - 1,0,1

79 };80 const half Gy[9] ={81 -1,-2,-1,82 0, 0, 0,83 1, 2, 1

84 };85 //分別計算橫向和縱向的梯度值,方法為各項對應(yīng)元素相乘并相加

86 half graX = 0;87 half graY = 0;88

89 for (int it = 0; it < 9; it++)90 {91 graX += Gx[it] *minGrayCompute(i, it);92 graY += Gy[it] *minGrayCompute(i, it);93 }94 //絕對值相加近似模擬最終梯度值

95 return abs(graX) +abs(graY);96 }97

98 fixed4 frag (v2f i) : SV_Target99 {100 half gra =sobel(i);101 fixed4 col = tex2D(_MainTex, i.uv[4]);102 //利用得到的梯度值進行插值操作,其中梯度值越大,越接近邊緣的顏色

103 fixed4 withEdgeColor =lerp( col, _EdgeColor, gra);104 fixed4 onlyEdgeColor =lerp( _BackgroundColor, _EdgeColor, gra);105 fixed4 color =lerp(withEdgeColor, onlyEdgeColor, _EdgeOnly);106

107 UNITY_APPLY_FOG(i.fogCoord, color);108 returncolor;109 }110 ENDCG111 }112 }113 }

效果如下:

總結(jié)

以上是生活随笔為你收集整理的unity 给图片边缘_Unity Shader 屏幕后效果——边缘检测的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。