Unity Shader 屏幕後效果——高斯模糊

高斯模糊是圖像模糊處理中很是經典和常見的一種算法,也是Bloom屏幕效果的基礎。html

 

實現高斯模糊一樣用到了卷積的概念,關於卷積的概念和原理詳見個人另外一篇博客:算法

 http://www.javashuo.com/article/p-uawxakhx-dp.html數組

 

經過高斯方程計算出的卷積核稱爲高斯核,一個5*5的高斯覈對它進行權重歸一化以下:緩存

0.0030 0.0133 0.0219 0.0133 0.0030
0.0133 0.0596 0.0983 0.0596 0.0133
0.0219 0.0983 0.1621 0.0983 0.0219
0.0133 0.0596 0.0983 0.0596 0.0133
0.0030 0.0133 0.0219 0.0133 0.0030

 

 

 

 

 

 

 

經過表也能夠很清楚的看到,離原點越近的點模糊程度影響越大,反之越小。app

爲了優化計算,能夠將這個5*5矩陣簡化爲兩個矩陣分別計算,獲得的效果是相同的。函數

它們分別是一個1*5的橫向矩陣和一個5*1的縱向矩陣,這樣咱們只須要對橫縱向矩陣分別進行一次採樣既可,這樣能夠很大程度的減小計算量。優化

拆分以後結果以下:spa

 

 咱們發現,最終的計算只須要記錄3個權重值既可,它們是weight[3]={0.4026,0.2442,0.0545};code

 

具體實現:htm

1.實現調整高斯模糊參數的腳本。

爲了進一步優化計算,這裏加入了降採樣係數,模糊範圍縮放;爲此,須要在外部增長模糊採樣的迭代次數,具體以下:

 

 1 using UnityEngine;
 2 
 3 public class GaussianBlurCtrl : ScreenEffectBase
 4 {
 5     private const string _BlurSize = "_BlurSize";//只有模糊範圍須要在GPU中計算
 6 
 7     [Range(0, 4)]
 8     public int iterations = 3;//迭代次數
 9     [Range(0.2f, 3)]
10     public float blurSize = 0.6f;//模糊範圍
11     [Range(1, 8)]
12     public int downSample = 2;//降採樣係數
13 
14     private void OnRenderImage(RenderTexture source, RenderTexture destination)
15     {
16         if (Material != null)
17         {
18             //獲得屏幕的渲染紋理後直接除以降採樣係數以成倍減小計算量,但過大時模糊效果不佳
19             int rtw = source.width/downSample;
20             int rth = source.height/downSample;
21 
22             RenderTexture buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
23             buffer0.filterMode = FilterMode.Bilinear;
24 
25             Graphics.Blit(source, buffer0);
26 
27             //利用迭代次數對模糊範圍加以控制,用到了相似於雙緩衝的方式對紋理進行處理
28             for (int i = 0; i < iterations; i++)
29             {
30                 //設置採樣範圍,根據迭代次數範圍增長,以後會與紋理座標進行乘積操做,固基礎值爲1
31                 Material.SetFloat(_BlurSize, blurSize*i+1);
32 
33                 RenderTexture buffer1 = RenderTexture.GetTemporary(rtw, rth, 0);
34                 Graphics.Blit(buffer0, buffer1, Material, 0);
35                 //每次處理完當即釋放相應緩存,由於Unity內部已經對此作了相應的優化
36                 RenderTexture.ReleaseTemporary(buffer0);
37                 buffer0 = RenderTexture.GetTemporary(rtw, rth, 0);
38                 Graphics.Blit(buffer1, buffer0,Material, 1);
39                 RenderTexture.ReleaseTemporary(buffer1);
40             }
41             Graphics.Blit(buffer0, destination);
42             RenderTexture.ReleaseTemporary(buffer0);
43         }
44         else
45             Graphics.Blit(source, destination);
46     }
47 }

 

2.在Shader中分別進行橫向和縱向的模糊計算,分爲兩個Pass進行,具體以下:

  1 Shader "MyUnlit/GaussianBlur"
  2 {
  3     Properties
  4     {
  5         _MainTex ("Texture", 2D) = "white" {}
  6     }
  7     SubShader
  8     {
  9         Tags { "RenderType"="Opaque" }
 10 
 11         //CGINCLUDE中的代碼可被其餘Pass重複調用,用於簡化沒必要要的重複代碼
 12         CGINCLUDE
 13 
 14         #pragma multi_compile_fog
 15         #include "UnityCG.cginc"
 16 
 17         struct appdata
 18         {
 19             float4 vertex : POSITION;
 20             float2 uv : TEXCOORD0;
 21         };
 22 
 23         struct v2f
 24         {
 25             half2 uv[5] : TEXCOORD0;
 26             UNITY_FOG_COORDS(1)
 27             float4 pos : SV_POSITION;
 28         };
 29 
 30         sampler2D _MainTex;
 31         float4 _MainTex_TexelSize;
 32         float _BlurSize;
 33 
 34         //用於計算縱向模糊的紋理座標元素
 35         v2f vert_v(appdata v)
 36         {
 37             v2f o;
 38             o.pos = UnityObjectToClipPos(v.vertex);
 39             half2 uv = v.uv;
 40 
 41             //以擴散的方式對數組進行排序,只偏移y軸,其中1和2,3和4分別位於原始點0的上下,且距離1個單位和2個像素單位
 42             //獲得的最終偏移與模糊範圍的控制參數進行乘積
 43             o.uv[0] = uv;
 44             o.uv[1] = uv + float2(0.0, _MainTex_TexelSize.y*1.0)*_BlurSize;
 45             o.uv[2] = uv - float2(0.0, _MainTex_TexelSize.y*1.0)*_BlurSize;
 46             o.uv[3] = uv + float2(0.0, _MainTex_TexelSize.y*2.0)*_BlurSize;
 47             o.uv[4] = uv - float2(0.0, _MainTex_TexelSize.y*2.0)*_BlurSize;
 48 
 49             UNITY_TRANSFER_FOG(o, o.vertex);
 50             return o;
 51         }        
 52         
 53         //用於計算橫向模糊的紋理座標元素
 54         v2f vert_h(appdata v)
 55         {
 56             v2f o;
 57             o.pos = UnityObjectToClipPos(v.vertex);
 58             half2 uv = v.uv;
 59 
 60             //與上面同理,只不過是x軸向的模糊偏移
 61             o.uv[0] = uv;
 62             o.uv[1] = uv + float2( _MainTex_TexelSize.x*1.0,0.0)*_BlurSize;
 63             o.uv[2] = uv - float2( _MainTex_TexelSize.x*1.0,0.0)*_BlurSize;
 64             o.uv[3] = uv + float2( _MainTex_TexelSize.x*2.0,0.0)*_BlurSize;
 65             o.uv[4] = uv - float2( _MainTex_TexelSize.x*2.0,0.0)*_BlurSize;
 66 
 67             UNITY_TRANSFER_FOG(o, o.vertex);
 68             return o;
 69         }
 70 
 71         //在片元着色器中進行最終的模糊計算,此過程在每一個Pass中都會進行一次計算,但計算方式是統一的
 72         fixed4 frag(v2f i) : SV_Target
 73         {
 74             float weights[3] = {0.4026,0.2442,0.0545};
 75 
 76             fixed4 col = tex2D(_MainTex, i.uv[0]);
 77 
 78             fixed3 sum = col.rgb*weights[0];
 79 
 80             //對採樣結果進行對應紋理偏移座標的權重計算,以獲得模糊的效果
 81             for (int it = 1; it < 3; it++) 
 82             {
 83                 sum += tex2D(_MainTex, i.uv[2 * it - 1]).rgb*weights[it];//對應1和3,也就是原始像素的上方兩像素
 84                 sum += tex2D(_MainTex, i.uv[2 * it]).rgb*weights[it];//對應2和4,下方兩像素
 85             }
 86             fixed4 color = fixed4(sum, 1.0);
 87             UNITY_APPLY_FOG(i.fogCoord, color);
 88             return color;
 89         }
 90 
 91         ENDCG
 92 
 93         ZTest Always
 94         Cull Off
 95         ZWrite Off
 96 
 97         //縱向模糊Pass,直接用指令調用上面的函數
 98         Pass
 99         {
100             NAME "GAUSSIANBLUR_V"
101             CGPROGRAM
102             #pragma vertex vert_v
103             #pragma fragment frag
104 
105             ENDCG
106         }
107 
108         //橫向模糊Pass
109         Pass
110         {
111             NAME "GAUSSIANBLUR_H"
112             CGPROGRAM
113             #pragma vertex vert_h
114             #pragma fragment frag
115 
116             ENDCG
117         }
118     }
119     Fallback Off
120 }

效果以下:

相關文章
相關標籤/搜索