webgl实现径向模糊
径向模糊简介
径向模糊,是一种从中心向外呈幅射状,逐渐模糊的效果。 因此径向模糊经常会产生一些中心的发散效果,在PS中同样也有径向模糊的滤镜效果。 径向模糊通常也称为变焦模糊。径向模糊(Radial Blur)可以给画面带来很好的速度感,是各类游戏中后处理的常客,也常用于Sun Shaft等后处理特效中作为光线投射(体积光)的模拟。
在游戏中,常常使用径向模糊来模拟一些运动的动感效果。如鬼泣4中的场景切换特效,和一些技能打击特效;赛车游戏也尝用来模拟动感模糊,如狂野飙车,极品飞车等。 径向模糊还是实现体积光照的一种技术手段之一,如下图:

径向模糊的原理
图形学中模糊的大致原理都是一样的:就是从原像素周围去寻找附近像素的颜色,来共同影响当前的像素颜色。如高斯模糊就是将原像素四周像素的颜色加权求和作为原像素的颜色以达到模糊的目的。
不同的模糊就是取周边像素和加权求和的算法不太一样。径向模糊的特点是从某个中心点向外散射扩散,因此其需要采样的像素来自于当前的像素点和中心点的连线上,通过参数可以控制采样的数量和采样步进的距离。像素的颜色是由该像素的点与中心点之间连线上进行采样,然后求将这些采样点颜色的加权平均。根据径向模糊的特性,离目标点越近采样点越密集,反之亦然。
因此,实现径向模糊的大致流程如下:
- 确定径向模糊的中心点,一般为画布的中心点,或这个某个对象的中心点在屏幕投影所在的位置。(注意中心点是2维坐标)
- 计算当前像素和中心点的距离和向量线段。
- 在线段上面进行采样,加权。
- 将模糊的结果和原图进行一个叠加合成(可能需要)
webgl实现径向模糊
径向模糊是一个后处理过程,径向模糊可以对静态的图片施加效果,也可以对动态渲染的图像施加效果。本示例中将对动态的图像施加效果。先上一张图看看效果:

首先绘制的几个圆环对象,然后对绘制的图像施加径向模糊。
渲染到纹理
要施加径向模糊,首先要把圆环绘制到texture对象上面,我们知道,通过framebuffer的技术,可以实现把绘制效果输出到贴图对象上。
有关framebuffer的技术,不属于本文重点介绍的内容,如果读者不熟悉,可以自行查找相关资料。也可以参考:渲染到纹理。
输入贴图对象
要把贴图对象输出到屏幕上面,我们需要构造一个矩形对象,该对象正好是webgl坐标系中的四个顶点,代码如下:
function quad() {
var pos = [-1,1,0, -1,-1,0, 1,-1,0, 1,1,0],
st = [0,1,0,0,1,0, 1,1],
idx = [0,1,2,0,2,3];
return {
p:pos,
t:st,
i:idx,
}
}
上述对象可以正好把一个贴图对象完整的输出到屏幕上(webgl坐标系)
实现径向模糊
径向模糊的主要在着色器语言中进行实现,而且主要是在片元着色器中,下面是片元着色器的代码:
var ofs = `precision mediump float;
uniform sampler2D texture;
uniform float strength;
varying vec2 vTexCoord;
const float tFrag = 1.0 / 512.0;
const float nFrag = 1.0 / 30.0;
const vec2 centerOffset = vec2(256.0, 256.0);
float rnd(vec3 scale, float seed) {
return fract(sin(dot(gl_FragCoord.stp + seed, scale)) * 43758.5453 + seed);
}
vec4 fragRadialBlur(){
vec2 fc = vec2(gl_FragCoord.s, 512.0 - gl_FragCoord.t);
vec2 fcc = fc - centerOffset;
vec3 destColor = vec3(0.0);
float random = rnd(vec3(12.9898, 78.233, 151.7182), 0.0);
float totalWeight = 0.0;
for (float i = 0.0; i <= 30.0; i++) {
float percent = (i + random) * nFrag;
float weight = percent - percent * percent;
vec2 t = fc - fcc * percent * strength * nFrag;
destColor += texture2D(texture, t * tFrag).rgb * weight;
totalWeight += weight;
}
return vec4(destColor / totalWeight, 1.0);
}
void main(void) {
gl_FragColor = fragRadialBlur();
}`;
随机函数
首先声明了一个rnd函数,此函数是一个简单的随机数生成器,当给定向量和种子值时,将返回0到1范围内的随机数。
使用随机数,是为了让模糊的效果呈现一定的随机状态,而不是按照某种一致性的原则进行模糊。
rnd 在每次片元着色器中都会调用,因此要尽量使用轻量化的实现,不然可能会造成性能负载。
定义相关变量
const float tFrag = 1.0 / 512.0;
const float nFrag = 1.0 / 30.0;
const vec2 centerOffset = vec2(256.0, 256.0);
然后定义相关变量。在此示例中,缩放的中心点设置为画布的中心。
画布的大小为512像素,因此上面的代码相应地声明了一些常量。
vec2变量centerOffset用于定义中心位置。
floag变量tFrag用于规范化,把二维顶点坐标转换成归一化为uv坐标,以正确引用着色器中的纹理像素。
另一个float类型常量nFrag用于着色器中for的语句进行迭代处理进行归一化。
径向模糊逻辑
vec4 fragRadialBlur(){
vec2 fc = vec2(gl_FragCoord.s, 512.0 - gl_FragCoord.t);
vec2 fcc = fc - centerOffset;
vec3 destColor = vec3(0.0);
float random = rnd(vec3(12.9898, 78.233, 151.7182), 0.0);
float totalWeight = 0.0;
for (float i = 0.0; i <= 30.0; i++) {
float percent = (i + random) * nFrag;
float weight = percent - percent * percent;
vec2 t = fc - fcc * percent * strength * nFrag;
destColor += texture2D(texture, t * tFrag).rgb * weight;
totalWeight += weight;
}
return vec4(destColor / totalWeight, 1.0);
}
首先,通过gl_FragCoord计算出变量fc,表示当前像素在canvas画布的坐标。 注意gl_FragCoord坐标的原点是在左下角,而canvas画布的坐标原点在左上角,应此做了一个翻转计算:
512.0 - gl_FragCoord.t
计算变量fcc,表示当前坐标到中心点的向量。
定义变量destColor用于保存最终要输出的像素颜色。 然后计算一个随机值random。totalWeight表示每次迭代时候采样像素所占的比重之和。
然后开始迭代处理。
在片段着色器中通过for语句进行迭代处理,使用i加上随机数之和来计算目标像素的percent(比重),然后通过percent - percent * percent 是为了把线性的比重数据变成非线性的比重weight。
然后通过percent和strength计算出一采样的坐标点t,其中strength表示径向模糊的强度,此值越大,偏离越大,模糊效果越强。并通过texture2D函数获取对应坐标点的颜色值,然后乘以weight并加入到destColor,并最终计算totalWeight。
最后,完成迭代过程后进行归一化destColor: destColor / totalWeight。
说明
此处我们使用了30次迭代,看起来性能并没有太大影响。实际过程中,可以选择不同的迭代次数,来达到效果和性能的平衡。
最终效果如下,

本文也发表在我的webgl专栏,完整代码可以在专栏中获取:
https://xiaozhuanlan.com/topic/6480975213
下一篇文章讲述利用径向模糊实现体积光的效果,先上一张图看看效果:

案例视频 可以关注视频号 "ITman彪叔"观看,也欢迎关注公众号。

webgl实现径向模糊的更多相关文章
- webgl智慧楼宇发光效果算法系列之高斯模糊
webgl智慧楼宇发光效果算法系列之高斯模糊 如果使用过PS之类的图像处理软件,相信对于模糊滤镜不会陌生,图像处理软件提供了众多的模糊算法.高斯模糊是其中的一种. 在我们的智慧楼宇的项目中,要求对楼宇 ...
- Webgl的2D开发方案(一)spritebatcher
使用TypeScript 和 webgl 开发 第一步:实现了SpriteBatcher 例子如下 http://oak2x0a9v.bkt.clouddn.com/test/index.html ...
- HTML5 学习总结(四)——canvas绘图、WebGL、SVG
一.Canvas canvas是HTML5中新增一个HTML5标签与操作canvas的javascript API,它可以实现在网页中完成动态的2D与3D图像技术.<canvas> 标记和 ...
- 数百个 HTML5 例子学习 HT 图形组件 – WebGL 3D 篇
<数百个 HTML5 例子学习 HT 图形组件 – 拓扑图篇>一文让读者了解了 HT的 2D 拓扑图组件使用,本文将对 HT 的 3D 功能做个综合性的介绍,以便初学者可快速上手使用 HT ...
- 基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(二)
我们上一篇<基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(一)>主要讲解了如何搭建一个实时数据通讯服务器,客户端与服务端是如何通讯的,相信通过上一篇的讲解,再配 ...
- 基于 WebSocket 实现 WebGL 3D 拓扑图实时数据通讯同步(一)
今天没有延续上一篇讲的内容,穿插一段小插曲,WebSocket 实时数据通讯同步的问题,今天我们并不是很纯粹地讲 WebSocket 相关知识,我们通过 WebGL 3D 拓扑图来呈现一个有趣的 De ...
- 基于HTML5的WebGL应用内存泄露分析
上篇(http://www.hightopo.com/blog/194.html)我们通过定制了CPU和内存展示界面,体验了HT for Web通过定义矢量实现图形绘制与业务数据的代码解耦及绑定联动, ...
- 基于WebGL 的3D呈现A* Search Algorithm
http://www.hightopo.com/demo/astar/astar.html 最近搞个游戏遇到最短路径的常规游戏问题,一时起兴基于HT for Web写了个A*算法的WebGL 3D呈现 ...
- 20个不可思议的 WebGL 示例和演示
WebGL 是一项在网页浏览器呈现3D画面的技术,有别于过去需要安装浏览器插件,通过 WebGL 的技术,只需要编写网页代码即可实现3D图像的展示.WebGL 可以为 Canvas 提供硬件3D加速渲 ...
随机推荐
- Day09_商品管理
学于黑马和传智播客联合做的教学项目 感谢 黑马官网 传智播客官网 微信搜索"艺术行者",关注并回复关键词"乐优商城"获取视频和教程资料! b站在线视频 0.学习 ...
- 设在起始地址为STRING的存储空间存放了一个字符串(该串已存放在内存中,无需输入,且串长不超过99),统计字符串中字符“A”的个数,并将结果显示在屏幕上。
问题 设在起始地址为STRING的存储空间存放了一个字符串(该串已存放在内存中,无需输入,且串长不超过99),统计字符串中字符"A"的个数,并将结果显示在屏幕上. 代码 data ...
- Java锁_读写锁
独占锁:是指锁一次只能被一个线程持有,ReentrantLock和Synchronized都是独占锁. 共享锁:是指锁可以被多个线程持有. 对于ReentrantReadWriteLock,其读锁是共 ...
- PHP 基础语法介绍
PHP 语法 PHP 脚本在服务器上执行,然后将纯 HTML 结果发送回浏览器. 基本的 PHP 语法 PHP 脚本可以放在文档中的任何位置. PHP 脚本以 <?php 开始,以 ?> ...
- PHP cal_to_jd() 函数
------------恢复内容开始------------ 实例 把 2007 年 6 月 20 日(格利高里历法)转换为儒略日计数: <?php$d=cal_to_jd(CAL_GREGOR ...
- PHP date_parse_from_format() 函数
------------恢复内容开始------------ 实例 根据指定的格式返回一个包含指定日期信息的关联数组: <?phpprint_r(date_parse_from_format(& ...
- 程序人生丨听说程序员是相当就能当的?BAT大牛当场就不乐意了!
有一种对软件开发者的偏见是:他们都是无趣的极客,是学校里的数学天才,每天都要在计算机屏幕前花费多个小时去写代码. 没错,开发者确实会在计算机屏幕前花费多个小时去写代码.但是,每天的工作中还有很多比写代 ...
- Idea风格的快捷键
在使用IntelliJ IDEA时,是可以定义快捷键风格的:File --> Setting --> Keymap 里进行选择,因为我以前用Eclipse开发,后来换成Idea有2年的时间 ...
- 深入学习JDK源码系列之、ArrayList
前言 JDK源码解析系列文章,都是基于JDK8分析的,虽然JDK15马上要出来了,但是JDK8我还不会,我... 类图 实现了RandomAccess接口,可以随机访问 实现了Cloneable接口, ...
- kubernetes 中安装 heapster 问题
step1: 在官网下载部署文件 https://github.com/kubernetes-retired/heapster/tree/master/deploy/kube-config/influ ...