Unity Shader PostProcessing - 12 - 外发光


其实以前老早就想制作这个效果了,但是没有太多的空闲时间

那这次反正项目组需要这个效果,就顺手将 Demo 记录到 Blog


2021/03/03 刚刚好今天早上晨会分享了这个 外发光 的思路

我讲的比较简单的理解化的方式

该效果还是比较简单的,都是非常基础的东西,大神、大佬可以跳过。


思路

使用后效处理:

  • 先将需要外发光的对象都 draw 到一张 RT(RenderTexture,这里因为颜色统一的,所以 RT 只要 Format为 R8 即可),假设 RT 名为:Mask_RT
  • 再将 Mask_RT Blit 一下,处理高斯模糊,将 Mask_RT 高斯模糊后的内容存入到另一张 RT: Blur_RT
  • 再将 Value_RT = Blur_RT - Mask_RT,就是最终外发光的像素部分了
  • 再用一个 FinalCol = _Color * Value_RT 就是最终颜色了

下面列出完整的 CSharp + ShaderLab 的代码


Shader Code - GlowZAlwaysPP.shader

// jave.lin 2021/02/25
// references : https://blog.csdn.net/linjf520/article/details/104940213
Shader "Game/PP/GlowZAlwaysPP"
{
    
    
    CGINCLUDE
#include "UnityCG.cginc"

        // pure col
        float4 vert_pure_col(float4 vertex : POSITION) : SV_POSITION
    {
    
    
        return UnityObjectToClipPos(vertex);
    }
        fixed4 frag_pure_col() : SV_Target
    {
    
    
        return 1;
    }

        // expand
    sampler2D _ExpandOrginTex;
    float4 _ExpandOrginTex_TexelSize;
    float _GlowSize;
    struct a2v_expand
    {
    
    
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };
    struct v2f_expand
    {
    
    
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
        float4 uv01 : TEXCOORD1;
        float4 uv23 : TEXCOORD2;
    };
    v2f_expand vert_expand(a2v_expand v) {
    
    
        v2f_expand o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        float2 ts = _ExpandOrginTex_TexelSize.xy;
        float2 offset1 = float2(1, 0);
        float2 offset2 = float2(0, 1);
        o.uv01.xy = v.uv + offset1 * ts * _GlowSize; // 左
        o.uv01.zw = v.uv + offset1 * -ts * _GlowSize; // 右
        o.uv23.xy = v.uv + offset2 * ts * _GlowSize; // 上
        o.uv23.zw = v.uv + offset2 * -ts * _GlowSize; // 下
        return o;
    }
    fixed4 frag_expand(v2f_expand i) : SV_Target
    {
    
    
        fixed sum = tex2D(_ExpandOrginTex, i.uv).r;
        if (sum == 0)
            sum = tex2D(_ExpandOrginTex, i.uv01.xy).r; // 左
        if (sum == 0)
            sum += tex2D(_ExpandOrginTex, i.uv01.zw).r; // 右
        if (sum == 0)
            sum += tex2D(_ExpandOrginTex, i.uv23.xy).r; // 上
        if (sum == 0)
            sum += tex2D(_ExpandOrginTex, i.uv23.zw).r; // 下

        //if (sum == 0)
        //    sum = tex2D(_ExpandOrginTex, float2(i.uv01.xy.x, i.uv23.xy.y)).r; // 左 | 上
        //if (sum == 0)
        //    sum += tex2D(_ExpandOrginTex, float2(i.uv01.zw.x, i.uv23.xy.y)).r; // 右 | 上
        //if (sum == 0)
        //    sum = tex2D(_ExpandOrginTex, float2(i.uv01.xy.x, i.uv23.zw.y)).r; // 左 | 下
        //if (sum == 0)
        //    sum += tex2D(_ExpandOrginTex, float2(i.uv01.zw.x, i.uv23.zw.y)).r; // 右 | 下

        return sum != 0 ? 1 : 0;
    }

        /// blur /
        struct a2v_blur
    {
    
    
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };
    struct v2f_blur
    {
    
    
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
        float4 uv01 : TEXCOORD1;
        float4 uv23 : TEXCOORD2;
    };
    sampler2D _BlurOrginTex;
    float4 _BlurOrginTex_TexelSize;
    float _BlurSize;
    v2f_blur vert_blur_h(a2v_blur v) {
    
    
        v2f_blur o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        float2 ts = _BlurOrginTex_TexelSize.xy;
        float2 offset1 = float2(1, 0);
        float2 offset2 = float2(2, 0);
        o.uv01.xy = v.uv + offset1 * ts * _BlurSize; // 左1
        o.uv01.zw = v.uv + offset1 * -ts * _BlurSize; // 右1
        o.uv23.xy = v.uv + offset2 * ts * _BlurSize; // 左2
        o.uv23.zw = v.uv + offset2 * -ts * _BlurSize; // 右2
        return o;
    }
    v2f_blur vert_blur_v(a2v_blur v) {
    
    
        v2f_blur o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        float2 ts = _BlurOrginTex_TexelSize.xy;
        float2 offset1 = float2(0, 1);
        float2 offset2 = float2(0, 2);
        o.uv01.xy = v.uv + offset1 * ts * _BlurSize; // 上1
        o.uv01.zw = v.uv + offset1 * -ts * _BlurSize; // 下1
        o.uv23.xy = v.uv + offset2 * ts * _BlurSize; // 上2
        o.uv23.zw = v.uv + offset2 * -ts * _BlurSize; // 下2
        return o;
    }
    fixed4 frag_blur(v2f_blur i) : SV_Target{
    
    
        fixed4 sum = tex2D(_BlurOrginTex, i.uv) * 0.4026;
        sum += tex2D(_BlurOrginTex, i.uv01.xy) * 0.2442; // 左1 | 上1
        sum += tex2D(_BlurOrginTex, i.uv01.zw) * 0.2442; // 右1 | 下1
        sum += tex2D(_BlurOrginTex, i.uv23.xy) * 0.0545; // 左2 | 上2
        sum += tex2D(_BlurOrginTex, i.uv23.zw) * 0.0545; // 右2 | 下2
        return sum;
    }

        /// final /
    sampler2D _MaskTex;
    sampler2D _BlurTex;
    sampler2D _SrcTex;
    fixed4 _GlowColor;
    struct a2v_final
    {
    
    
        float4 vertex : POSITION;
        float2 uv : TEXCOORD0;
    };
    struct v2f_final
    {
    
    
        float4 vertex : SV_POSITION;
        float2 uv : TEXCOORD0;
    };
    v2f_final vert_final(a2v_final v) {
    
    
        v2f_final o;
        o.vertex = UnityObjectToClipPos(v.vertex);
        o.uv = v.uv;
        return o;
    }
    fixed4 frag_final(v2f_final i) : SV_Target{
    
    
        fixed blur_col = tex2D(_BlurTex, i.uv).r;
        fixed mask_col = tex2D(_MaskTex, i.uv).r;
        fixed value = saturate(blur_col - mask_col);
        return saturate(tex2D(_SrcTex, i.uv) + value * _GlowColor);
    }
        ENDCG
        SubShader
    {
    
    
        // No culling or depth
        Cull Off ZWrite Off ZTest Always
            Pass // pure col 0
        {
    
    

            ColorMask R
            CGPROGRAM
            #pragma vertex vert_pure_col
            #pragma fragment frag_pure_col
            ENDCG
        }
            Pass // expand 1
        {
    
    
            ColorMask R
            CGPROGRAM
            #pragma vertex vert_expand
            #pragma fragment frag_expand
            ENDCG
        }
            Pass // blur h 2
        {
    
    
            ColorMask R
            CGPROGRAM
            #pragma vertex vert_blur_h
            #pragma fragment frag_blur
            ENDCG
        }
            Pass // blur v 3
        {
    
    
            ColorMask R
            CGPROGRAM
            #pragma vertex vert_blur_v
            #pragma fragment frag_blur
            ENDCG
        }
            Pass // final 4
        {
    
    
            CGPROGRAM
            #pragma vertex vert_final
            #pragma fragment frag_final
            ENDCG
        }
    }
}


CSharp Code - GlowPP.cs

// jave.lin 2021/02/25
// 绘制外发光后效
// 临时效果,时间关系,未优化
using UnityEngine;
using UnityEngine.Rendering;

public class GlowPP : PostEffectBasic
{
    
    
    private static int _GlowSize_hash = Shader.PropertyToID("_GlowSize");
    private static int _BlurSize_hash = Shader.PropertyToID("_BlurSize");
    private static int _GlowColor_hash = Shader.PropertyToID("_GlowColor");
    private static int _ExpandOrginTex_hash = Shader.PropertyToID("_ExpandOrginTex");
    private static int _BlurTex_hash = Shader.PropertyToID("_BlurTex");
    private static int _BlurOrginTex_hash = Shader.PropertyToID("_BlurOrginTex");
    private static int _MaskTex_hash = Shader.PropertyToID("_MaskTex");
    private static int _SrcTex_hash = Shader.PropertyToID("_SrcTex");

    private static int _ZLessTex_hash = Shader.PropertyToID("_ZLessTex");
    private static int _ZGreaterTex_hash = Shader.PropertyToID("_ZGreaterTex");
    private static int _ExpandTex_hash = Shader.PropertyToID("_ExpandTex");

    [Header("ZGreater绘制材质")]
    public Material z_greater_draw_mat;
    [Header("ZAlways绘制材质")]
    public Material z_always_draw_mat;

    [Header("DownSample 降采等级")]
    public int down_sample_level = 4;

    [Range(1, 4)]
    [Header("高斯模糊的次数")]
    public int iterations = 4;

    [Header("模糊边界大小:每次模糊采样纹素距离的缩放因数")]
    [Range(0.2f, 3.0f)]
    public float blur_size = 0.2f;

    [Header("外发光边缘大小")]
    [Range(0.0f, 2.0f)]
    public float glow_size = 2;

    [Header("外发光颜色")]
    public Color glow_color = Color.red;

    [Header("是否只显示 z greater 部分(暂时无效的参数)")]
    public bool only_show_greater_glow = false;

    private CommandBuffer cmdBuffer;
    private Camera cam;

    protected override void Start()
    {
    
    
        base.Start();
        cmdBuffer = new CommandBuffer();
        cmdBuffer.name = "GlowPPCmdBuffer";
        cam = GetComponent<Camera>();
    }

    private void OnDestroy()
    {
    
    
        if (cmdBuffer != null)
        {
    
    
            cmdBuffer.Clear();
            cmdBuffer.Dispose();
            cmdBuffer = null;
        }
        cam = null;
    }

    protected override void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
    
    
        if (!IsSupported || GlowManager.instance.Count == 0)
        {
    
    
            Graphics.Blit(src, dest);
            return;
        }

        if (z_always_draw_mat == null)
        {
    
    
            Debug.LogError("GlowPP.z_always_draw_mat == null");
            Graphics.Blit(src, dest);
            return;
        }

        // clamp down_sample_level
        if (down_sample_level <= 0) down_sample_level = 1;

        var sw = Screen.width;
        var sh = Screen.height;
        var rw = sw / down_sample_level;
        var rh = sh / down_sample_level;
        //if (only_show_greater_glow)
        //{
    
    
        //    // 还有 BUG,后续完善
        //    ShowGreaterGlow(src, dest, rw, rh, z_greater_draw_mat);
        //}
        //else
        //{
    
    
        ShowAlwaysGlow(src, dest, sw, sh, rw, rh, z_always_draw_mat);
        //}
    }

    private void ShowAlwaysGlow(RenderTexture src, RenderTexture dest, int sw, int sh, int rw, int rh, Material usingMat)
    {
    
    
        // create RT
        var glow_mask_rt = RenderTexture.GetTemporary(sw, sh, 0, RenderTextureFormat.R8);
        glow_mask_rt.filterMode = FilterMode.Bilinear;
        glow_mask_rt.name = "GlowPP.glow_mask_rt";

        // back up actived rt
        var src_rt = cam.targetTexture;

        cmdBuffer.Clear();
        cmdBuffer.SetRenderTarget(glow_mask_rt);
        cmdBuffer.ClearRenderTarget(false, true, Color.black);

        GlowManager.instance.Update2CmdBuffer2Draw(cmdBuffer, usingMat, 0);
        // execute cmd buffer, Draw To RT
        Graphics.ExecuteCommandBuffer(cmdBuffer);

        // expand
        var expand_rt = RenderTexture.GetTemporary(rw, rh, 0, RenderTextureFormat.R8);
        expand_rt.filterMode = FilterMode.Bilinear;
        expand_rt.name = "GlowPP.expand_rt";

        usingMat.SetFloat(_GlowSize_hash, glow_size);
        usingMat.SetTexture(_ExpandOrginTex_hash, glow_mask_rt);
        Graphics.Blit(null, expand_rt, usingMat, 1);

        // blur
        var blur_rt = RenderTexture.GetTemporary(rw, rh, 0, RenderTextureFormat.R8);
        blur_rt.filterMode = FilterMode.Bilinear;
        blur_rt.name = "GlowPP.blur_rt";

        var rt0 = RenderTexture.GetTemporary(rw, rh, 0, RenderTextureFormat.R8);
        rt0.filterMode = FilterMode.Bilinear;
        rt0.name = "GlowPP.rt0";

        // 先将远 blur_rt 复制到rt0
        // references : https://blog.csdn.net/linjf520/article/details/104940213
        Graphics.Blit(expand_rt, rt0);

        for (int i = 0; i < iterations; i++)
        {
    
    
            usingMat.SetFloat(_BlurSize_hash, 1 + i * blur_size);

            var rt1 = RenderTexture.GetTemporary(rw, rh, 0, RenderTextureFormat.R8);
            rt1.filterMode = FilterMode.Bilinear;
            rt1.name = "GlowPP.rt1.1";

            usingMat.SetTexture(_BlurOrginTex_hash, rt0);
            // horizontal blur
            Graphics.Blit(null, rt1, usingMat, 2);

            RenderTexture.ReleaseTemporary(rt0);
            rt0 = rt1;
            rt1 = RenderTexture.GetTemporary(rw, rh, 0, RenderTextureFormat.R8);
            rt1.filterMode = FilterMode.Bilinear;
            rt1.name = "GlowPP.rt1.2";

            // vertical blur
            usingMat.SetTexture(_BlurOrginTex_hash, rt0);
            Graphics.Blit(null, rt1, usingMat, 3);
            RenderTexture.ReleaseTemporary(rt0);
            rt0 = rt1;
        }

        Graphics.Blit(rt0, blur_rt);
        RenderTexture.ReleaseTemporary(rt0);

        // final
        usingMat.SetTexture(_MaskTex_hash, glow_mask_rt);
        usingMat.SetTexture(_BlurTex_hash, blur_rt);
        usingMat.SetTexture(_SrcTex_hash, src);
        usingMat.SetColor(_GlowColor_hash, glow_color);
        Graphics.Blit(null, dest, usingMat, 4);

        // reset src rt
        cam.targetTexture = src_rt;

        RenderTexture.ReleaseTemporary(glow_mask_rt);
        RenderTexture.ReleaseTemporary(expand_rt);
        RenderTexture.ReleaseTemporary(blur_rt);
    }

    private void ShowGreaterGlow(RenderTexture src, RenderTexture dest, int rw, int rh, Material usingMat)
    {
    
    
        // create RT
        var glow_mask_rt = RenderTexture.GetTemporary(rw, rh, 0, RenderTextureFormat.R8);
        glow_mask_rt.filterMode = FilterMode.Bilinear;
        glow_mask_rt.name = "GlowPP.glow_mask_rt";

        // back up actived rt
        var src_rt = cam.targetTexture;

        cmdBuffer.Clear();
        cmdBuffer.SetRenderTarget(glow_mask_rt);
        cmdBuffer.ClearRenderTarget(false, true, Color.black);
        GlowManager.instance.Update2CmdBuffer2Draw(cmdBuffer, usingMat, 0);
        // execute cmd buffer, Draw To RT
        Graphics.ExecuteCommandBuffer(cmdBuffer);

        // expand
        var expand_rt = RenderTexture.GetTemporary(rw, rh, 0, RenderTextureFormat.R8);
        expand_rt.filterMode = FilterMode.Bilinear;
        expand_rt.name = "GlowPP.expand_rt";

        usingMat.SetFloat(_GlowSize_hash, glow_size);
        usingMat.SetTexture(_ExpandOrginTex_hash, glow_mask_rt);
        Graphics.Blit(null, expand_rt, usingMat, 1);

        // blur
        var blur_rt = RenderTexture.GetTemporary(rw, rh, 0, RenderTextureFormat.R8);
        blur_rt.filterMode = FilterMode.Bilinear;
        blur_rt.name = "GlowPP.blur_rt";

        var rt0 = RenderTexture.GetTemporary(rw, rh, 0);
        rt0.filterMode = FilterMode.Bilinear;
        rt0.name = "GlowPP.rt0";

        // 先将远 blur_rt 复制到rt0
        // references : https://blog.csdn.net/linjf520/article/details/104940213
        Graphics.Blit(expand_rt, rt0);

        for (int i = 0; i < iterations; i++)
        {
    
    
            usingMat.SetFloat(_BlurSize_hash, 1 + i * blur_size);

            var rt1 = RenderTexture.GetTemporary(rw, rh, 0);
            rt1.filterMode = FilterMode.Bilinear;

            usingMat.SetTexture(_BlurOrginTex_hash, rt0);
            // horizontal blur
            Graphics.Blit(null, rt1, usingMat, 2);

            RenderTexture.ReleaseTemporary(rt0);
            rt0 = rt1;
            rt1 = RenderTexture.GetTemporary(rw, rh, 0);
            rt1.filterMode = FilterMode.Bilinear;

            // vertical blur
            usingMat.SetTexture(_BlurOrginTex_hash, rt0);
            Graphics.Blit(null, rt1, usingMat, 3);
            RenderTexture.ReleaseTemporary(rt0);
            rt0 = rt1;
        }

        Graphics.Blit(rt0, blur_rt);
        RenderTexture.ReleaseTemporary(rt0);

        // final
        usingMat.SetTexture(_MaskTex_hash, glow_mask_rt);
        usingMat.SetTexture(_BlurTex_hash, blur_rt);
        usingMat.SetTexture(_SrcTex_hash, src);
        usingMat.SetColor(_GlowColor_hash, glow_color);
        Graphics.Blit(null, dest, usingMat, 4);

        // reset src rt
        cam.targetTexture = src_rt;

        RenderTexture.ReleaseTemporary(glow_mask_rt);
        RenderTexture.ReleaseTemporary(expand_rt);
        RenderTexture.ReleaseTemporary(blur_rt);
    }
}


CSharp Code - GlowManager.cs

再写一个简单的Glow 管理器

// jave.lin 2021/02/25
// 外发光的管理
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Rendering;

public class GlowManager : MonoSingleton<GlowManager>
{
    
    
    private Stack<List<Renderer>> listPool = new Stack<List<Renderer>>();
    private Stack<GlowElement> glowElementPool = new Stack<GlowElement>();

    private List<GlowElement> glowElementList = new List<GlowElement>();
    private Dictionary<int, GlowElement> glowElementDict_key_instid = new Dictionary<int, GlowElement>();
    private Dictionary<GameObject, GlowElement> glowElementDict_key_go = new Dictionary<GameObject, GlowElement>();


    public int Count => glowElementList.Count;

    private void OnDestroy()
    {
    
    
        if (listPool != null)
        {
    
    
            foreach (var item in listPool)
            {
    
    
                item.Clear();
            }
            listPool.Clear();
            listPool = null;
        }
        if (glowElementPool != null)
        {
    
    
            glowElementPool.Clear();
            glowElementPool = null;
        }
        if (listPool != null)
        {
    
    
            listPool.Clear();
            listPool = null;
        }
    }
    public bool Contains(GameObject go)
    {
    
    
        foreach (var glowElement in glowElementList)
        {
    
    
            if (glowElement.go == go)
            {
    
    
                return true;
            }
        }
        return false;
    }
    public void Add(int instID, List<Renderer> renderers)
    {
    
    
        GlowElement e = glowElementPool.Count > 0 ? glowElementPool.Pop() : null;

        if (e == null)
        {
    
    
            e = new GlowElement
            {
    
    
                optType = eGlowOptType.SpecialRenderers,
                instID = instID,
                go = null,
                renderers = renderers,
                ignoreActive = false
            };
        }
        else
        {
    
    
            e.optType = eGlowOptType.SpecialRenderers;
            e.instID = instID;
            e.go = null;
            e.renderers = renderers;
            e.ignoreActive = false;
        }

        glowElementDict_key_instid[instID] = e;
        glowElementList.Add(e);
        //Log.logError($"GlowManager.Add instID:{instID}");
    }
    public void Add(GameObject go, bool ignoreActive = false, int ignoreLayer = 0)
    {
    
    
        if (ignoreLayer == -1)
        {
    
    
            // culling everything
            return;
        }
        if (go == null)
        {
    
    
            return;
        }

        if (Contains(go))
        {
    
    
            return;
        }

        var list = listPool.Count > 0 ? listPool.Pop() : new List<Renderer>();
        go.GetComponentsInChildren<Renderer>(false, list);

        GlowElement e = glowElementPool.Count > 0 ? glowElementPool.Pop() : null;

        if (ignoreLayer != 0)
        {
    
    
            var count = list.Count;
            for (int i = 0; i < count; i++)
            {
    
    
                if (list[i].gameObject.layer == ignoreLayer)
                {
    
    
                    list.RemoveAt(i);
                    --i;
                    --count;
                    continue;
                }
            }
        }

        if (e == null)
        {
    
    
            e = new GlowElement {
    
     optType = eGlowOptType.SpecialGO, instID = -1, go = go, renderers = list, ignoreActive = ignoreActive };
        }
        else
        {
    
    
            e.optType = eGlowOptType.SpecialGO;
            e.instID = -1;
            e.go = go;
            e.renderers = list;
            e.ignoreActive = ignoreActive;
        }
        glowElementDict_key_go[go] = e;
        glowElementList.Add(e);
    }
    public void Remove(GameObject go)
    {
    
    
        if (go == null)
        {
    
    
            return;
        }

        for (int i = 0; i < glowElementList.Count; i++)
        {
    
    
            var e = glowElementList[i];
            if (e.go == null)
            {
    
    
                _Reclyle(e);
                glowElementList.RemoveAt(i);
                continue;
            }
            if (e.go == go)
            {
    
    
                _Reclyle(e);
                glowElementList.RemoveAt(i);
                return;
            }
        }
        glowElementDict_key_go.Remove(go);
    }
    public void Remove(int instID)
    {
    
    
        if (glowElementDict_key_instid.Remove(instID))
        {
    
    
            for (int i = 0; i < glowElementList.Count; i++)
            {
    
    
                var e = glowElementList[i];
                if (e.instID == instID)
                {
    
    
                    _Reclyle(e);
                    glowElementList.RemoveAt(i);
                    break;
                }
            }
        }

        //Log.logError($"GlowManager.Remove instID:{instID}");
    }
    public void Clear()
    {
    
    
        if (glowElementList.Count > 0)
        {
    
    
            foreach (var e in glowElementList)
            {
    
    
                _Reclyle(e);
            }
            glowElementList.Clear();
        }
        glowElementList.Clear();
        glowElementDict_key_go.Clear();
    }
    public void Update2CmdBuffer2Draw(CommandBuffer cmdBuffer, Material material, int pass = -1)
    {
    
    
        for (int i = glowElementList.Count - 1; i > -1; i--)
        {
    
    
            var e = glowElementList[i];
            switch (e.optType)
            {
    
    
                case eGlowOptType.SpecialGO:
                    if (e.go == null)
                    {
    
    
                        _Reclyle(e);
                        glowElementList.RemoveAt(i);
                        continue;
                    }
                    if (!e.ignoreActive)
                    {
    
    
                        if (!e.go.activeInHierarchy)
                        {
    
    
                            continue;
                        }
                    }

                    for (int j = 0; j < e.renderers.Count; j++)
                    {
    
    
                        var r = e.renderers[j];
                        var draw = r != null;
                        if (draw && !e.ignoreActive)
                        {
    
    
                            draw = r.enabled && r.gameObject.activeInHierarchy;
                        }
                        if (draw)
                        {
    
    
                            cmdBuffer.DrawRenderer(r, material, 0, pass);
                        }
                    }
                    break;
                case eGlowOptType.SpecialRenderers:
                    for (int j = 0; j < e.renderers.Count; j++)
                    {
    
    
                        var r = e.renderers[j];
                        if (r == null || r.gameObject == null)
                        {
    
    
                            _Reclyle(e);
                            glowElementList.RemoveAt(i);
                            break;
                        }
                        var draw = true;
                        if (!e.ignoreActive)
                        {
    
    
                            draw = r.enabled && r.gameObject.activeInHierarchy;
                        }
                        if (draw)
                        {
    
    
                            cmdBuffer.DrawRenderer(r, material, 0, pass);
                        }
                    }
                    break;
                default:
                    Debug.LogError($"Unimplements GlowOptType : {e.optType}");
                    break;
            }
        }
    }
    private void _Reclyle(GlowElement e)
    {
    
    
        if (e.optType == eGlowOptType.SpecialGO)
        {
    
    
            glowElementDict_key_go.Remove(e.go);
        }
        else
        {
    
    
            glowElementDict_key_instid.Remove(e.instID);
        }
        e.renderers.Clear();
        listPool.Push(e.renderers);
        glowElementPool.Push(e);
    }
}

public enum eGlowOptType
{
    
    
    SpecialGO,
    SpecialRenderers,
}

public class GlowElement
{
    
    
    public eGlowOptType optType;
    public int instID;      // key, when optType == Special Instance ID
    public GameObject go;   // key, when optType == Special GO
    public List<Renderer> renderers;
    public bool ignoreActive;
}


使用方式

// jave.lin 2021/02/25
// 测试外发光的管理的使用效果
using UnityEngine;

public class TestingPushToGlowMgr : MonoBehaviour
{
    
    
    public GameObject[] goes;
    // Start is called before the first frame update
    private bool added = false;
    private void AddGoes(GameObject[] goes)
    {
    
    
        foreach (var go in goes)
        {
    
    
            GlowManager.instance.Add(go, false);
        }
        added = true;
    }

    private void RemoveGoes(GameObject[] goes)
    {
    
    
        foreach (var go in goes)
        {
    
    
            GlowManager.instance.Remove(go);
        }
        added = false;
    }
    private void Start()
    {
    
    
        AddGoes(goes);
    }
    // Update is called once per frame
    void Update()
    {
    
    
        if (Input.GetKeyDown(KeyCode.Space))
        {
    
    
            if (!added)
            {
    
    
                AddGoes(goes);
            }
            else
            {
    
    
                RemoveGoes(goes);
            }
        }
    }
}


查看效果

在这里插入图片描述


Project

back up : TestingGlowPostProcessEffect


References

猜你喜欢

转载自blog.csdn.net/linjf520/article/details/114084729#comments_22134612