mesh渲染到ui_UGUI深入理解--渲染系统

UGUI怎么显示一张图片?从原理上来说,显示图片和其他渲染一样,需要的也是mesh和material。所以我们要看的就是怎么把mesh和material传给引擎。

UI的渲染可以分三部分来看

CanvasUpdateRegistry负责驱动,也就是通知需要渲染的UI组件,为什么用通知的方式而不是UI自己处理呢,UGUI的处理流程是这样的,UI自己记录是否需要重新渲染,注册事件给registry,registry在要渲染的时候触发事件,UI再去提交数据。这样的好处是,首先UI各种数据会在一帧内多次改变,肯定不能每次改变都发渲染事件,一帧处理一次效率比较高。再一个如果不发事件,那就必然要在update里写逻辑,比统一事件要麻烦些。

UI组件的基类是Graphic,Graphic核心功能是组织mesh和material然后传给底层,也就是CanvasRenderer类。

CanvasRenderer连接画布和渲染组件,通过CanvasRenderer把网格绘制到Canvas上,CR并不是直接渲染,而是交给Canvas,Canvas还要做合批等操作

CanvasRenderer这个名字有点误导,并不是对应Canvas,而是对应Graphic。重要的接口有两个,SetMesh和SetMaterial。一次设置后,如果没有改变,不需要重复设置,底层有缓存,mesh和material可以分开设置。

每个Graphic的CanvasRenderer保存了当前元素的mesh和material,但并不会每个Graphic一个drawcall,canvas会对节点下的Graphic进行合批,所以一个Graphic设置dirty,整个canvas都需要重新计算合批,这个消耗是比较大的,合理分配canvas,对性能影响较大,这是界面渲染性能要注意的地方。

UI渲染的结构大致如下图

重绘触发条件

enable,disable,validate都会触发

SetVerticesDirty

MeshEffect有变化

shadow属性改版

transform大小改变

image类型改变,层级改变,填充方式改变

RawImage:texture改变,uvRect改变,触发动画效果

text内容改变,开关richtex,等等很多,text是最频繁dirty的

SetMaterialDirty

material替换

Image触发动画

显示mask,设置是否开启mask

transform层级变化

canvas层级变化

重新计算mask

RawImage替换texture,使触发动画

同时dirty,包括layout

transform层级改变

Sprite替换,改变图片大小,替换图集

字体改变,字体图集变化

这部分没记太细,因为很多是不可避免的,同时重绘很可能成为瓶颈,也要有针对性的优化。

遮挡mask

两个方式,Rect2DMask和mask,只对子节点生效,理论上可以改源码,一般没啥必要改。

RectMask2D

只能遮挡矩形范围,类似NGUIpanel的裁剪方式。这种方式不增加drawcall,比mask性能高些,但是只能遮挡矩形区域。

shader部分,定义UNITY_UI_CLIP_RECT,color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);实现裁剪。

代码部分,调用CanvasRenderer的EnableRectClipping方法,传遮挡区域,底层设置给_ClipRect。

RectMask2D节点下的maskable组件,注册到ClipperRegistry类,底层控制对应的shader打开宏定义。

Mask

原理设置模板缓冲值,通过测试的像素显示,从而只在指定范围内显示图像。透明度为0的区域不显示。

实现方式

将渲染分3个步骤,首先渲染mask,设置模板缓冲的值,然后渲染模板下的对象,判断模板缓冲值,相同才渲染,也就是在根节点定义的区域内渲染,最后将模板缓冲区设置为0。

缺点打乱合批。

圆形边缘锯齿明显,原因是并不支持边缘渐变,只有显示和不显示两个状态。

遮挡效果只是显示,点击逻辑还是完整的区域,一般常用的,扩展一个图形更好,比如圆形。

对比NGUI

UGUI在需要重绘时触发事件,NGUI在update每帧检测,界面复杂的情况下会有一定额外消耗。

合批,NGUI开源,修改方便,也更好查问题。UGUI只是传数据到底层,规则只能是测试和猜。不过合批的原理基本相同,性能上UGUI更好,底层不用C#,在语言层面效率就更高些。

重绘,在NGUI和UGUI都是个性能消耗点,要注意。

层级,UGUI按节点顺序,调整起来容易一点,NGUI要点开才能看到depth,有点麻烦

裁剪,NGUI通过切换shader,多创建一个material实现的,要多一个shader,没有UGUI方便,而且UGUI2D的方式更高效,不过NGUI支持裁剪边缘模糊,UGUI要自己实现。

图集,NGUI的图集比较可控,UGUI默认的图集不可控,一般还要用其他方案实现。

总结下来,UGUI渲染还是比较好用的,mask也比较好用,图集要处理一下,这样更好控制包体和更新。

你可能感兴趣的:(mesh渲染到ui)