Unity shader学习之屏幕后期处理效果之高斯模糊

时间:2023-02-02 15:24:29

高斯模糊,见 百度百科

也使用卷积来实现,每个卷积元素的公式为:Unity shader学习之屏幕后期处理效果之高斯模糊

其中б是标准方差,一般取值为1。

x和y分别对应当前位置到卷积中心的整数距离。

由于需要对高斯核中的权重进行归一化,即使所有权重相加为1,因此e前面的系数实际不会对结果产生任何影响。

转载请注明出处:http://www.cnblogs.com/jietian331/p/7238032.html

综上,公式简化为:

G(x,y) = e-(x*x+y*y)/2

因此,高斯核计算代码如下:

 using System;

 namespace TestShell
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("输入需要得到的高斯卷积核的维数(如3,5,7...):"); string input = Console.ReadLine();
int size; if (!int.TryParse(input, out size))
{
Console.WriteLine("不是数字...");
return;
} // 计算
double[] r2 = null;
double[,] r = null;
try
{
r = CalcGaussianBlur(size, out r2);
}
catch (Exception ex)
{
Console.WriteLine("错误: " + ex.Message);
} if (r != null && r2 != null)
{
// 卷积如下:
Console.WriteLine();
Console.WriteLine("{0}x{0}的高斯卷积核如下:", size);
for (int i = ; i < r.GetLongLength(); i++)
{
for (int j = ; j < r.GetLongLength(); j++)
{
Console.Write("{0:f4}\t", r[i, j]);
}
Console.WriteLine();
}
Console.WriteLine(); Console.WriteLine("可拆成2个一维的数组:");
for (int i = ; i < r2.Length; i++)
{
Console.Write("{0:f4}\t", r2[i]);
}
Console.WriteLine();
Console.WriteLine(); Console.WriteLine("验证,使用这2个一维的数组也可以得到同样的结果:");
for (int i = ; i < size; i++)
{
for (int j = ; j < size; j++)
{
Console.Write("{0:f4}\t", r2[i] * r2[j]); }
Console.WriteLine();
}
} Console.WriteLine();
Console.WriteLine("按任意键结束...");
Console.ReadKey();
} static double[,] CalcGaussianBlur(int size, out double[] r2)
{
if (size < )
throw new ArgumentException("size < 3");
if (size % != )
throw new ArgumentException("size % 2 != 1"); double[,] r = new double[size, size];
r2 = new double[size];
int center = (int)Math.Floor(size / 2f);
double sum = ; for (int i = ; i < size; i++)
{
for (int j = ; j < size; j++)
{
int x = Math.Abs(i - center);
int y = Math.Abs(j - center);
double d = CalcItem(x, y);
r[i, j] = d;
sum += d;
}
} for (int i = ; i < size; i++)
{
for (int j = ; j < size; j++)
{
r[i, j] /= sum;
if (i == j)
r2[i] = Math.Sqrt(r[i, i]);
}
} return r;
} static double CalcItem(int x, int y)
{
return Math.Pow(Math.E, -(x * x + y * y) / 2d);
}
}
}

工具在:http://files.cnblogs.com/files/jietian331/CalcGaussianBlur.zip

一个5 x 5的高斯核如下:

Unity shader学习之屏幕后期处理效果之高斯模糊

使用2个一维数组可简化计算量,提高性能,通过观察可知,只需要计3个数:

Unity shader学习之屏幕后期处理效果之高斯模糊

使用unity shader屏幕后期处理来实现高斯模糊,代码如下。

子类:

 using UnityEngine;

 public class GaussianBlurRenderer : PostEffectRenderer
{
[Range(, )]
[SerializeField]
public int m_downSample = ; // 降采样率
[Range(, )]
[SerializeField]
public int m_iterations = ; // 迭代次数
[Range(0.2f, 3f)]
[SerializeField]
public float m_blurSpread = 0.6f; // 模糊扩散量 protected override void OnRenderImage(RenderTexture src, RenderTexture dest)
{
int w = (int)(src.width / m_downSample);
int h = (int)(src.height / m_downSample);
RenderTexture buffer0 = RenderTexture.GetTemporary(w, h);
RenderTexture buffer1 = RenderTexture.GetTemporary(w, h);
buffer0.filterMode = FilterMode.Bilinear;
buffer1.filterMode = FilterMode.Bilinear;
Graphics.Blit(src, buffer0); for (int i = ; i < m_iterations; i++)
{
Mat.SetFloat("_BlurSpread", + i * m_blurSpread); Graphics.Blit(buffer0, buffer1, Mat, );
Graphics.Blit(buffer1, buffer0, Mat, );
} Graphics.Blit(buffer0, dest);
RenderTexture.ReleaseTemporary(buffer0);
RenderTexture.ReleaseTemporary(buffer1);
} protected override string ShaderName
{
get { return "Custom/Gaussian Blur"; }
}
}

GaussianBlurRenderer

shader:

 // Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

 Shader "Custom/Gaussian Blur"
{
Properties
{
_MainTex("Main Texture", 2D) = "white" {}
_BlurSpread("Blur Spread", float) =
} SubShader
{
CGINCLUDE sampler2D _MainTex;
float4 _MainTex_TexelSize;
uniform float _BlurSpread; struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
}; struct v2f
{
float4 pos : SV_POSITION;
float2 uv[] : TEXCOORD0;
}; v2f vertHorizontal(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
float tsx = _MainTex_TexelSize.x * _BlurSpread;
o.uv[] = v.uv + float2(tsx * -, );
o.uv[] = v.uv + float2(tsx * -, );
o.uv[] = v.uv;
o.uv[] = v.uv + float2(tsx * , );
o.uv[] = v.uv + float2(tsx * , );
return o;
} v2f vertVertical(appdata v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
float tsy = _MainTex_TexelSize.y * _BlurSpread;
o.uv[] = v.uv + float2(, tsy * -);
o.uv[] = v.uv + float2(, tsy * -);
o.uv[] = v.uv;
o.uv[] = v.uv + float2(, tsy * );
o.uv[] = v.uv + float2(, tsy * );
return o;
} fixed4 frag(v2f i) : SV_TARGET
{
float g[] = {0.0545, 0.2442, 0.4026};
fixed4 col = tex2D(_MainTex, i.uv[]) * g[];
for(int k = ; k < ; k++)
{
col += tex2D(_MainTex, i.uv[k]) * g[k];
col += tex2D(_MainTex, i.uv[ - k]) * g[k];
}
return col;
} ENDCG Pass
{
Name "HORIZONTAL"
ZTest Always
ZWrite Off
Cull Off CGPROGRAM
#pragma vertex vertHorizontal
#pragma fragment frag
ENDCG
} Pass
{
Name "VERTICAL"
ZTest Always
ZWrite Off
Cull Off CGPROGRAM
#pragma vertex vertVertical
#pragma fragment frag
ENDCG
}
} Fallback Off
}

Custom/Gaussian Blur

调整参数:

Unity shader学习之屏幕后期处理效果之高斯模糊

DownSample,即降采样率,越大性能越好,图像越模糊,但过大可能会使图像像素化。

Iteraitions, 即迭代次数,越大图像模糊效果越好,但性能也会下降。

BlurSpread,即模糊扩散量,越大图像越模糊,但过大会造成虚影。

效果如下:

Unity shader学习之屏幕后期处理效果之高斯模糊 Unity shader学习之屏幕后期处理效果之高斯模糊