[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/本文部分素材使用了参考文档中的内容。