问题
开发过程中有很多用到粒子特效的时候出现和UI层级冲突,比如粒子需要再同一个界面两个Image中间
解决
一般有三种方案
1.通过rendertexture渲染,可以完美处理层级问题,不过性能不好,多个摄像机
2.直接放到ui界面增加canvas,调整特效sort in layer,不过如果ui特效穿插多,层级不好管理,且多canvas造成合批问题
3.就是这篇文章主要讲的 粒子BakeMesh 优点:可像UGUI一样通过上下调整层级排序,接受Mask处理
下载资源
用法:
文件里面有demo,简单来说就是在特效的父物体上加UIParticle脚本就行
如果是为了解决问题看到这里就可以了,下面是解析怎么实现的
粒子BakeMesh
原理:直接让粒子的网格和贴图在ui基础组件里面渲染
使用接口
ParticleSystemRenderer.BakeMesh和ParticleSystemRenderer.BakeTrailsMesh这里是生成网格信息
CanvasRenderer.SetMesh
CanvasRenderer.SetTexture
把mesh和texture扔给canvasRenderer渲染
代码解析
UIParticle
UIParticle 是粒子的父物体
[RequireComponent(typeof(RectTransform))]
[RequireComponent(typeof(CanvasRenderer))]
public class UIParticle : MaskableGraphic
{
protected override void OnEnable()
{
UIParticleUpdater.Register(this);
CanvasRenderer渲染包含在Canvas中的UI对象,是一个Graphic必须的
UIParticleUpdater
Canvas.willRenderCanvases监听
internal static class UIParticleUpdater
{
[RuntimeInitializeOnLoadMethod]
private static void InitializeOnLoad()
{
Canvas.willRenderCanvases -= Refresh;
Canvas.willRenderCanvases += Refresh;
}
Q: Canvas.willRenderCanvases监听
A:官方解释:在即将开始 Canvas 渲染前调用的事件。
这让您能够延时处理/更新基于画布的元素,直到即将开始渲染它们之时。在这里做生成粒子的Mesh,再通过调用particle.canvasRenderer.SetMesh,渲染粒子的mesh
Refresh
private static void Refresh(UIParticle particle)
{
Profiler.BeginSample("[UIParticle] Bake mesh");
BakeMesh(particle);
Profiler.EndSample();
Profiler.BeginSample("[UIParticle] Set mesh to CanvasRenderer");
particle.canvasRenderer.SetMesh(particle.bakedMesh);
Profiler.EndSample();
}
想了解更多可以下载下来仔细研究
在你的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
}
}
}