[toc]web
前面一篇文章 <webgl智慧樓宇發光效果算法系列之高斯模糊>, 咱們知道了 高斯模糊的本質原理,就是對每一個像素,按照正態分佈的權重去獲取周邊像素的值進行平均,是一種卷積操做。算法
同時咱們能夠指定周邊像素的數量,好比能夠是3X3,或者5X5,通用的表達就是N X N, 數字N一般稱之爲模糊半徑,這在以前的文章的代碼中有體現(uRadius):微信
uniform float uRadius; float gaussianPdf(in float x, in float sigma) { return 0.39894 * exp( -0.5 * x * x/( sigma * sigma))/sigma; } void main() { for( int i = 1; i < MAX_KERNEL_RADIUS; i ++ ) { float x = float(i); if(x > radius){ break; } ... } vec4 result = vec4(1.0) - exp(-diffuseSum/weightSum * uExposure); gl_FragColor = result; } `
一般,咱們但願模糊的效果越強烈,模糊半徑就會要求越大。所謂的半徑就是上面的數字N。
咱們知道,要實現一個NxN大小的高斯模糊,在紋理的每一個像素點,都須要去獲取周邊N個像素點。由於1024_1024大小的紋理,要實現33 33 大小的高斯模糊,須要訪問大概1024 1024 _ 33 * 33≈11.4億個紋理像素,才能應用整個圖像的模糊效果。函數
爲了得到更有效的算法,咱們來看看高斯函數的一些特性:性能
高斯函數的這兩個屬性爲咱們提供了進行大量優化的空間。測試
基於第一個屬性,咱們能夠將二維高斯函數分紅兩個一維函數。在使用片斷着色器的狀況下,咱們能夠將高斯濾鏡分爲水平模糊濾鏡和垂直模糊濾鏡,在渲染後仍可得到準確的結果。 這個時候,1024_1024大小的紋理,要實現33 33 大小的高斯模糊,須要訪問大概1024 1024 _ 33*2≈6,900萬個紋理提取。這種優化明細減小了一個量級。文章 《webgl智慧樓宇發光效果算法系列之高斯模糊》已經實現了這一優化。優化
第二個屬性可用於繞過平臺上的硬件限制,這些平臺僅在一次pass中僅支持有限數量的紋理提取。webgl
到此,咱們知道了把一個二維的高斯模糊 分離成兩個一維的高斯模糊。效率上也有了大幅度的提升。可是實際上,咱們還能夠經過線性採樣的特性進一步提升效率。spa
咱們知道,要獲取一個像素信息,就要作一次貼圖的讀取。這就意味33個像素信息,就須要作33次貼圖的讀取操做。 可是因爲在GPU上面能夠隨意進行雙線線性插值,而沒有額外的性能消耗。 這就意味着,若是咱們再也不像素的中心點讀取貼圖,就能夠得到多個像素的信息。 以下圖所示:
code
假設兩個像素,咱們在像素1中心點讀取貼圖就是獲取像素1的顏色,在像素2中心點讀取貼圖就是獲取像素2的顏色;而在像素1中心點和像素2中心點的某個位置讀取貼圖,則會獲取像素1和像素2的顏色的加權平均的效果。
由於咱們作高斯模糊的時候,自己就是獲取周邊相鄰元素的加權平均值,所以利用線性採樣的這個特性,能夠把本來2個像素的採樣,減小爲一次採樣。 若是本來33次採樣,則能夠減小到17次。
對於兩個紋素的採樣,須要調整座標使其與紋素#1中心的距離等於紋素#2的權重除以兩個權重之和。一樣的,座標與紋素#2中心的距離應該等於紋素#1的權重除以兩個權重之和。
而後咱們就有了計算線性採樣高斯濾波的權重和位移公式:
uniform bool uUseLinear;
if(uUseLinear){ radius = uRadius / 2.0; }
if(uUseLinear){ // http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/ float t1 = 2.0 * x - 1.0,t2 = 2.0 * x ; float w1 = gaussianPdf(t1,fSigma); float w2 = gaussianPdf(t2,fSigma); w = w1 + w2; t = (t1 * w1 + t2 * w2) / w; } vec2 uvOffset = uDirection * invSize * t; vec4 sample1 = texture2D( uColorTexture, vUv + uvOffset).rgba; vec4 sample2 = texture2D( uColorTexture, vUv - uvOffset).rgba; diffuseSum += (sample1 + sample2) * w; weightSum += 2.0 * w;
最終的繪製效果以下:
其中左邊的未使用線性採樣的機制,而右邊的使用了線性採樣,能夠看出右邊再減小了一半的採樣的狀況下,效果和左邊的基本沒有差異。
而效率上,經過測試,右邊比左邊大概提升了40%的渲染效率。
經過線性採樣的機制,咱們能夠看到效率提升了近一倍。這在一些對性能要求高得場景或者移動終端是頗有意義。
其實要作出一個好的發光效果,涉及到相關算法是不少了,並且細節之處都須要關注。
先看看咱們已經作了得一些發光樓宇得案例吧, 如下都是再簡單模型(立方體) + 貼圖 + 光照 + 發光 出來得效果,若是模型層面在優化,應該還能夠有更酷效果:
若是對可視化感興趣,能夠和我交流,微信541002349. 另外關注公衆號「ITMan彪叔」 能夠及時收到更多有價值的文章。
參考文檔:http://rastergrid.com/blog/2010/09/efficient-gaussian-blur-with-linear-sampling/本文部分素材使用了參考文檔中的內容。