Unity菜鸟开发纪要——CommandBuffer

Deadly 提交于 2020-02-17 11:19:44
在做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,自己渲染自己的渲染结果,那么就是无穷个自己。
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!