一、创建一个用来控制效果开启和关闭的开关,获取处理过的贴图的管理类
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,填写自己定义的参数内容



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