在做UI背景模糊的时候,权衡了几种效果,尝试一下CommandBuffer这种神奇的东西。
CommandBuffer是Unity2018以后推出的,似乎听说2019已经没有了。项目使用的还是2018,所以看看。去网上搜索资料的时候,还是之前那样,要么是官方资料,要么就是一堆复制粘贴的。我喜欢转成小白语言,争取看一次就彻底明明白白的。
CommandBuffer是个啥玩意,其实就相机暴露给外面的一个接口,通过在这个接口中设置我们需要的渲染指令,去修改相机的渲染结果。但凡有一点Unity基础的都知道,Unity的相机如果没有做任何处理,那么在运行窗口中显示的东西就是他本来的样子,一个“正常”相机的渲染顺序就是官方给出的那种到处被贴出来的示意图:
![官方示意图](https://img-blog.csdnimg.cn/20200217102225431.jpg?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NDYwNzMx,size_16,color_FFFFFF,t_70)
Unity中相机的渲染顺序就是这样,CommandBuffer就是在相机执行这样的顺序的时候,插入你编写的处理,然后相机完成渲染时就渲染出你想要的结果(前提是你写对了,手动滑稽)。所以很多文章说CommandBuffer就是相机的一条渲染指令,但是没怎么讲清楚,为啥是。通过代码的设置你可以在渲染任何对象的时候插入这条指令,这样你就可以处理透明不透明物体等等之类的。需要注意的是,如果没有设置天空盒子,AtferSkyBox这样的顺序设置是不会生效的,也有会出其他问题。下面是一个小型实例。
添加一个3D物体,将场景相机的渲染结果在UI层显示出来,Shader完成的事就是在Image上显示渲染的结果:使用的物体如截图:![测试使用的物体](https://img-blog.csdnimg.cn/20200217102432877.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NDYwNzMx,size_16,color_FFFFFF,t_70)
使用的Shader也贴一下:
Shader "UI/ShowTex"
{
Properties
{
_MainTex("呵呵", 2D) = "defaulttexture" {}
}
SubShader
{
Cull Off ZWrite Off ZTest Always
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
};
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv = v.uv;
return o;
}
sampler2D _SrcCapTex;
fixed4 frag (v2f i) : SV_Target
{
fixed4 FinalCol = tex2D(_SrcCapTex, i.uv);
return FinalCol;
}
ENDCG
}
}
}
新建一个脚本,挂在Image上运行就能看到结果:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
// 注意引用这个
using UnityEngine.Rendering;
public class GetTex : MonoBehaviour
{
private Material material;
private CommandBuffer buffer;
public Camera sceneCam;
// Start is called before the first frame update
void Start()
{
if (sceneCam == null)
{
Debug.LogError("木有相机");
return ;
}
Shader shader = Shader.Find("UI/ShowTex");
if (material == null)
{
material = new Material(shader);
gameObject.GetComponent<Image>().material = material;
buffer = new CommandBuffer();
// 申请一片缓存
int scrCapID = Shader.PropertyToID("_ScrCap");
buffer.GetTemporaryRT(scrCapID, Screen.width, Screen.height, 0, FilterMode.Bilinear);
// 将当前相机的渲染RT给申请的缓存, 有的说Bilt的效率不高,使用SetGlobalTexture会好点,没测
buffer.Blit(BuiltinRenderTextureType.CurrentActive, scrCapID);
// 将得到的RT交给材质球,申请的RT会在Buffer清除的时候清除掉所以不要在这里清除RT,不会没渲染完就没了
buffer.SetGlobalTexture("_SrcCapTex", scrCapID);
// 将编写好的渲染指令插入相机的队列中, 放在不透明物体之后
sceneCam.AddCommandBuffer(CameraEvent.AfterImageEffectsOpaque, buffer);
}
}
// Update is called once per frame
void OnDestroy()
{
if(material)
{
Object.Destroy(material);
}
if(buffer != null)
{
sceneCam.RemoveCommandBuffer(CameraEvent.AfterImageEffectsOpaque, buffer);
// 清除所有指令
buffer.Clear();
// 释放插入buffer
buffer.Release();
buffer = null;
}
}
}
运行结果如下:
![运行结果,在UI上显示场景相机的运行结果](https://img-blog.csdnimg.cn/20200217102612677.PNG?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzM2NDYwNzMx,size_16,color_FFFFFF,t_70)
如果需要做UI背景的模糊,则使用模糊算法处理即可。需要注意的事,不能在将UI相机的渲染结果又交给UI,自己渲染自己的渲染结果,那么就是无穷个自己。
来源:CSDN
作者:qq_36460731
链接:https://blog.csdn.net/qq_36460731/article/details/104348822