• 【Unity Shader​】 屏幕后处理5.0:讨论双重模糊的Bloom


    接上一篇基于高斯模糊的Bloom继续进行接下来的学习。


    1 一些必要的思考*

    1.1 关于高质量Bloom

    前面提到了,Bloom对于游戏必不可少的效果之一,于是我们不仅仅要把Bloom效果实现出来,效果的质量好坏就更加是我们需要关注的点了。高质量泛光(bloom)从理论到实战这篇文章中对高质量、高品质的Bloom做了三点定义,我就直接把原话搬过来了:

    • 发光物边缘向外“扩张”得足够大
    • 发光物中心足够量(甚至超过1.0而被clamp成白色)
    • 该亮的地方要亮,不该亮的地方不亮

    这篇文章逻辑非常清楚,从实现高品质Bloom出发,介绍了如何利用HDR实现快速的大范围模糊、如何保证中心的高亮区域、以及如何处理泛光的方块图样、闪烁等问题,值得一看!

    1.2 关于Kawase模糊

    不同于【Unity Shader】屏幕后处理3.0:均值模糊和高斯模糊中实现的均值模糊(Box Blur)和高斯模糊(Gassian Blur),Kawase模糊的kernel会随迭代次数移动,而不是固定的:会对当前像素越来越远的四个角进行采样(黑点向四个方向偏移成四个采样点),且在两个相同大小的纹理之间进行乒乓式的Blit:(图来自高品质后处理:十种图像模糊算法的总结与实现 - 知乎 (zhihu.com)

    Kawase模糊实现的效果跟高斯模糊差不多,且性能要优于高斯模糊。

    2 新的模糊思想:双重模糊

    2.1 Unity中实现Bloom的过程

    上一篇博客中我用Unity自带Bloom实现效果跟高斯模糊实现的效果做了个对比,下面我们再Frame Debug一下,看看到底是怎样的一个过程:

    可以发现Unity自带Bloom的实现是有一个先降采样再升采样的过程,跟之前我实现Bloom的方式多了一步升采样,得到的效果也会比仅降采样的效果好。

    2.2 双重模糊思想

    那么上面提到的先降采样再升采样的方法,就是一种新的模糊思想——双重模糊(Dual Kawase Blur,简称Dual Blur),它是SIGGRAPH 2015上ARM团队提出的一种衍生自Kawase Blur的模糊算法(是参考这篇文章的说法),所以会叫做Dual Kawase Blur。

    但现在我认为与其说双重模糊是一种具体的模糊算法,不如说它是一种先降后升的模糊思想,它不仅可以基于Kawase Blur,还可以基于Box Blur、Tent Blur(两次Box Blur)或是Gaussian Blur,取决于在Blit的过程中选择哪种Blur算法。

    根据实时渲染学习笔记—光晕效果(bloom)过程:将全分辨率原图采样为不同更小分辨率的纹理以扩大模糊范围,将这些图片升采样为原分辨率大小的纹理并叠加到原图上,实现大范围的Bloom效果。

    升降采样的插值和滤波

    为什么会有这个疑问呢?因为我发现,在c#脚本中,即使是分辨率不同的纹理之间的跨度也还是简单的:

    Graphics.Blit(rt0, rt1, Material, 1); //假设rt0和rt1分辨率不相同

    那么分辨率高->低or低->高到底是如何重建的?我一直很模糊,通过大量搜索(例如在做降采样处理时,是先滤波,还是先降采样,二者有区别吗?),我简单理解的生/降采样中插值和滤波之间的关系应该是:

    • 降采样——先滤波(选择的滤波方法),后插值(抽取值)
    • 升采样——先插值(内插值法,插入若干0值),后滤波

    我不确定这样的说法是否绝对正确,不过这样想的话也是能解决我的困惑的。

    2.3 优点

    与之前相比这个方法得到的Bloom效果有这样三种优点:

    模糊范围扩大得更好

    这里对应着上述提到的缺点1性能问题,双重模糊的降采样很好得解决了这个问题,达到了模糊范围扩大又好控制、又节省性能的效果。这个时候如果你想说:好像上面的方法里也有用到降采样呀?两者有什么区别?我们不妨看看上面方法是如何体现降采样的:

    1. int rtW = source.width / downSample;
    2. int rtH = source.height / downSample;
    3. //定义rt
    4. RenderTexture rt0 = RenderTexture.GetTemporary(rtW, rtH, 0);
    5. rt0.filterMode = FilterMode.Bilinear;

    明不明显!这里相当于在进行Blit之前只是简单的对源图像降低了分辨率,仅此而已!并没有生成一个个mip层、没有形成一个像Mipmap一样的“图像金字塔”。

    淡化了最终效果的边界感

    降采样扩大了模糊范围后,如果只是单纯的把下采样的最高Mip层级叠加到的源图像上,得到的结果会是一种界限分明的效果,我们借用这篇文章里的只进行下采样的效果:

    过渡得如此突兀显然不是我们想要的,于是就来到了双重模糊的第二个要点——升采样。我们不仅仅把最高Mip层叠加到原图,而是把每一层叠加到一起,这样过渡的就会非常自然,且中间部分该亮的也会亮度合适:(图还是引用上面提到的文章内容)

    提升了性能

    这种方法为什么可以提升性能?——我们可以在低分辨率图像上进行小范围滤波,进而达到在高分辨率图像上大范围滤波等价的效果,比较而言性能当然有所提升。

    3 总结不同方法使用blur kernel

    双重模糊的实现主要体现在两点:

    • 降采样
    • 升采样

    我大概列举一下我能看到的一些文章里实现这两步的方法。

    3.1 采用高斯模糊

    高质量泛光(bloom)从理论到实战这篇文章中最开始降采样和升采样都是用的5X5的高斯滤波盒。

    【Free Bird/URP教学】11.双重模糊 - 知乎 (zhihu.com)这篇文章也是采用的纵横的高斯模糊。

    3.2 《使命召唤》的思路

    《使命召唤:高级战争》中介绍了更好的双重模糊的思路,采用了优化后的降(下)采样和升(上)采样滤波器。

    为了进一步提升性能介绍了更好的滤波盒,(下面的图片保存自高质量泛光(bloom)从理论到实战,实际出处:Advances in Real-Time Rendering in 3D Graphics and Games - SIGGRAPH 2014,详细PPT参考:NEXT GENERATION POST PROCESSING IN CALL OF DUTY: ADVANCED WARFARE

    降采样:更巧妙的kernel

    该方法中,降采样采用了下面这种2X2这种采样模式,如动图所示一共采样了5组(剔除重合采样点一共有13个需要进行纹理查询的采样点),整个过程可以理解为5个“4次双线性纹理查询平均值”的加权平均和。文章实时渲染学习笔记—光晕效果(bloom)更加清楚了介绍降采样的方式,可自行查看。

    上采样:tent kernel

    (本小节的叙述主要参考了实时渲染学习笔记—光晕效果(bloom)

    我们已经理解了所谓的上采样就是将降采样得到的
    N个Mip层的图像还原到原图像分辨率大小,每将一个Mip层还原分辨率,还要进行一次滤波,意味着一共要进行N次高斯滤波,代价是很大的。

    该方法选择了用简单的tent kernel,并采用了一种渐进的采样方式:图中一共有5个Mip层,从最高的第5Mip层出发,Mip5重构到Mip4的分辨率,再与原先的Mip4叠加;叠加后的Mip4重构到Mip3分表率,再与原先的Mip3叠加,以此类推。

    更值得注意的是,他们提出了一个radius parameter来控制范围,卷积核的权重值不再是“一个萝卜一个坑了”,核中间有一个“洞”, 类似卷积里的空洞卷积(总结-空洞卷积(Dilated/Atrous Convolution)),更加降低了计算量。

    3.3 采用Kawase模糊

    参考了高品质后处理:十种图像模糊算法的总结与实现,基于两种不同的kernel:

    其核心思路在于会在Blit的过程中对RT进行降采样和升采样,就像下图:

    3.4 基于简单的Box Blur

    【Shader】后处理之模糊算法这篇文章采用的是基于简单均值模糊的双重模糊。

  • 相关阅读:
    双指针扫描、滑动窗口
    鲁棒实验设计(ED-最优设计)
    bat脚本守护进程
    大数据-之LibrA数据库系统告警处理(ALM-12045 网络读包丢包率超过阈值)
    【ElasticSearch】大数据量情况下的前缀、中缀实时搜索方案
    MySQL学习系列(1)-每天学习10个知识
    【启扬方案】基于RK3568核心板的激光打标机应用解决方案
    vue 插槽 - 具名插槽
    灵卡 LCC262 高性能多功能数字视频和音频一体式采集卡详尽解读
    C语言航路外传之隐式转换与优先级的那点事(你程序总是出bug的一个重要原因)
  • 原文地址:https://blog.csdn.net/qq_41835314/article/details/127986418