Unity UI背景实现毛玻璃虚化

一、创建一个用来控制效果开启和关闭的开关,获取处理过的贴图的管理类

using UnityEngine;

public class GlassCtrl : MonoBehaviour
{
    public static int Iterations = 2;//高斯模糊处理次数
    public static int takeShot = 0;//1只处理一次获取贴图,-1一直处理更新贴图
    public static RenderTexture renderTexture = null;//保存处理过的贴图

    public void StartTakeShot(int width, int height, int takeShot)
    {
        ReleaseRenderTexture();
        renderTexture = new RenderTexture(width, height, 32);
        GlassCtrl.takeShot = takeShot;
    }

    public void StopTakeShot()
    {
        takeShot = 0;
    }

    public void SetIterations(int time)
    {
        Iterations = time;
    }

    public void ReleaseRenderTexture()
    {
        if (renderTexture != null)
        {
            Destroy(renderTexture);
            renderTexture = null;
        }

    }

    public RenderTexture GetShotTexture()
    {
        return renderTexture;
    }
}


二、创建一个ScriptableRenderPass

using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class GlassBlurRenderPass : ScriptableRenderPass
{
    private CommandBuffer cmd;
    private string cmdName;
    private RenderTargetHandle dest;
    private Material m_blurMat;
    private RenderTargetIdentifier source { get; set; }
    RenderTargetHandle m_temporaryColorTexture;
    RenderTargetHandle blurredID;
    RenderTargetHandle blurredID2;
    public GlassBlurRenderPass(GlassBlurRenderPassFeature.Settings param)
    {
        renderPassEvent = param.renderEvent;
        cmdName = param.cmdName;
        m_blurMat = param.blurMat;
 
        blurredID.Init("blurredID");
        blurredID2.Init("blurredID2");
    }
    
    public void Setup(RenderTargetIdentifier src, RenderTargetHandle _dest)
    {
        this.source = src;
        this.dest = _dest;
    }
    
     public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        if (GlassCtrl.takeShot == 0)
            return;
        if (renderingData.cameraData.isSceneViewCamera) return;
        //如果cullingMask非UI层的camera,返回
        // if (!((renderingData.cameraData.camera.cullingMask & 1<<LayerMask.NameToLayer("UI")) > 0))
        //     return;
 
        cmd = CommandBufferPool.Get(cmdName);
        Vector2[] sizes = {
                new Vector2(Screen.width, Screen.height),
                new Vector2(Screen.width / 2, Screen.height / 2),
                new Vector2(Screen.width / 4, Screen.height / 4),
                new Vector2(Screen.width / 8, Screen.height / 8),
            };
 
        RenderTextureDescriptor opaqueDesc = renderingData.cameraData.cameraTargetDescriptor;
 
        opaqueDesc.depthBufferBits = 0;
        cmd.GetTemporaryRT(m_temporaryColorTexture.id, opaqueDesc, FilterMode.Bilinear);
        cmd.Blit(source, m_temporaryColorTexture.Identifier());
        for (int i = 0; i < GlassCtrl.Iterations; ++i)
        {
 
            cmd.GetTemporaryRT(blurredID.id, opaqueDesc, FilterMode.Bilinear);
            cmd.GetTemporaryRT(blurredID2.id, opaqueDesc, FilterMode.Bilinear);
 
            cmd.Blit(m_temporaryColorTexture.Identifier(), blurredID.Identifier());
            cmd.SetGlobalVector("offsets", new Vector4(2.0f / sizes[i].x, 0, 0, 0));
            cmd.Blit(blurredID.Identifier(), blurredID2.Identifier(), m_blurMat);
            cmd.SetGlobalVector("offsets", new Vector4(0, 2.0f / sizes[i].y, 0, 0));
            cmd.Blit(blurredID2.Identifier(), blurredID.Identifier(), m_blurMat);
 
            cmd.Blit(blurredID.Identifier(), m_temporaryColorTexture.Identifier());
        }
//把最终内容Blit到一个RenderTexture上。
        cmd.Blit(blurredID.Identifier(), GlassCtrl.renderTexture);
        if (GlassCtrl.takeShot == 1)
            GlassCtrl.takeShot = 0;
        
 
        context.ExecuteCommandBuffer(cmd);
        CommandBufferPool.Release(cmd);
        //Debug.LogError("glass pass render");
    }
}


使用的shader为:

Shader "PostEffect/SeparableGlassBlur" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "" {}
	}

	HLSLINCLUDE
	
	#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"

	struct appdata_img {
		float4 vertex:POSITION;
		float2 texcoord:TEXCOORD0;
	};
	struct v2f {
		float4 pos : POSITION;
		float2 uv : TEXCOORD0;

		float4 uv01 : TEXCOORD1;
		float4 uv23 : TEXCOORD2;
		float4 uv45 : TEXCOORD3;
	};
	
	float4 offsets;
	
	sampler2D _MainTex;
	
	v2f vert (appdata_img v) {
		v2f o;
		VertexPositionInputs vertexInput = GetVertexPositionInputs(v.vertex.xyz);
		o.pos = vertexInput.positionCS;
		o.uv.xy = v.texcoord.xy;

		o.uv01 =  v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1);
		o.uv23 =  v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1) * 2.0;
		o.uv45 =  v.texcoord.xyxy + offsets.xyxy * float4(1,1, -1,-1) * 3.0;
		return o;
	}
	
	half4 frag (v2f i) : COLOR {
		half4 color = float4 (0,0,0,0);

		color += 0.40 * tex2D (_MainTex, i.uv);
		color += 0.15 * tex2D (_MainTex, i.uv01.xy);
		color += 0.15 * tex2D (_MainTex, i.uv01.zw);
		color += 0.10 * tex2D (_MainTex, i.uv23.xy);
		color += 0.10 * tex2D (_MainTex, i.uv23.zw);
		color += 0.05 * tex2D (_MainTex, i.uv45.xy);
		color += 0.05 * tex2D (_MainTex, i.uv45.zw);
		
		return color;
	}

	ENDHLSL
	
Subshader {
 Pass {
	  ZTest Always Cull Off ZWrite Off

      HLSLPROGRAM
      #pragma vertex vert
      #pragma fragment frag
      ENDHLSL
  }
}

}


三、创建一个ScriptableRendererFeature

using UnityEngine;
using UnityEngine.Rendering.Universal;
 
public class GlassBlurRenderPassFeature : ScriptableRendererFeature
{
//设置一个RendererFeature的配置,写上要用的参数
    [System.Serializable]
    public class Settings
    {
        public RenderPassEvent renderEvent = RenderPassEvent.BeforeRenderingPostProcessing;
        public LayerMask layerMask = -1;
        public Material blurMat;
        public string textureName = "";
        public string cmdName = "";
        public string passName = "";
    }
 
    GlassBlurRenderPass m_ScriptablePass;
    private RenderTargetHandle dest;
    public Settings settings; //这个在可视化中设置
    public override void Create()
    {
        m_ScriptablePass = new GlassBlurRenderPass(settings);
        m_ScriptablePass.renderPassEvent = settings.renderEvent;
        
    }
 
    public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
    {
        var src = renderer.cameraColorTarget;
        dest = RenderTargetHandle.CameraTarget;
//把camera渲染到的画面src 传入GlassBlurRenderPass里。
        m_ScriptablePass.Setup(src,this.dest);
//注入队列
        renderer.EnqueuePass(m_ScriptablePass);
    }
}


四、将ScriptableRendererFeature添加到Render Feature,填写自己定义的参数内容

image.png

image.png

image.png


五、业务控制和注意

通过逻辑控制GlassCtrl然后获取贴图就可以了。注意的是URP这个处理只对主相机渲染的内容进行处理(Base Camera),对添加到主相机下面的Overlay相机不会影响,所以必要时刻需要调整需要玻璃化的相机为主相机。一般都是背景做毛玻璃效果,内容还是在上面的,所以这应该不会有问题。



首页 我的博客
粤ICP备17103704号