前言

常见的bloom流程分为以下几步:

  • 通过阈值计算高光部分
  • 高光部分下采样并生成mipmap
  • 每个mipmap都上采样到原始分辨率,且这个过程会自动完成模糊
  • 将上采样的各个mipmap叠加到原始图片
  • 模糊


但这种实现存在几个问题:

  • 时域闪烁(Fireflies)
  • 存在阈值,并不物理

COD提出了新的算法,能有效解决这两个问题,本文将逐步解析COD的算法

COD的优化:

  • 提升HDR的感知
  • 输入不再是阈值后的输入
  • 颜色是PBR的
  • 时域稳定

COD的方案

COD测试过四种方案:

  1. 分布执行
    • 降采样
    • 每一层滤波
    • 上采样
  2. 降采样时滤波
    • 降采样时滤波
    • 上采样
  3. 升采样时滤波
    • 降采样
    • 升采样时滤波
  4. 双向滤波
    • 下采样时滤波
    • 上采样时滤波

第四种方案双向滤波是最佳方案,因为下采样时滤波可以防止采样走样(aliasing);升采样滤波可以得到质量更好更丝滑的结果。且在上下采样时,应该同时完成缩放与滤波

滤波选择

双线性滤波、三线性滤波效果都较差,最好的是高斯模糊

下采样

  • 双线性过滤单fetch

    双线性过滤单fetch虽然性能很好,但会产生伪影与时域稳定性问题

    这是因为双线性过滤本质是一个2x2 box blur的过程,它的滤波范围较小,这极有可能导致闪烁

    比如,相机在缓慢移动,某个非常明亮但面积范围非常小(只占1个pixel)的亮光,在这一帧亮光正好在某个2x2双线性过滤框中,下一帧相机移动导致亮光移出这个2x2框,原本2x2框变得很暗,新的2x2框变亮

  • 双线性过滤4fetch

    双线性过滤4fetch,四个点通过四次双线性滤波,采样16个pixel,扩大了感受野,可以缓和这个问题,但不能完全根除

    还是需要一个不仅范围大、越向边缘权重越低的滤波器

  • COD采用的滤波器

    COD也是使用的双线性滤波,但他们巧用双线性滤波的特性,滤波器范围覆盖很广,内部每个pixel都能加权平均

    算法解析:如上所示,分成两种权重的采样盒,一种是最中心的红色占0.5,另一种是黄绿蓝紫占0.125,正是这种分布,解决了闪烁的问题

    最中心的pixel涵盖了黄绿蓝紫四种采样盒,这意味着周围的pixel都混合了最中心的pixel,它的权重最高;十字的四个圈圈,各自涵盖了两种采样盒的pixel,它的权重中等;四个角的pixel只有单一采样盒,权重最低

    这种巧妙的结构,正好涵盖了从中心到最边缘权重逐渐减小、的滤波范围足够大的需求

    且这种结构涵盖了36个pixel(图中所有pixel),但不像高斯模糊只消耗了13次fetch

    效果对比如下:

上采样

  • mipmap大的图不要一步到位到mipmap0,而是一级一级的上采样,否则直接拉伸会导致马赛克

    由于对同一张图反复卷积,这种逐级双线性滤波会等效于直接做了一次极其昂贵、极其平滑的三线性滤波

  • 在每次上采样时同时实现blur,会得到更好的效果;且上采样还可以lerp之前mip,以节省开销

  • COD采用的上采样是3x3 tent filter,这种滤波经过多次卷积可以逼近高斯模糊的效果,但开销比高斯低

  • 效果如下

阈值Fireflies

已经解决了时域闪烁问题,但阈值Fireflies还存在

  • 经典的bloom算法会根据阈值提取亮度,这正是导致Fireflies的元凶!因为这种截断属于非线性的,可能上一帧当前pixel几乎没有亮度,这一帧和其他高亮pixel亮度混合,从而导致一起闪烁

  • Brian Karis 提出一种加权算法,在13-tap 降采样时,不再使用加权平均,而是使用weight = \frac{1}{1 + luma}

    这个公式的优势:

    • 当像素很暗时,weight接近1,正常采样

    • 当像素非常亮时,weight非常小,压低了亮度

  • 如何应用算法呢?

    我们不能统一计算13个pixel的亮度,再应用权重,这样的做法会导致整个区域的能量被过度压制

    正确的做法是,根据上图,五组独立的应用权重

    • 取中间红色的四个点,应用Karis 权重,得到ColorRed
    • 取左上角的黄色四个点,应用Karis 权重,得到ColorYellow
    • 依次应用绿、紫、青三组的权重
    • 最后用权重0.5与0.125加权平均上述计算的颜色,FinalColor = ColorRed * 0.5 + (ColorYellow + ColorGreen + ColorPurple + ColorCyan) * 0.125

    简而言之,这也是种加权平均

总结

  • 上下采样滤波
    • 下采样使用13 tap的滤波
    • 从mip 0到mip 1下采样时,采用Karis的平均缓解Fireflies问题
    • 上采样使用3x3的tent filter
    • 逐级上采样
    • 上采样过程中,同时与已有的mip混合
  • 最终mips数目6,格式为R11G11B10

效果

4k分辨率下,消耗0.35ms

优化

降采样

对于bloom这种低频信息,用降采样效果非常好,不仅性能节省了75%,甚至还能起到模糊的作用

降采样时已经使用硬件的双线性滤波,以混合颜色

如下图,可以看到耗时减到了0.1ms,非常ok

Reference

Next Generation Post Processing in Call of Duty: Advanced Warfare


他们曾如此骄傲的活过,贯彻始终