大部分解释说明都在代码注释里面,部分代码很长,本人进行了折叠,帮助更好理清思路,推荐复制放入VS CODE观看
VS Code 展开/折叠快捷键:ctrl+k 再 ctrl+j/0
高斯模糊
-
高斯核的构建
G ( x , y ) = 1 2 π σ 2 e − x 2 + y 2 2 σ 2 G(x,y)=\frac{1}{2\pi\sigma^2}e^{-\frac{x^2+y^2}{2\sigma^2}} G(x,y)=2πσ21e−2σ2x2+y2
很简单,从二维正态分布中均匀的采样(按照矩阵的形状),得到采样点的值,之后归一化即可
-
模糊的程度与参数的关系:
核的范围越大,模糊程度越高
核的分布越重尾,模糊程度越高(存疑,还没有实验)
模糊运算的次数越多越模糊
-
高斯核的分解:
由于卷积核是二维的,其运算量是随边长平方数增长的,负担太大;
若能分解为两个一维的,其运算量只会线性增长
将上述的两条,当作两个模糊核,分别做一次模糊运算,其结果和一个二维高斯模糊是一致的,这大大减少了运算
另外由于两条的权值是一样的,单独的也是对称的,所以对于一个高斯核的存储,可以大大压缩: 5 × 5 5\times5 5×5的高斯核实际上只用存3个数字
在实际计算中,会用到两个Pass,分别对应两条一维核(猜测是由于两个核不同,所以不能共用一个pass?)
实际上为了节省运算,一般还需要缩放图像来节省运算(先把图像分辨率降低,再模糊,反正都是模糊)
代码
脚本
using UnityEngine;
public class G_Blur : PostEffectsBase
{
public Shader G_Blur_Shader;
private Material G_Blur_Mat = null;
public Material material{
get{
G_Blur_Mat = CheckShader_CreateMat(G_Blur_Shader,G_Blur_Mat);
return G_Blur_Mat;
}
}
//迭代次数
[Range(0,4)]
public int iterations = 3;
//控制相邻两个采样点的距离
[Range(0.2f, 10.0f)]
public float blurSpread = 0.6f;
//下采样次数 这个参数是控制图像分辨率的,越多次图像越像素
[Range(1,8)]
public int downSample = 2;
//1.0这里参数中就直接创建了两个纹理变量
// void OnRenderImage(RenderTexture src, RenderTexture dest)
// {
// if (material != null)
// {
// //这里我们建立了一块缓冲区,大小与屏幕一致
// //原因因为两次模糊需要两个Pass,所以在第一次模糊后不能直接输出到目标纹理,而是先输出到缓冲中暂存
// int rtW = src.width; //src因为是渲染纹理,所以其长宽和屏幕一致
// int rtH = src.height;
// RenderTexture buffer = RenderTexture.GetTemporary(rtW, rtH,0); //这个函数能分配一块缓存用来作buffer
//列,调用第1个pass进行第一次模糊,并存储到刚才创建的缓冲中
// Graphics.Blit(src, buffer, material, 0);
//行,调用第2个pass,输出到目标纹理
// Graphics.Blit(buffer, dest, mate