這篇文章主要為大家展示了“Unity Shader后處理中如何實現(xiàn)簡單均值模糊”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學習一下“Unity Shader后處理中如何實現(xiàn)簡單均值模糊”這篇文章吧。
十余年的和靜網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。網(wǎng)絡(luò)營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整和靜建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。成都創(chuàng)新互聯(lián)公司從事“和靜網(wǎng)站設(shè)計”,“和靜網(wǎng)站推廣”以來,每個客戶項目都認真落實執(zhí)行。
后處理中比較常用的一種效果,屏幕模糊效果。模糊效果,在圖像處理中經(jīng)常用到,Photoshop中也有類似的濾鏡。我們在游戲中也會經(jīng)常用到。因為屏幕模糊效果是一些高級后處理效果的基礎(chǔ),比如景深等效果都需要用屏幕模糊效果來實現(xiàn),所以我們首先看一下屏幕模糊效果,然后通過屏幕模糊,進一步學習景深效果與運動模糊效果的實現(xiàn)。
所謂模糊,也就是不清楚,清晰的圖片,各個像素之間會有明顯的過渡,而如果各個像素之間的差距不是很大,那么圖像就會模糊了,極端一點的情況,當一張圖片所有的像素之間顏色都差不多時,那么這張圖片也就是一個純色的圖片了。模糊操作就是讓像素間的顏色差距變小,比如A點是紅色,A點周圍的點是綠色,模糊就像用一把刷子,將A點和周圍的點的顏色混合起來,變成最終的顏色。而怎樣混合,按照不同的權(quán)值進行混合,就可以達到不同的效果了。比如均值模糊,以及著名的高斯模糊。
影響模糊程度的重要因素是模糊半徑,模糊半徑越大,模糊程度越大,模糊半徑越小,模糊程度越小。那么,模糊半徑是什么?所謂模糊半徑,也就是我們采樣的一個范圍,比如我們模糊的半徑很小,只是把像素和它周圍的一圈定點混合,那么模糊的程度就很小,而如果我們加大模糊半徑,極端情況是每個頂點都取了周圍所有點,也就是整張圖的像素平均值,那么這張圖的顏色就會偏向一種顏色。
最簡單的,我們看一下簡單的模糊,直接用周圍像素求和平均,我們混合的最終圖像,在某一點的權(quán)重僅僅跟模糊半徑有關(guān)。換句話說,比如模糊半徑為1,那么,我們?nèi)∫粋€像素點,以及他周圍的一圈像素點,一共九個點,直接取平均,那么每個點的權(quán)重設(shè)置為1/9。這也就是所謂的均值模糊。我們看一下均值模糊的例子。
shader部分:
Shader "Custom/SimpleBlurEffect" { Properties { _MainTex("Base (RGB)", 2D) = "white" {} } //通過CGINCLUDE我們可以預定義一些下面在Pass中用到的struct以及函數(shù), //這樣在pass中只需要設(shè)置渲染狀態(tài)以及調(diào)用函數(shù),shader更加簡潔明了 CGINCLUDE //cg文件,包含了unity內(nèi)置的一些cg函數(shù) #include "UnityCG.cginc" //blur結(jié)構(gòu)體,從blur的vert函數(shù)傳遞到frag函數(shù)的參數(shù) struct v2f_blur { float4 pos : SV_POSITION; //頂點位置 float2 uv : TEXCOORD0; //紋理坐標 float2 uv1 : TEXCOORD1; //周圍紋理1 float2 uv2 : TEXCOORD2; //周圍紋理2 float2 uv3 : TEXCOORD3; //周圍紋理3 float2 uv4 : TEXCOORD4; //周圍紋理4 }; //用到的變量 sampler2D _MainTex; //XX_TexelSize,XX紋理的像素相關(guān)大小width,height對應(yīng)紋理的分辨率,x = 1/width, y = 1/height, z = width, w = height float4 _MainTex_TexelSize; //模糊半徑 float _BlurRadius; //vertex shader v2f_blur vert_blur(appdata_img v) { v2f_blur o; o.pos = mul(UNITY_MATRIX_MVP, v.vertex); o.uv = v.texcoord.xy; //計算uv上下左右四個點對于blur半徑下的uv坐標 o.uv1 = v.texcoord.xy + _BlurRadius * _MainTex_TexelSize * float2( 1, 1); o.uv2 = v.texcoord.xy + _BlurRadius * _MainTex_TexelSize * float2(-1, 1); o.uv3 = v.texcoord.xy + _BlurRadius * _MainTex_TexelSize * float2(-1, -1); o.uv4 = v.texcoord.xy + _BlurRadius * _MainTex_TexelSize * float2( 1, -1); return o; } //fragment shader fixed4 frag_blur(v2f_blur i) : SV_Target { fixed4 color = fixed4(0,0,0,0); color += tex2D(_MainTex, i.uv ); color += tex2D(_MainTex, i.uv1); color += tex2D(_MainTex, i.uv2); color += tex2D(_MainTex, i.uv3); color += tex2D(_MainTex, i.uv4); //相加取平均,據(jù)說shader中乘法比較快 return color * 0.2; } ENDCG //子著色器 SubShader { //pass 0: blur effect Pass { ZTest Always Cull Off ZWrite Off Fog{ Mode Off } //直接調(diào)用vert_blur和frag_blur CGPROGRAM #pragma vertex vert_blur #pragma fragment frag_blur ENDCG } } }
C#腳本部分:
using UnityEngine; using System.Collections; //編輯狀態(tài)下也運行 [ExecuteInEditMode] //繼承自PostEffectBase public class SimpleBlurEffect : PostEffectBase { //模糊半徑 public float BlurRadius = 1.0f; void OnRenderImage(RenderTexture source, RenderTexture destination) { if (_Material) { //blur _Material.SetFloat("_BlurRadius", BlurRadius); Graphics.Blit(source, destination, _Material); } } }
注意,此處的PostEffectBase為各種后處理效果的基類,在上一篇文章: Unity Shader-后處理:簡單的顏色調(diào)整(亮度,飽和度,對比度)中有該類的完整實現(xiàn),此處不予貼出代碼。
效果如下圖所示:
原圖效果
blurRadius = 1
blurRadius = 5
從上面的模糊效果我們看到,模糊半徑越大,模糊的效果越明顯。但是!這種效果看起來一點都不舒服,有種近視的趕腳,完全不是平滑的模糊效果,就更不要說進一步的毛玻璃之類的全模糊效果了。
既然,一次模糊我們感覺效果不是很盡人意,那么,我們可以嘗試迭代模糊,也就是用上一次模糊的輸出作為下一次模糊的輸入,迭代之后的模糊效果更加明顯。先看一下代碼,這次,我們的shader代碼和上面的一樣,沒有變動,僅僅是修改了腳本,增加了降分辨率和迭代的兩個操作。
using UnityEngine; using System.Collections; //編輯狀態(tài)下也運行 [ExecuteInEditMode] //繼承自PostEffectBase public class SimpleBlurEffect : PostEffectBase { //模糊半徑 public float BlurRadius = 1.0f; //降分辨率 public int downSample = 2; //迭代次數(shù) public int iteration = 3; void OnRenderImage(RenderTexture source, RenderTexture destination) { if (_Material) { //申請RenderTexture,RT的分辨率按照downSample降低 RenderTexture rt1 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0, source.format); RenderTexture rt2 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0, source.format); //直接將原圖拷貝到降分辨率的RT上 Graphics.Blit(source, rt1); //進行迭代,一次迭代進行了兩次模糊操作,使用兩張RT交叉處理 for(int i = 0; i < iteration; i++) { //用降過分辨率的RT進行模糊處理 _Material.SetFloat("_BlurRadius", BlurRadius); Graphics.Blit(rt1, rt2, _Material); Graphics.Blit(rt2, rt1, _Material); } //將結(jié)果拷貝到目標RT Graphics.Blit(rt1, destination); //釋放申請的兩塊RenderBuffer內(nèi)容 RenderTexture.ReleaseTemporary(rt1); RenderTexture.ReleaseTemporary(rt2); } } }
結(jié)果如下:
blurRadius = 1, downSample = 2, iteration = 3
blurRadius = 1, downSample = 2, iteration = 5
我們看到,通過迭代以及降低分辨率,我們的模糊效果更加明顯了,當?shù)螖?shù)較大時,會有一種毛玻璃的效果。這里,雖然迭代次數(shù)增加了,會耗費更多的性能,但是相應(yīng)地,我們也降低了分辨率,也減少了采樣等計算操作的消耗。
這里,我們通過多次處理,包括降分辨率以及迭代,完成了模糊操作,這里我們需要臨時存儲上一次處理過的中間輸出,所以就需要用渲染中常用的一個概念RenderTexture。
關(guān)于RenderTexture,簡要介紹一下,我們在渲染場景時,一般都是直接輸出到幀緩存,然后輸出到屏幕上,然而有的時候,我們并不想直接輸出結(jié)果,而是需要對這個渲染的結(jié)果進行處理,所以,我們就將渲染的結(jié)果輸出到了一張紋理上,也就是RenderTexture,這也是所有后處理的基礎(chǔ)。Unity的RenderTexture還是很好用的,我們不僅僅可以在后處理時使用,還可以通過把攝像機的輸出設(shè)置到某個RT上,然后用這張RT作為一些類似鏡子的物體上,就可以實現(xiàn)鏡面效果或者屏幕效果。
不過RenderTexture還是很耗費資源的,一張大的RenderTexture是屏幕分辨率大小的一張圖片,而且是完全不能夠壓縮的,所以當后處理中RenderTexture用得多時,內(nèi)存消耗很大,在手機,尤其是大屏手機,內(nèi)存比較小的情況下,后處理疊加時很可能會由于內(nèi)存耗盡而崩潰。所以,我們在使用RenderTexture時需要慎重考慮。如果效果可以接受,我們就可以考慮降低RenderTexture的分辨率,這樣,輸出的畫面效果可能會打一些折扣,但是性能會有很大的提高。而我們的模糊效果,本身降低分辨率就會導致畫面比較模糊,所以在這里,我們完全可以放心大膽地降低RT的分辨率,既可以提升效果,又可以大大地減少開銷。
這里還有一點,由于OnRenderImage函數(shù)每幀在渲染之前都會調(diào)用,之前曾經(jīng)擔心會不會每一幀在這里申請RT,然后釋放,會不會有很高的GC?經(jīng)過查找了一些資料,發(fā)現(xiàn)Unity這里是進行過處理的,RenderTexture是之前申請好的一塊內(nèi)存區(qū)域,我們可以直接使用,而不需要考慮GC的問題,正如這兩個函數(shù)的名字一樣,RenderTexture.GetTemporary和RenderTexture.ReleaseTemporary一樣。并且,本人親測,使用Profile掛了一下這個腳本,發(fā)現(xiàn)的確沒有GC:
以上是“Unity Shader后處理中如何實現(xiàn)簡單均值模糊”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學習更多知識,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!
當前題目:UnityShader后處理中如何實現(xiàn)簡單均值模糊
本文來源:http://chinadenli.net/article0/giepio.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供企業(yè)網(wǎng)站制作、自適應(yīng)網(wǎng)站、網(wǎng)站設(shè)計公司、網(wǎng)站設(shè)計、定制網(wǎng)站、軟件開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)