前言

在UI上显示特效是一直是一个比较棘手的问题,一开始的方案是调整UI特效的渲染顺序,设置其sortingLayersortingOrder+offset,在每个单独的UI以后渲染。

这种方法能满足大部分的需求,但也有缺点。

如果需要在特效上再盖一层UI的话,由于特效并不属于Canvas的一部分,所以修改Hierarchy并不能改变其渲染顺序,特效会在渲染完Canvas的UI元素以后再进行渲染,所以需要把这个UI的层级通过添加Canvas继续往上抬。

再者无法被RectMask2DMask裁剪,除非改造Shader,并手动传入裁剪区域。

最好的方法就是让特效像UI一样,直接按Hierarchy 顺序渲染,并支持遮罩,就是这文章的主角UIParticle。

原理

This package utilizes the new APIsMeshBake/MashTrailBake(introduced with Unity 2018.2) to render particles through CanvasRenderer.

You can render, mask, and sort your ParticleSystems for UI without the necessity of an additional Camera, RenderTexture, or Canvas.

这是项目首页的原理,具体就是通过一个API让例子特效通过CanvasRender进行渲染,这样就和普通的UI没什么不同了。

使用

按官方的教程,直接引入包,添加组件到特效上,直接拖到UI中即可。

改造已有shader以支持遮罩

项目推荐我们使用UIShader,如UIDefault或者UIAdditive。

Mask通过模板测试实现遮罩,RectMask2D通过传入裁剪区域实现。

所以自定义的Shader只需要参考上面的UIShader使其拥有遮罩特效即可,注意RenderQueue设置为Transparent,下面贴一下关键Shader代码。

Shader "Your/Custom/Shader"
{
    Properties
    {
        // ...
        // #### required for Mask ####
        _StencilComp ("Stencil Comparison", Float) = 8
        _Stencil ("Stencil ID", Float) = 0
        _StencilOp ("Stencil Operation", Float) = 0
        _StencilWriteMask ("Stencil Write Mask", Float) = 255
        _StencilReadMask ("Stencil Read Mask", Float) = 255
        _ColorMask ("Color Mask", Float) = 15
        [Toggle(UNITY_UI_ALPHACLIP)] _UseUIAlphaClip ("Use Alpha Clip", Float) = 0
    }

    SubShader
    {
        Tags
        {
            // ...
        }

        // #### required for Mask ####
        Stencil
        {
            Ref [_Stencil]
            Comp [_StencilComp]
            Pass [_StencilOp]
            ReadMask [_StencilReadMask]
            WriteMask [_StencilWriteMask]
        }
        ColorMask [_ColorMask]
        // ...

        Pass
        {
            // ...
            // #### required for RectMask2D ####
            #include "UnityUI.cginc"
            #pragma multi_compile __ UNITY_UI_CLIP_RECT
            float4 _ClipRect;

            // #### required for Mask ####
            #pragma multi_compile __ UNITY_UI_ALPHACLIP

            struct appdata_t
            {
                // ...
            };

            struct v2f
            {
                // ...
                // #### required for RectMask2D ####
                float4 worldPosition    : TEXCOORD1;
            };
            
            v2f vert(appdata_t v)
            {
                v2f OUT;
                // ...
                // #### required for RectMask2D ####
                OUT.worldPosition = v.vertex;
                return OUT;
            }

            fixed4 frag(v2f IN) : SV_Target
            {
                // ...
                // #### required for RectMask2D ####
                #ifdef UNITY_UI_CLIP_RECT
                    color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
                #endif

                // #### required for Mask ####
                #ifdef UNITY_UI_ALPHACLIP
                    clip (color.a - 0.001);
                #endif

                return color;
            }
            ENDCG
        }
    }
}

总结

至此已经可以像UI一样使用UI特效了,具体的性能分析,参考一下首页。

参考

https://github.com/mob-sakai/ParticleEffectForUGUI

Unity Mask 和RectMask2D原理和区别-CSDN博客

Unity的三级排序层级渲染Layer,sorting layer,order in layer_unity layer 和order-CSDN博客

UGUI:调整Unity中UI和特效的层级关系(特效穿透问题)_unity中特效显示在image背景上 其他ui元素覆盖在特效上 层级怎么处理-CSDN博客