了解完高斯模糊之后,接下来看看运动模糊。
什么是运动模糊? 根据百科的定义:动态模糊或运动模糊是静态场景或一系列的图片像电影或是动画中快速移动的物体造成明显的模糊拖动痕迹。
为什么会出现运动模糊? 摄影机的工作原理是在很短的时间里把场景在胶片上曝光。场景中的光线投射在胶片上,引起化学反应,最终产生图片。这就是曝光。如果在曝光的过程中,场景发生变化,则就会产生模糊的画面。
问题一:运动模糊是否就是单一方向的高斯模糊?
我们根据运动模糊的物理成像原理可以知道,离快门关闭越近的图像越清晰,残影是存在透明度变化的,它也受速度影响:
我们尝试一下通过单一方向的高斯模糊来模拟运动模糊,看看效果如何:
// 只展示核心代码
vec4 blur13(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
vec4 color = vec4(0.0);
vec2 off1 = vec2(1.411764705882353) * direction;
vec2 off2 = vec2(3.2941176470588234) * direction;
vec2 off3 = vec2(5.176470588235294) * direction;
color += texture2D(image, uv) * 0.1964825501511404;
color += texture2D(image, uv + (off1 / resolution)) * 0.2969069646728344;
color += texture2D(image, uv - (off1 / resolution)) * 0.2969069646728344;
color += texture2D(image, uv + (off2 / resolution)) * 0.09447039785044732;
color += texture2D(image, uv - (off2 / resolution)) * 0.09447039785044732;
color += texture2D(image, uv + (off3 / resolution)) * 0.010381362401148057;
color += texture2D(image, uv - (off3 / resolution)) * 0.010381362401148057;
return color;
}
void main() {
gl_FragColor = blur13(texture, st, iResolution, vec2(0., 5.));
}
复制代码
虽然单一方向的高斯模糊并不完全符合运动模糊的定义。但单纯看效果其实分辨不太出来,我们再把效果强化:
问题二:如何让画面自然地动起来?
运动模糊,自然需要运动才能体现出来。首先我们实现一个简单的位移:
// 只展示核心代码
vec4 blur13(sampler2D image, vec2 uv, vec2 resolution, vec2 direction) {
vec4 color = vec4(0.0);
vec2 off1 = vec2(1.411764705882353) * direction;
vec2 off2 = vec2(3.2941176470588234) * direction;
vec2 off3 = vec2(5.176470588235294) * direction;
color += texture2D(image, uv) * 0.1964825501511404;
color += texture2D(image, uv + (off1 / resolution)) * 0.2969069646728344;
color += texture2D(image, uv - (off1 / resolution)) * 0.2969069646728344;
color += texture2D(image, uv + (off2 / resolution)) * 0.09447039785044732;
color += texture2D(image, uv - (off2 / resolution)) * 0.09447039785044732;
color += texture2D(image, uv + (off3 / resolution)) * 0.010381362401148057;
color += texture2D(image, uv - (off3 / resolution)) * 0.010381362401148057;
return color;
}
void main() {
st += time*3.; // time: 0~1
st = fract(st);
gl_FragColor = blur13(texture, st, iResolution, vec2(0., 20.));
}
复制代码
OK,有点辣眼睛。首先需要解决的问题是图像边界连接到地方并没有运动模糊:
这意味着我们要实时的取当前的坐标来对图像进行取样,所以传入一个新的参数,表示当前运动的距离:
vec4 blur13(sampler2D image, vec2 uv, vec2 resolution, vec2 direction, vec2 speed) {
vec4 color = vec4(0.0);
vec2 off1 = vec2(1.411764705882353) * direction;
vec2 off2 = vec2(3.2941176470588234) * direction;
vec2 off3 = vec2(5.176470588235294) * direction;
color += texture2D(image, fract(uv + speed)) * 0.1964825501511404;
color += texture2D(image, fract(uv + (off1 / resolution) + speed)) * 0.2969069646728344;
color += texture2D(image, fract(uv - (off1 / resolution) + speed)) * 0.2969069646728344;
color += texture2D(image, fract(uv + (off2 / resolution) + speed)) * 0.09447039785044732;
color += texture2D(image, fract(uv - (off2 / resolution) + speed)) * 0.09447039785044732;
color += texture2D(image, fract(uv + (off3 / resolution) + speed)) * 0.010381362401148057;
color += texture2D(image, fract(uv - (off3 / resolution) + speed)) * 0.010381362401148057;
return color;
}
void main() {
vec2 speed = vec2(0, time*3.);
gl_FragColor = blur13(inputImageTexture, myst, iResolution, vec2(0., 20.), speed);
}
复制代码
那解决完边界问题,再分析下运动模糊出现的时机,运动开始和结束肯定不会产生模糊,只有中间过程才会有模糊,所以我们根据时间来调整模糊:
我们先构造一个从 0~1 的单位时间内,它的值从 0~1~0 的变化曲线,作为我们模糊的乘数,通过这个工具,对之前的正态分布概率密度函数进行一点改造:
vec4 blur13(sampler2D image, vec2 uv, vec2 resolution, vec2 direction, vec2 speed) {
vec4 color = vec4(0.0);
vec2 off1 = vec2(1.411764705882353) * direction;
vec2 off2 = vec2(3.2941176470588234) * direction;
vec2 off3 = vec2(5.176470588235294) * direction;
color += texture2D(image, fract(uv + speed)) *