注意别爆显存!!

原文地址:Unity UI背景模糊显示_wx667a71ca4e53b的技术博客_51CTO博客

原理就是提取相机拍摄画面,然后材质处理后再返回一个RenderTexture,然后赋值给RawImage,唯一缺点,就是如果释放不及时,容易爆显存。

BlurShader.shader

Shader "Unlit/BlurShader"
{
    Properties
    {
        _MainTex ("Texture", 2D) = "white" {}
        _BlurSize("BlurSize", Range(0, 127)) = 1.0
    }
    SubShader
    {
        CGINCLUDE
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            half4 _MainTex_TexelSize; 
            fixed _BlurSize;

            struct v2f{
                float4 pos : SV_POSITION;
                half2 uv[5] : TEXCOORD0;
            };

            // 水平uv数据扩展采样
            v2f vert_hor(appdata_img v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                half2 uv = v.texcoord;

                // 下标从0开始,分别取到当前像素,偏移1单位和2单位的uv位置
                o.uv[0] = uv;
                o.uv[1] = uv + half2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
                o.uv[2] = uv - half2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;

                o.uv[3] = uv + half2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
                o.uv[4] = uv - half2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;

                return o;
            }

            // 水平uv数据扩展采样
            v2f vert_ver(appdata_img v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                half2 uv = v.texcoord;

                // 下标从0开始,分别取到当前像素,偏移1单位和2单位的uv位置
                o.uv[0] = uv;
                o.uv[1] = uv + half2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
                o.uv[2] = uv - half2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;

                o.uv[3] = uv + half2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
                o.uv[4] = uv - half2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;

                return o;
            }

            // 处理模糊片元
            fixed4 frag(v2f i) : SV_TARGET
            {
                // 模糊算子,分别决定了当前像素,上下(左右)偏移1个单位和2个单位的计算权重
                // 算子决定了模糊的质量,算子越大越复杂效果越好,当然性能上就要差一些
                half weight[3] = {0.4026, 0.2442, 0.0545};

                // 当前像素片元颜色(乘以权重)
                fixed3 color = tex2D(_MainTex, i.uv[0]).rgb * weight[0];
                // 根据权重叠加上下(左右)像素颜色
                color += tex2D(_MainTex, i.uv[1]).rgb * weight[1];
                color += tex2D(_MainTex, i.uv[2]).rgb * weight[1];
                color += tex2D(_MainTex, i.uv[3]).rgb * weight[2];
                color += tex2D(_MainTex, i.uv[4]).rgb * weight[2];

                return fixed4(color, 1.0);
            }
        ENDCG

        Cull Off
        ZWrite Off
        Pass // 0:处理水平模糊
        {
            Name "BLUR_HORIZONTAL"
            CGPROGRAM
            #pragma vertex vert_hor
            #pragma fragment frag
            ENDCG
        }

        Pass // 1:处理垂直模糊
        {
            Name "BLUR_VERTICAL"
            CGPROGRAM
            #pragma vertex vert_ver
            #pragma fragment frag
            ENDCG
        }
    }
    Fallback Off
}

BlurEffectMgr.cs

using UnityEngine;

public class BlurEffectMgr
{
    private static BlurEffectMgr instance;
    public static BlurEffectMgr Instance
    {
        get
        {
            if (instance == null)
                instance = new BlurEffectMgr();
            return instance;
        }
    }
    private Camera Cam;
    private RenderTexture blurRt;

    RenderTexture tempRt;
    public RenderTexture GetBlurRanderTexture(Camera Cam,Material blurMat,float blurLv = 1)
    {
        //Material blurMat = new Material(Resources.Load<Material>("Material/BlurEffect"));//这是刚刚创建的材质球
        //Cam = GameObject.Find("Main Camera Full").GetComponent<Camera>();//用来获取相机的渲染画面
        int width = Screen.width;
        int height = Screen.height;
        blurRt = RenderTexture.GetTemporary(width, height, 0);//尺寸我设置1/4,优化性能
        Cam.targetTexture = blurRt;
        Cam.Render();
        Cam.targetTexture = null;
        int count = 0;
        tempRt = RenderTexture.GetTemporary(width, height, 0);//创建一张临时存放画面
        while (count <= blurLv)//blurLv越大,画面越糊
        {
            blurMat.SetFloat("_BlurSize", (1.0f + count) * blurLv);
            Graphics.Blit(blurRt, tempRt, blurMat, 0);
            Graphics.Blit(tempRt, blurRt, blurMat, 1);
            count++;
        }
        RenderTexture.ReleaseTemporary(tempRt);
        return blurRt;
    }
    //不需要时,回收模糊背景图
    public void ReleaseBlurRenderTexture()
    {
        RenderTexture.ReleaseTemporary(blurRt);
    }
}

TestView.cs

using System;
using UnityEngine;
using UnityEngine.UI;

public class TestView : MonoBehaviour
{
    public RawImage BlurBg;
    public Camera Camera;
    public Material BlurMat;
    public float BlurLv;
    RenderTexture BlurRt;
    void Start()
    {
        
    }

    private void LateUpdate()
    {
        BlurRt?.Release();
        BlurEffectMgr.Instance.ReleaseBlurRenderTexture();
        BlurRt = BlurEffectMgr.Instance.GetBlurRanderTexture(Camera,BlurMat,BlurLv);//获取模糊图片
        BlurBg.texture = BlurRt;
    }

    private void OnDisable()
    {
    }
}