Unity Shader 螢幕後效果 邊緣檢測

2022-06-22 01:36:11 字數 4320 閱讀 4262

關於螢幕後效果的控制類詳細見之前寫的另一篇部落格:

這篇主要是基於之前的控制類,實現另一種常見的螢幕後效果——邊緣檢測

概念和原理部分:

首先,我們需要知道在圖形學中經常處理畫素的一種操作——卷積

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

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

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

邊緣檢測的卷積核也叫邊緣檢測運算元,以sobel運算元為例,形如:

需要特別注意的是,這裡的sobel運算元是基於座標軸以螢幕左上為原點,右下分別為+x,+y方向的,而不是類似於uv座標軸的以螢幕左下為原點,右上分別為+x,+y方向的。這一點需要特別注意,不然後面的程式很容易寫錯。

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

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

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

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

對影象中的每個畫素都如此處理,最終就能得到影象的邊緣。這也就是邊緣檢測的實質內容。

計算方法:

1.得到每個畫素周圍的8個畫素的座標位置以便與sobel運算元進行計算,類似於:(排列方式應該與sobel運算元的座標軸保持一致)

uv[0]

uv[1]

uv[2]

uv[3]

uv[4](原始畫素點)

uv[5]

uv[6]

uv[7]

uv[8]

但因為uv座標的原點在左下角,因此在計算uv[0]-uv[8]時,若依據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.通過偏移值可以很快計算出目標畫素的周圍畫素位置座標資訊,隨後與gxgy對應元素分別進行橫向和縱向的梯度值計算,也就是分別進行縱向和橫向的邊緣檢測:

具體計算方法為:先對卷積核進行180度翻轉,得到新的矩陣,隨後各項對應元素相乘並相加,注意,不要與矩陣的乘法計算混淆。

但因為sobel運算元是否執行翻轉操作對計算結果沒有任何影響,故對於sobel運算元來說,翻轉操作可以省略。

gxgy計算結束後再將它們開平方和;但往往為了簡化gpu的計算量,可以直接取各自的絕對值再相加,得到最終的梯度值g

3.計算出梯度值後對原始的取樣結果進行關於g的插值操作以得到最終的影象。

程式實現:

首先是引數調控的指令碼:

1 using unityengine;

2 3 public class edgedetectionctrl : screeneffectbase

4 25 else

26 graphics.blit(source, destination);

27 }

28 }

同樣是繼承自screeneffectbase基類,三個引數的意義分別如下:

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

edgecolor(shader中:_edgecolor):邊緣線的顏色

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

基類指令碼見:

下面是shader指令碼:

1 shader "myunlit/edgedetection"

2 6 }

7 subshader

8

10 11 pass

12 ;

30 31 struct v2f

32 ;

37 38 sampler2d _maintex;

39 //紋理對映到[0,1]之後的大小,用於計算相鄰區域的紋理座標

40 half4 _maintex_texelsize;

41 //定義控制指令碼中對應的引數

42 fixed _edgeonly;

43 fixed4 _edgecolor;

44 fixed4 _backgroundcolor;

45 47

67 //計算對應畫素的最低灰度值並返回

68 fixed mingraycompute(v2f i,int idx)

69

72 //利用sobel運算元計算最終梯度值

73 half sobel(v2f i)

74 ;

80 const half gy[9] = ;

85 //分別計算橫向和縱向的梯度值,方法為各項對應元素相乘並相加

86 half grax = 0;

87 half gray = 0;

88 89 for (int it = 0; it < 9; it++)

90

94 //絕對值相加近似模擬最終梯度值

95 return abs(grax) + abs(gray);

96 }

97 98 fixed4 frag (v2f i) : sv_target

99

110 endcg

111 }

112 }

113 }

效果如下:

Unity Shader 螢幕後效果 高斯模糊

高斯模糊是影象模糊處理中非常經典和常見的一種演算法,也是bloom螢幕效果的基礎。實現高斯模糊同樣用到了卷積的概念,關於卷積的概念和原理詳見我的另一篇部落格 通過高斯方程計算出的卷積核稱為高斯核,乙個5 5的高斯核對它進行權重歸一化如下 0.0030 0.0133 0.0219 0.0133 0.0...

Unity Shader 螢幕抓取,螢幕座標

抓取螢幕,抓取後名字為name 獲取螢幕座標有3種方法 sv position語義的xy 使用sv position語義,在片元著色器中拿到的pos.xy就是螢幕空間的座標。struct v2f vpos語義 vpos語義和sv position衝突,使用vpos語義,則v2f不能定義sv posi...

螢幕後處理

void onrenderimage rendertexture src,rendertexture dest 螢幕後處理函式 graphics.blit src,dest,mat,pass 螢幕後處理 src當前螢幕紋理 graphics.drawmesh amesh,vector3.zero,q...