一种基于glsl的高效Hexagon Bokeh实现方式

一种基于glsl的高效Hexagon Bokeh实现方式

关于Hexagon Bokeh

找到这篇博文的应该已经知道Hexagon Bokeh是什么的。不过为了完整性,这里还是简单介绍下。
Bokeh是个源于日语的词,意思是焦外成像。指的是摄像机在拍摄画面时,超出焦距范围的部分会出现虚化的现象。这种散焦会导致焦距外的画面中,亮度比较高的区域进行模糊扩散,其中模糊扩散的形状是由镜头光圈的形状决定的。而Hexagon是六边形的意思,Hexagon Bokeh也就是指六边形的摄像机光圈焦散模糊的效果。

实现方式讲解

本文所描述的实现方式并非原创,早期想法来自于SIGGRAPH 2011中寒霜引擎的工作人员的技术分享,可以点击这里下载当时演讲的pdf.

Colin Barré-Brisebois在他的一篇博文中对这种方法也有精彩的讲解。

我在这篇博文中主要是讲解我在试图利用这种方式来实现Hexagon Bokeh效果,并使之尽量接近After Effects中的官方Camera Lens Blur插件的效果时遇到的问题和相应的解决办法。

1. 基本实现方法

这种算法的核心是把一个六边形拆解成三个菱形,或者如寒霜PPT中所称的斜交方块(Skewed Box)。 然后再通过把这三个菱形进行混合,产生最终的六边形模糊。如下图所示

六边形拆解

我们先来讲解如何渲染一个菱形模糊。
首先,我们对图像做一次单方向模糊,如下图所示,左侧的圆形代表原图像中的像素,我们对其进行向上的模糊后,得到的结果会如右侧所示,一条向上的直线。

模糊通道1

然后我们把模糊后的结果进行下一轮方向模糊,这次我们需要对其进行朝向左下方的模糊,这次模糊过后,我们就能得到一个菱形了。

模糊通道2

同样的方式,我们只需对模糊的方向进行调整,很容易得出其余两个菱形。之后再对三个菱形进行混合,即可得到最终的六边形模糊效果。

扫描二维码关注公众号,回复: 12357407 查看本文章

下面是对图像进行方向模糊的核心算法

// 模糊方向的计算
// blurAngle: 指的是模糊方向的弧度值
// amount: 指的是模糊的强度
vec2 direction = vec2(cos(blurAngle), sin(blurAngle)) * amount; 

// 模糊结果的计算
vec4 BlurTexture(sampler2D tex, vec2 uv, vec2 direction, float amount) {
    if (amount >= 1.0){
        vec4 finalColor = vec4(0.0);
        for (float i = 0; i < amount; i += 1.0) {
            float percent = i / amount;
            vec4 color = texture(tex, (uv + direction * percent) / texSize);
            finalColor += color;
        } 
        return (finalColor / amount);
    }
    return texture(tex, uv / texSize);
}

当我们对三个菱形的内容进行混合时,代码也很简单

vec4 result = (color1 + color2 + color3) / 3.0;

2. 解决画面变暗问题

由以上模糊算法和模糊通道混合算法我们不难推测出,最终画面的颜色亮度会随着模糊值的增大迅速降低。这个结果和After Effects中的Camera Lens Blur的效果差异比较大。我们可以通过下图看到颜色值的降低也导致高光区域模糊产生的六边形可见度下降。

luma_compare

为了解决这个问题,我们需要在对原图进行模糊之前,将原图的gamma值提高,然后在模糊完成后,将gamma值还原。这样就能很好地保证颜色的亮度在模糊的过程中不受到损失。

//提高gamma值,在进行任何模糊操作之前运行
//power代表新的gamma值,根据测试,power为2.2比较接近Camera Lens Blur的效果
vec4 color = pow(srcColor, vec4(power));


//还原gamma值,在对三个菱形进行颜色混合得出最终的颜色值后运行
vec4 outputColor = pow(result, vec4(1.0 / power));

3. 增加六边形比例调节和旋转的支持

为了能对模糊效果进行更好的控制,我们需要增加对模糊六边形和六边形的角度进行调节的功能。具体调节的效果如下图所示:
ratio_rotation

经过调节后,我们能够得到更加有趣的画面效果。具体实现我们只需要在计算模糊方向时将ratio和rotation的影响融合进去即可,代码如下

mat2 rotate(float _angle) { return mat2(cos(_angle),-sin(_angle), sin(_angle), cos(_angle)); }
// 模糊方向的计算
// blurAngle: 指的是模糊方向的弧度值
// amount: 指的是模糊的强度
// ratio: 六边形的比例
// rotation: 旋转弧度值
vec2 direction = rotate(rotation) * vec2(cos(blurAngle) * ratio, sin(blurAngle)) * amount;

猜你喜欢

转载自blog.csdn.net/weixin_41191739/article/details/102664821