后处理 - 均值模糊

原理

就是取自身以及该像素周围的8个像素的颜色值相加,然后除9取个平均值,得到最终颜色值

 

效果

因为模糊后会出现一些方形的像素效果,模糊效果不是很平均,所以均值模糊也叫做盒状模糊。

 

c#代码

using UnityEngine;

public class BoxBlurEff : MonoBehaviour
{
    public Shader m_Shader;
    public Material m_Material;

    [Range(-3, 3)]
    public float m_BlurOffset = 1;

    void Start()
    {
        InitMaterial();
    }

    private void InitMaterial()
    {
        if (false == SystemInfo.supportsImageEffects)
        {
            Debug.LogWarning("This platform does not support image effects or render textures.");
            this.enabled = false;
            return;
        }

        if (null == m_Material)
        {
            if (null != m_Shader && m_Shader.isSupported)
            {
                m_Material = new Material(m_Shader);
                m_Material.hideFlags = HideFlags.DontSave;
            }
        }
        else if (null != m_Shader && m_Material.shader != m_Shader)
        {
            if (m_Shader.isSupported) //优先shader
            {
                m_Material = new Material(m_Shader);
                m_Material.hideFlags = HideFlags.DontSave;
            }
            else
            {
                m_Material = null;
            }
        }

        if (null != m_Material)
            m_Material.SetFloat("_BlurOffset", m_BlurOffset);
    }

    private void ReleaseRT(RenderTexture rt)
    {
        if (rt != null) RenderTexture.ReleaseTemporary(rt);
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (null == m_Material)
        {
            Graphics.Blit(source, destination);
        }
        else
        {
#if UNITY_EDITOR
            m_Material.SetFloat("_BlurOffset", m_BlurOffset);
#endif
            Graphics.Blit(source, destination, m_Material, 0);
        }
    }
    
}

 

shader

Shader "My/PostEff/BoxBlur"
{
	CGINCLUDE
	#include "UnityCG.cginc"

	sampler2D _MainTex;
	float4 _MainTex_TexelSize; //贴图大小信息, 1/width, 1/height, width, height

	float _BlurOffset;

	fixed4 fragBoxBlur(v2f_img i) : SV_Target //片元着色器(逐像素)
	{
		//均值模糊, 这边没有采样9个, 只采样了上下左右4个, 速度更快
		float4 colBlur = 0;
		// (1/width, 1/height, -1/width, -1/height)*_BlueOffset
		float4 blurUV = _MainTex_TexelSize.xyxy * float4(1, 1, -1, -1) * _BlurOffset; //控制采样上下左右1个像素还是n个像素
		colBlur += tex2D(_MainTex, i.uv + blurUV.xy);//1,1
		colBlur += tex2D(_MainTex, i.uv + blurUV.xw);//1,-1
		colBlur += tex2D(_MainTex, i.uv + blurUV.zy);//-1,1
		colBlur += tex2D(_MainTex, i.uv + blurUV.zw);//-1,-1

		half4 col = tex2D(_MainTex, i.uv); //获取像素颜色
		col.rgb = colBlur.rgb / 4;
		return col;
	}
	ENDCG

	Properties
	{
		_MainTex("Texture", 2D) = "white" {} //主贴图
		_BlurOffset("BlurOffset", Float) = 1 //模糊偏移
	}
	SubShader
	{
		Cull Off //剔除关闭
		ZWrite Off //写入深度buff关闭
		ZTest Always //深度测试开始

		Pass //Pass0
		{
			CGPROGRAM
			#pragma vertex vert_img
			#pragma fragment fragBoxBlur

			ENDCG
		}

		Pass //Pass1
		{
			CGPROGRAM
			#pragma vertex vert_img
			#pragma fragment fragBoxBlur

			ENDCG
		}
	}

}

 

双重模糊

单次的均值模糊,其实效果并不是很好,这边可以通过双重模糊来优化模糊效果

原理:将图片分辨率降低1倍(降采样),做一次模糊,再降1倍,做一次模糊;

然后再将分辨率升1倍(升采样),做一次模糊,再升1倍,做一次模糊。

 

using UnityEngine;

public class BoxBlurEff : MonoBehaviour
{
    public Shader m_Shader;
    public Material m_Material;

    [Range(-3, 3)]
    public float m_BlurOffset = 1;

    public bool m_DoubleBlur;

    private int m_SrcRTWidth;
    private int m_SrcRTHeight;

    private RenderTexture m_RTHalfSize; //一半大小
    private RenderTexture m_RTQuarterSize; //1/4大小

    void Start()
    {
        InitMaterial();
    }

    private void InitMaterial()
    {
        if (false == SystemInfo.supportsImageEffects)
        {
            Debug.LogWarning("This platform does not support image effects or render textures.");
            this.enabled = false;
            return;
        }

        if (null == m_Material)
        {
            if (null != m_Shader && m_Shader.isSupported)
            {
                m_Material = new Material(m_Shader);
                m_Material.hideFlags = HideFlags.DontSave;
            }
        }
        else if (null != m_Shader && m_Material.shader != m_Shader)
        {
            if (m_Shader.isSupported) //优先shader
            {
                m_Material = new Material(m_Shader);
                m_Material.hideFlags = HideFlags.DontSave;
            }
            else
            {
                m_Material = null;
            }
        }

        if (null != m_Material)
            m_Material.SetFloat("_BlurOffset", m_BlurOffset);
    }

    private void ReleaseRT(RenderTexture rt)
    {
        if (rt != null) RenderTexture.ReleaseTemporary(rt);
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (null == m_Material)
        {
            Graphics.Blit(source, destination);
        }
        else
        {
#if UNITY_EDITOR
            m_Material.SetFloat("_BlurOffset", m_BlurOffset);
#endif
            if (m_DoubleBlur)
                DoubleBlur(source, destination);
            else
                Graphics.Blit(source, destination, m_Material, 0);
        }
    }

    private void DoubleBlur(RenderTexture source, RenderTexture destination)
    {
        if (m_SrcRTWidth != source.width || m_SrcRTHeight != source.height)
        {
            m_SrcRTWidth = source.width;
            m_SrcRTHeight = source.height;
            m_RTHalfSize = RenderTexture.GetTemporary((int)(m_SrcRTWidth * 0.5f), (int)(m_SrcRTHeight * 0.5f));
            m_RTQuarterSize = RenderTexture.GetTemporary((int)(m_SrcRTWidth * 0.25f), (int)(m_SrcRTHeight * 0.25f));
        }

        //降采样
        Graphics.Blit(source, m_RTHalfSize, m_Material, 0);
        Graphics.Blit(m_RTHalfSize, m_RTQuarterSize, m_Material, 1);

        //升采样
        Graphics.Blit(m_RTQuarterSize, m_RTHalfSize, m_Material, 0);
        Graphics.Blit(m_RTHalfSize, destination, m_Material, 1); 
    }

    void OnDestroy()
    {
        if (null != m_RTHalfSize)
        {
            RenderTexture.ReleaseTemporary(m_RTHalfSize);
            RenderTexture.ReleaseTemporary(m_RTQuarterSize);
            m_RTHalfSize = null;
            m_RTQuarterSize = null;
        }
    }

}

效果

 

参考

Unity自定义后处理——模糊效果_unity图片模糊效果-CSDN博客

UnityShader实例13:屏幕特效之均值模糊(Box Blur) - yjbjingcha - 博客园 (cnblogs.com)

 

posted @ 2024-03-28 23:24  yanghui01  阅读(8)  评论(0编辑  收藏  举报