# 【均值模糊】
# 盒状模糊
注意在实现同样效果的情况下,尽量减少迭代次数。
均值模糊也称为盒状模糊,原理是采样像素点上下左右的像素累加求平均。
把这个 BoxBlur.cs 脚本挂在需要模糊的摄像机上。
Assets\ScreenAfterEffect\Blur\BoxBlur.cs
using UnityEngine;
[ExecuteInEditMode()]
public class BoxBlur : MonoBehaviour
{
public Material material;
[Range(0,10)]
public int _Iteration = 4;
[Range(0,15)]
public float _BlurRadius = 5.0f;
void Start()
{
if(material == null || material.shader == null || material.shader.isSupported == false)
{
enabled = false;
return;
}
}
private void OnRenderImage(RenderTexture src, RenderTexture dest) {
int width = (int)src.width/4; // 除以4是为了提升性能
int height = (int)src.height/4;
RenderTexture RT1 = RenderTexture.GetTemporary(width,height);
RenderTexture RT2 = RenderTexture.GetTemporary(width,height);
Graphics.Blit(src, RT1,material,0);
material.SetVector("_BlurOffset", new Vector4(_BlurRadius/width,_BlurRadius/height,0,0));
for (int i = 0; i < _Iteration; i++)
{
Graphics.Blit(RT1,RT2 ,material,0);
Graphics.Blit(RT2,RT1 ,material,0);
}
Graphics.Blit(RT1,dest,material,0);
RenderTexture.ReleaseTemporary(RT1);
RenderTexture.ReleaseTemporary(RT2);
}
}
BoxBlur 使用的 material 使用以下Shader 进行创建。
Assets\ScreenAfterEffect\Blur\BoxBlurShader.shader
Shader "Hidden/BoxBlurShader"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_BlurOffset("BlurOffset",Float) = 1.0
}
SubShader
{
// No culling or depth
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert_img
#pragma fragment frag
#include "UnityCG.cginc"
sampler2D _MainTex;
float4 _BlurOffset;
fixed4 frag (v2f_img i) : SV_Target
{
fixed4 col = tex2D(_MainTex, i.uv);
half4 d = _BlurOffset.xyxy * half4(-1,-1,1,1);
half4 s = 0;
s += tex2D(_MainTex,i.uv + d.xy);
s += tex2D(_MainTex,i.uv + d.zy);
s += tex2D(_MainTex,i.uv + d.xw);
s += tex2D(_MainTex,i.uv + d.zw);
s *= 0.25;
return s;
}
ENDCG
}
}
}
# 双重模糊
模糊效果更好,这种更加适用于游戏中使用,也适合用于泛光Bloom。
Shader代码与上面的一致。
通过模糊过程中缩小采样,然后放大,减少相邻的格子重影效果。
Assets\ScreenAfterEffect\Blur\DualBlur.cs
using UnityEngine;
[ExecuteInEditMode()]
public class DualBlur : MonoBehaviour
{
public Material material;
[Range(0,4)]
public int _Iteration = 4;
[Range(0,15)]
public float _BlurRadius = 5.0f;
void Start()
{
if(material == null || material.shader == null || material.shader.isSupported == false)
{
enabled = false;
return;
}
}
private void OnRenderImage(RenderTexture src, RenderTexture dest) {
int width = (int)src.width;
int height = (int)src.height;
RenderTexture RT1 = RenderTexture.GetTemporary(width,height);
RenderTexture RT2 = RenderTexture.GetTemporary(width,height);
Graphics.Blit(src, RT1,material,0);
material.SetVector("_BlurOffset", new Vector4(_BlurRadius/width,_BlurRadius/height,0,0));
// 缩小
for (int i = 0; i < _Iteration; i++)
{
width = width/2;
height = height/2;
RenderTexture.ReleaseTemporary(RT2);
RT2 = RenderTexture.GetTemporary(width,height);
Graphics.Blit(RT1,RT2 ,material,0);
width = width/2;
height = height/2;
RT1 = RenderTexture.GetTemporary(width,height);
RenderTexture.ReleaseTemporary(RT1);
Graphics.Blit(RT2,RT1 ,material,0);
}
// 放大
for (int i = 0; i < _Iteration; i++)
{
width = width*2;
height = height*2;
RenderTexture.ReleaseTemporary(RT2);
RT2 = RenderTexture.GetTemporary(width,height);
Graphics.Blit(RT1,RT2 ,material,0);
width = width*2;
height = height*2;
RT1 = RenderTexture.GetTemporary(width,height);
RenderTexture.ReleaseTemporary(RT1);
Graphics.Blit(RT2,RT1 ,material,0);
}
Graphics.Blit(RT1,dest,material,0);
RenderTexture.ReleaseTemporary(RT1);
RenderTexture.ReleaseTemporary(RT2);
}
}