填充率

我们打开Scene窗口的Overdraw,可以查看到每个UI界面的重复绘制情况。

重复绘制

由于显卡的填充率有限,过多的重复绘制肯定会影响性能。

注意要点

UI的Image组件即使是全透明的也会增加Overdraw。

在设计UI时,尽量不要让UI元素相互覆盖。

在设计UI时,不要把UI分得太细。可以合并成一个图的尽量合并成一个。

圆形和不规则形状的UI,它们的原贴图一般都是方形的,可以对原贴图进行适当的裁剪优化。

优化

  1. 框型UI,使用九宫格。使用九宫格可以让框型UI中间部分镂空:

    九宫格镂空

  2. 不规则图形,无法使用九宫格,也是可以镂空的,通过一些工具脚本。(待补充)

  3. Mask,根据情况,可以使用自定义的Mask(比如圆形图片组件)

  4. Unity对Text组件,有自带的Outline和Shadow效果,它们的原理只是简单复制Text,会大量增加顶点和三角面。从而增加填充率。所以对于文本,无脑选择TextMesh Pro。如果条件允许,也可以自己写一个文本Outline效果。(待补充)

UI和3D物体

有的时候,当我们有些场景的物体使用OnRender等类似的函数时,在Game场景下物体已经不在Camera区域内了,但是OnRender函数依然会触发,这是因为Scene场景的摄像机依然在起作用。

在Unity中,打开一个全屏的UI,那些被UI遮挡的3D物体并不会取消渲染,我们可以准备一个UI摄像机,一个渲染摄像机,在开启全屏UI时,关闭渲染摄像机来优化。

图片平铺

Unity的Image组件,自带Image Type :Tiled,使用它可以平铺Image。但是,Image组件自带的平铺和Text的outline效果一样,使用后会增加顶点。

Image自带平铺增加顶点

使用需要平铺的图片作为UI的时候,可以使用RawImage组件。

修改图片素材导入设置,Texture Type设为Default,Wrap Mode设为Repeat。

将这个图片赋给RawImage组件,然后修改UV Rect的W和H的值,就能实现平铺效果,而且并不会增加顶点。

Pixel Perfect

在Canvas组件下,有一个Pixel Perfect开关,它的作用是微调UI,让UI的像素对齐(边缘更清晰),当Canvas下有Text,或者Canvas下有Scroll View时,会增加性能损耗,如果没必要,不要开启Pixel Prefect。

Raycast Target

每次点击时,需要响应的UI(开启Raycast Target的UI)都会保存在一个List当中,这个List中的UI元素越少,遍历的性能也就越高。

某一些Image或Text没有必要响应点击,关闭它们的Raycast Target。

UI动静分离

一个Canvas下的某个UI元素发生改变时,Canvas会把所有的UI元素Rebuild一遍,重新生成网格。

方案一

准备两个Canvas,一个静态Canvas,一个动态Canvas,两个Canvas层级是同级的。注意动态Canvas下没有子物体。

首先把UI都设定在静态Canvas下。当某些需要移动的UI移动时,把它们设为动态Canvas的子物体。

这种方案的缺点是,动态Canvas下的UI层级管理是个难题,可能出现意料之外的UI遮挡情况。

方案二

分成主Canvas和子Canvas,一开始UI都设定在主Canvas下,当某些需要移动(或者做渐变)的UI移动时,给它们(或它们的父级)动态挂载Canvas组件,这样子Canvas下的UI重建,并不影响主Canvas,当UI移动完毕后,卸载子Canvas组件,重新和主Canvas下的UI元素合批。子Canvas也可以自定义Sort Order,更好地管理层级。

这种方案的缺点是,需要控制子Canvas的数量,每增加Canvas都会增加drawcall,一个场景的Canvas要控制在4个之内。

UI渐变

当一个UI需要渐变或者改变颜色时,不建议修改Image组件的Color属性,这样会导致这个Image组件重建。

新建一个材质球,使用“UI/Default”作为Shader,然后修改这个材质球的“Tint”来制作单个UI的渐变,我们可以在代码中通过访问“_Color”属性来改变材质颜色。(material.setColor("_Color",new Color())

UI开闭

当一个UI SetActive(false)时,它的顶点、材质和Layout都会被打上脏标记,再次打开这个UI就会触发重建,如果我们频繁开闭一个Mesh非常多的组件(比如有大量Text),就会导致卡顿。

如果是单个UI图片,在没有被RectMask2D遮罩的情况下,可以使用Image.CanvasRenderer.cull来控制显隐(true为隐藏)。

【UGUI】利用CanvasRenderer.cull来实现低消耗界面显隐_ontransformparentchanged-CSDN博客

如果是一组UI,可以使用CanvasGroup组件来实现显隐。

BestFit

这个是Text组件的属性,让字体适应Rect框的大小。但是Unity会把重新生成的字体全部添加到字体的动态贴图当中,导致贴图非常大。一般情况下,直接关闭这个属性。

Button打断合批的操作

Pos Z

RectTransform中的Pos Z会打断合批,下面是4个完全相同的Button组件

Pos Z相同

Pos Z打断合批

第二个Button的PosZ是10,打断了合批。

修改了PosZ会直接打断合批,其原理和UI组件的Depth无关。

Rotation

Button的RectTransform的Rotation属性,X和Y的值不是180的倍数的时候,会打断合批。Z值并不会打断合批。

解决方案

把一个Button拆分成单个Image或者单个Text即可解决上面两个不能合批的问题。

一般情况下,不要修改Button的PosZ和Rotation属性,在动态生成的UI中,每次生成都要注意重置一下各个UI的位置。

如果某些UI必须要旋转,可以把这些UI分离开,或者使用自定义的Shader材质模拟某些方向上的旋转效果。