一、前言

本文着重围绕如下几点讲解:

  • 高斯模糊的基础实现

  • 高斯模糊的线性分解

  • 高斯模糊的双线性采样

  • cocos后处理应用

为了喜迎cocoscreator3.6.2,本示例工程已升级到3.6.2

二、效果预览

未模糊画面

9x9高斯核4次迭代效果

三、前期准备

首先参考了大佬陈皮皮的帖子,

模糊前

模糊后

效果确实可以,也能做到深度模糊的效果,但是性能比较堪忧,我界面的分辨率是960x640,设置的模糊半径是20的话,每一帧的计算量是960x640x41x41=10.3亿次。(ps:为啥是41? 半径是20,原点是1,就是20+1+20,半径为R,就是(2R+1)x(2R+1)的高斯核),反正是把我的电脑干趴了,将半径调成4,半径4的情况下,计算量是4976万次,效果就是上面截图的效果。那有没有优化空间呢?(由于每次乘960和640难看出数据变化,后续的计算量都除掉这两个值)

四、核心思路

高斯模糊在图像处理领域,通常用于减少图像噪声以及降低细节层次,以及对图像进行模糊,其视觉效果就像是经过一个半透明屏幕在观察图像。

从数字信号处理的角度看,图像模糊的本质一个过滤高频信号,保留低频信号的过程。过滤高频的信号的一个常见可选方法是卷积滤波。从这个角度来说,图像的高斯模糊过程即图像与正态分布做卷积。由于正态分布又叫作“高斯分布”,所以这项技术就叫作高斯模糊。而由于高斯函数的傅立叶变换是另外一个高斯函数,所以高斯模糊对于图像来说就是一个低通滤波器。

说到高斯模糊,就得说到高斯核,高斯核的一个基础模型如下

高斯函数的三维示意图

输入的每个像素点计算时都会将该像素周围一圈的像素点(模糊半径)通过基于高斯核的权重计算一遍然后加起来当做输出值。

高斯模糊也可以在二维图像上对两个独立的一维空间分别进行计算,即满足线性可分(Linearly separable)。这也就是说,使用二维矩阵变换得到的效果也可以通过在水平方向进行一维高斯矩阵变换加上竖直方向的一维高斯矩阵变换得到。从计算的角度来看,这是一项有用的特性,因为这样只需要 M * N * m + M * N * n 的计算复杂度,而原先的计算复杂度为M * N * n * m ,其中M, N是需要进行滤波的图像的维数(像素),m、n是滤波器的维数(模糊半径)。

以下为一个Gaussian Kernel的线性分解过程:

上图是滤波5次,杨辉三角展示了二项式系数,它可以用来计算卷积核权重(每个元素是上一排的两个相邻元素的和)。

杨辉三角

我们以最下面一行当做数据样本,最下面一行的数字和是4096,因为1/4096和12/4096的值比较小,我们为了保持更加nice的效果,可将1和12的参数去掉,那数字和就成了4070,每个的权重就是[66,220,495,792,924]/4070。

五、实现过程

因为目前cocos 还不支持后处理,所以我们弄个相机将场景渲染成renderTexture,再用Sprite装载,最后用Canvas的相机渲染到屏幕,在测试时发现了一些小问题,流程可以参考我之前发的帖子

我们以总权重为4070的9 X 9高斯核开始学习。

5.1、N X M -> N + M

        _BlurOffsetX: {value: 0,editor: { slide: true, range: [0, 1.0], step: 0.0001 }}_BlurOffsetY: {value: 0,editor: { slide: true, range: [0, 1.0], step: 0.0001 }}

首先定义2个uniform去记录单个像素的uv偏移,做了2个进度条可以动态调整水平和垂直方向的uv偏移,其中size是屏幕的尺寸,因为进度条是从0~1的,所以除以size后就变成了单个像素的uv偏移(ps:我这里用2做了缩放,调到最大相当于每次的偏移量是2个像素,只是为了测试效果)。

顶点着色器没做任何修改,片段着色器代码如下,因为是9X9 所以

  vec4 GaussianBlur() {// 原点vec4 color = 0.2270270270 * CCSampleWithAlphaSeparated(cc_spriteTexture, uv0);// 右边/上方的采样点color += 0.1945945946 * CCSampleWithAlphaSeparated(cc_spriteTexture, uv0 + vec2(1.0 * _BlurOffsetX  , 1.0 * _BlurOffsetY ));color += 0.1216216216 * CCSampleWithAlphaSeparated(cc_spriteTexture, uv0 + vec2(2.0 * _BlurOffsetX  , 2.0 * _BlurOffsetY ));color += 0.0540540541 * CCSampleWithAlphaSeparated(cc_spriteTexture, uv0 + vec2(3.0 * _BlurOffsetX  , 3.0 * _BlurOffsetY ));color += 0.0162162162 * CCSampleWithAlphaSeparated(cc_spriteTexture, uv0 + vec2(4.0 * _BlurOffsetX  , 4.0 * _BlurOffsetY ));// 左边/下方的采样点color += 0.1945945946 * CCSampleWithAlphaSeparated(cc_spriteTexture, uv0 + vec2(-1.0 * _BlurOffsetX  , -1.0 * _BlurOffsetY ));color += 0.1216216216 * CCSampleWithAlphaSeparated(cc_spriteTexture, uv0 + vec2(-2.0 * _BlurOffsetX  , -2.0 * _BlurOffsetY ));color += 0.0540540541 * CCSampleWithAlphaSeparated(cc_spriteTexture, uv0 + vec2(-3.0 * _BlurOffsetX  , -3.0 * _BlurOffsetY ));color += 0.0162162162 * CCSampleWithAlphaSeparated(cc_spriteTexture, uv0 + vec2(-4.0 * _BlurOffsetX  , -4.0 * _BlurOffsetY ));return color;}

将进度条拉到最大,我们得到了一次模糊的效果,效果如下(这个效果其实是有问题的,后面会讲)

一次模糊

这个效果跟9x9的模糊效果基本一致,但是计算量从9x9=81缩减到了9+9=18

5.2、多次滤波

想要实现多次滤波,必须是经过一次滤波之后,将本次输出图片的结果当做参数传到第二次滤波,在unity里用后处理可以轻松的操作,但是cocos creator后处理的功能还在重构中,只能使用另外一种方案:分层+多相机。

在项目设置中,我加了8个Step,并在Canvas地方摆放了8个精灵,每个精灵对应一个Step,并创建了8个摄像机分别去拍这8个精灵,并且摄像机的渲染优先级从低到高,这样8个摄像机总共可以滤波8次。这里我参考了社区的佛光普照教程,这个demo真是强大,当我对cocos的后处理处于迷茫状态时,这个demo对我来说所得即所需。这里封装好的代码我就不细说了,可以直接下载demo了解。

于是我按上面的代码,对模糊结果处理了4次,得到如下的效果:

四次模糊

我发现有模糊后的细节发生了扭曲,这肯定是哪里出了点问题,我们回到之前看到的公式 NxN 转化成 Nx1 与1xN,是需要Nx1计算完了再去计算1xN的,而我目前的算法是2者一起计算,用大白话说,原本只计算了水平模糊,再计算垂直模糊,现在我水平和垂直交替处理,那在第二次迭代时,本应该只计算垂直方向的像素值已经被第一次迭代给污染了,导致最终结果有点不一致,所以模糊结果发生了扭曲。

5.1、修正后的多次滤波

所以我们的代码要进行修正,下面是修正后的代码:

我们先用一个pass只处理水平方向的,再用一个pass处理垂直方向的,水平、垂直交叉出现,我将这个理解成乒乓交叉。虽然经过4个pass处理,但是它其实还只是算2次迭代。效果如下:

采用乒乓交叉的两次迭代

这张图对比上一张图,我们可以看出前所未有的丝滑,而且模糊效果也比最初的强一些,所以随着迭代次数的增加,模糊效果也会增加,那我就试试4次迭代。得到的效果如下:

采用乒乓交叉的四次迭代

此时的模糊程度比最初的效果强得多,此时的计算量是9x4x2 = 72次,比原本的81次还要少,更少的计算量却能得到更好的模糊效果,但是你以为这就完了嘛?

5.4、线性采样

到此为止,我们假设了必须要做一次贴图读取来获得一个像素的信息,意味着9个像素需要9次贴图读取。尽管这对于在CPU上的实现来说是成立的,但在GPU上却不总是这样。这是因为在GPU上可以随意地使用双线性插值(bilinear sampling)而没有什么额外的负担。这意味着如果不在纹素中心读取贴图,就可以得到多个像素的信息。既然已经利用了高斯函数的可分离性,实际上是在1D下工作,双线性插值会提供2个像素的信息。每个纹素贡献对颜色的贡献量则由使用的坐标决定。

通过正确地调整贴图读取的坐标偏移,可以仅通过一次贴图读取得到两个像素或纹素的准确信息。这意味着为了实现一个9x1或1x9的高斯滤波器只需要5次贴图读取。总的来说,实现Nx1或1xN的滤波器需要[N/2]次贴图读取。

怎么理解这一句话呢?

于是根据上面的公式,算出A点的坐标是1.3846153846 B点的坐标是3.2307692308

将其带入到之前的片段着色器中,代码如下:

双线性采样

这时候你会发现跟之前的结果几乎一样,但此时的计算量是5x4x2 = 20

如果去掉4次迭代的效果,只需要原本的9x9的效果,计算量只需要5x2 = 10次 是不是极大提升了性能呢?

六、最终代码

完整工程 git@gitee.com:onion92/cocos3d-shader-effect.git

七、小结

如果你需要深度模糊的效果,不妨增加迭代次数,或者加大采样半径,采用双线性采样,即使是13x13的高斯核,一次迭代也只需要7x2=14次计算。

八、后话

停了几个月的笔了,前段时间项目比较赶,在项目中做了一个高斯模糊和径向模糊,刚好这次cocos有个征文大赛以及项目出现真空期,于是就有了这篇帖子。(ps:上班的时间用来写文章什么的,最喜欢了)

本来想写个高斯模糊、径向模糊后,再搞个远景模糊的,结果一个高斯模糊下去竟然意想不到的发现了双线性采样带来的优化以及后处理的首次真正使用(以前搞的renderTexture只能处理一次,算啥后处理嘛),嗯,看来回顾旧的知识还是会有提升的嘛,温故而知新,古人诚不欺我!

有兴趣的同学可以关注一下我的公众号。你们的支持是我创作的动力!

泉小墨

感谢各位的观看,希望在渲染的道路上与君共勉,相互成长!

CocosCreator高斯模糊深度优化版相关推荐

  1. 深度完美 Ghost XP SP3 纯净优化版V2011.11

    深度完美 Ghost XP SP3 纯净优化版V2011.11 深度完美Ghost 系统采用最新的封装技术,全面提升系统在计算机上的部署速度,恢复效率更高. 系统中集成2000年以后流行的各种硬件驱动 ...

  2. 深度完美 GHOST XP SP3 快速装机优化版 V2010.06推荐给大家

    软件名称:深度完美 GHOST XP SP3 快速装机优化版 V2010.06 软件类型:国产软件 运行环境:Win9X/2000/XP/2003/ 软件语言:简体中文 授权方式:共享版 软件大小:6 ...

  3. 【转】深度完美GhostXP_SP3快速装机优化版V2011.12

    深度完美GhostXP_SP3快速装机优化版V2011.12 [白金品质 精品典范]深度完美GHOSTXPSP3快速装机优化版V2011.12============================= ...

  4. n9009+android+4.4.2,三星N9009电信双卡版刷机包 基于官方深度优化 精简冗余应用 极度纯净 操作流畅...

    三星N9009电信双卡版刷机包 基于官方深度优化 精简冗余应用 极度纯净 操作流畅. 温馨提示: 刷机前确认原手机系统已root.以免造成不必要的麻烦 *_*!!!老话说:刷机需谨慎,刷前请备份.各位 ...

  5. ASUS ROG Win10.21H1 x64专业工作站极速精简优化版

    华硕ROG Win10.21H1 x64专业工作站极速精简优化版由购买的ASUS恢复OEM镜像通过适度精简,深度优化制作,保持了一贯的稳定快速的风格,系统设计,布局十分完美,纯尽简洁,安装简单. 没集 ...

  6. 转 FTP搜索引擎的设计与实现(优化版)

    width="336" height="280" src="http://www.zealware.com/csdnblog336280.html&q ...

  7. 基于Hexo的matery主题搭建博客并深度优化

    本文转自 悟尘纪,获取更新内容可查看原文: https://www.lixl.cn/2019/092856736.html 对于有一定技术背景的同学,自己动手搭建博客网站是一个很不错的选择.选择喜欢的 ...

  8. Win7纯手动深度优化系统

    深度优化前,首先要做几件事. 1.重装完新系统,所有驱动,补丁,程序都OK后,断网最新病毒库全盘查杀. 2.备份系统,非微软自带备份,此项应关闭. 3.阅读10则常见Win7优化误区 教你正确优化Wi ...

  9. YOLO3升级优化版!Poly-YOLO:支持实例分割!

    YOLO3升级优化版!Poly-YOLO:支持实例分割! POLY-YOLO: HIGHER SPEED, MORE PRECISE DETECTION AND INSTANCE SEGMENTATI ...

最新文章

  1. NHibernate Step By Step(10)-常用的配置属性
  2. linux配置selenium路径,Linux配置Selenium+Chrome+Python
  3. 部门选择控件源代码公布
  4. python展示文件_python 文件操作实力显示
  5. 在网页中的flash游戏,按方向键浏览器的滚动条会跟着滚动
  6. java集合表_java集合类散列表
  7. Android 系统性能优化(81)---Android后台优化系列-background optimization-初识低耗电模式
  8. arcobject c++实现检查要素是否为multipart(准确而且快 最主要是real 网上代码有问题)
  9. python常见面试题(三)
  10. mnist数据集下载linux,机器学习数据集篇——MNIST数据集
  11. 2021微信网页跳转APP
  12. 程序设计与数据结构_周立功【读书笔记】
  13. 《周易》中的君子形象--http://cul.china.com.cn/guoxue/2018-06/04/content_40369049.htm
  14. 对“淡泊以明志,宁静以致远”的理解
  15. css案例17——圆角头像
  16. VMware虚拟机装系统提示Units specified dont exist!
  17. 解决安装文件时2502、2503错误
  18. 30岁转行做程序员是一种怎样的体验?
  19. 端口号,UDP,TCP
  20. CPU和GPU的简介

热门文章

  1. 用selenium来下载小姐姐图片并保存
  2. mstsc远程登录windows服务器
  3. Chapter 2 认识游戏
  4. python-求无理数e的近似值
  5. 新一配:perl循环调用python爬虫批量下载喜马拉雅音频
  6. html 边框素材,2000+ 精美蕾丝、花边、边框素材
  7. 一文搞懂指标采集利器 Telegraf
  8. R语言学习-----数据的载入
  9. 青龙面板-- 咸鱼吃鱼(废-已不能使用)
  10. 加法链POJ2248