网站 设计 案例 简单,门户网站建设关系到,今天安阳发生的重大新闻,商业网络上期我们学习了简单的Scene优化#xff0c;接下来我们继续编辑器创建资源的UGUI优化 UI篇#xff08;UGUI#xff09;
优化UGUI应从哪些方面入手#xff1f;
可以从CPU和GPU两方面考虑#xff0c;CPU方面#xff0c;避免触发或减少Canvas的Rebuild和Rebatch#xff0c…上期我们学习了简单的Scene优化接下来我们继续编辑器创建资源的UGUI优化 UI篇UGUI
优化UGUI应从哪些方面入手
可以从CPU和GPU两方面考虑CPU方面避免触发或减少Canvas的Rebuild和Rebatch减少Drawcall减少CPU处理顶点的时间GPU方面降低Overdraw缩小纹理大小。
Canvas的Batch构建过程The Batch building process简称Rebatch Batch 构建过程是指Canvas通过结合网格绘制它所承载的UI元素生成适当的渲染命令发送给Unity图形流水线。Batch的结果被缓存复用直到这个Canvas被标为dirty当Canvas中某一个构成的网格改变的时候就会标记为dirty这个Dirty就会触发Rebatch。
Rebatch不仅有批处理排序还有网格合并之类的。Canvas的网格从那些Canvas下的CnavasRenderer组件中获取但不包含任何子Canvas。
所以对于UGUI的性能分析要分开两点
Canvas的批处理过程 Rebatch Graphic 和Layout的 Rebuild 这两点都会影响性能。但是Rebatch是有多线程的加持的而Rebuild是在主线程的。
Rebuild自身会有性能消耗同时Rebuild会触发Rebatch。 Rebatch除了被Rebuild触发还会被其他情况触发。 Rebatch的性能上的问题在电脑上比较难看的出来因为有多线程加持。 Rebuild过程
Rebuild 过程是指Layout和Graphic组件的网格被重新计算这是在CanvasUpdateRegistry类中执行的。这是一个C类打开UI的源码它里面的一个函数叫做PerformUpdate当一个Canvas组件触发它的WillRenderCanvases事件时这个方法就会被执行。这个事件每帧调用一次这也是为什么我们看Profile的时候出现性能高峰的总是会看到WillRenderCanvases的原因了。
PerformUpdate的运行过程分3步
按顺序遍历调用Dirty的Layout组件的Rebuild函数 要求任何已注册的裁剪组件例如Mask剔除所有裁剪的组件。这是通过ClippingRegistry.Cull完成的。 按顺序遍历调用Dirty的Graphic组件的Rebuild函数
Rebuild分为 Layout Rebuild 和 Graphic Rebuild
Layout Rebuild 要重新计算一个或多个Layout组件中包含的组件的适当位置和可能的大小必须按其适当的层次结构顺序应用Layouts。在GameObject层次结构中靠近根部的布局可能会更改嵌套在其中的任何布局的位置和大小因此必须首先进行计算。 为此UGUI根据层次结构中的深度对dirty的Layout组件列表进行排序。层次结构中较高的Layout即父节点较少将被移到列表的前面。 然后排序好的Layout组件的列表将被rebuild在这个步骤Layout组件控制的UI元素的位置和大小将被实际改变。
Graphic Rebuild 当Graphic组件被rebuild的时候UGUI会将控制权传递给ICanvasElement接口的Rebuild方法。Graphic执行了这一步并在rebuild过程中的PreRender阶段运行了两个不同的rebuild步骤
如果顶点数据已标记为Dirty例如当组件的RectTransform的大小更改时则将重新构建网格。 如果将材质数据标记为Dirty例如当更改组件的材质或纹理时则将更新附加的Canvas Renderer的材质。 Graphic的Rebuild不会按照Graphic组件的特殊顺序进行并且不需要任何排序操作。
Rebatch和Rebuild的触发条件总结
触发Rebatch的条件
当Canvas下有Mesh发生改变时如 SetActive Transform属性变化 Graphic的Color属性变化改Mesh顶点色 Text文本内容变化 Depth发生变化触发Rebuild的条件
Layout修改RectTransform部分影响布局的属性 Graphic的Mesh或Material发生变化 Mask裁剪内容变化
Unity UI性能的四类问题 1. Canvas Re-batch 时间过长 2. Canvas Over-dirty, Re-batch次数过多 3. 生成网格顶点时间过长 4. Fill-rate overutilization Canvas画布 Canvas负责管理UGUI元素负责UI渲染网格的生成与更新并向GPU发送DrawCall指令。 Canvas Re-batch过程(合批) 1. 根据UI元素深度关系进行排序 2. 检查UI元素的覆盖关系 3. 检查UI元素材质并进行合批 合批对比 UGUI渲染细节 UGUI中渲染是在Transparent半透明渲染队列中完成的半透明队列的绘制顺序是从后往前画由于UI元素做Alpha Blend,我们在做UI时很难保障每一个像素不被重画UI的Overdraw太高这会造成片元着色器利用率过高造成GPU负担。UI SpriteAtlas图集利用率不高的情况下大量完全透明的像素被采样也会导致像素被重绘造成片元着色器利用率过高同时纹理采样器浪费了大量采样在无效的像素上导致需要采样的图集像素不能尽快的被采样造成纹理采样器的填充率过低同样也会带来性能问题。如下图 Re-Build过程重构 1.在WillRenderCanvases事件调用PerformUpdate::CanvasUpdateRegistry接口 通过ICanvasElement.Rebuild方法重新构建Dirty的Layout组件 通过ClippingRegistry.Cullf方法任何已注册的裁剪组件Clipping Compnents(Such as Masks)的对象进行裁剪剔除操作 任何Dirty的 Graphics Compnents都会被要求重新生成图形元素 2.Layout Rebuild UI元素位置、大小、颜色发生变化 优先计算靠近Root节点并根据层级深度排序 3.Graphic Rebuild 顶点数据被标记成Dirty 材质或贴图数据被标记成Dirty 使用Canvas的基本准则 将所有可能打断合批的层移到最下边的图层尽量避免UI元素出现重叠区域尤其是一些很小的ui元素比如字体是一个很小的矩形容易被忽略但是每一帧都会导致重新合批可以拆分使用多个同级或嵌套的Canvas来减少Canvas的Rebatch复杂度拆分动态和静态对象放到不同Canvas下来避免动态UI元素导致每帧都要做太复杂的canvas Rebatch操作不使用Layout组件这样就不会有太多的rebuild 的过程了同样可以减少Rebatch的时间消耗Canvas的RenderMode尽量Overlay模式减少Camera调用的开销 UGUI射线Raycaster优化 必要的需要交互UI组件才开启“Raycast Target”开启“Raycast Targets”的UI组件越少层级越浅性能越好对于复杂的控件尽量在根节点开启“Raycast Target”对于嵌套的CanvasOverrideSorting属性会打断射线可以降低层级遍历的成本 UGUI优化思路
1.Canvas 子节点动静分离
在UI Canvas 中进行子节点动静分离主要是将频繁变动的UI元素如动态文本动画图标与相对静态的元素如背景图固定按钮分开管理。这样可以减少不必要的重绘提高性能。通常将动态节点放在一个单独的Canvas或者层级下。在需要更新时只重绘该部分避免影响影响静态元素。
2.Sprite Packer
是将多个小的UI精灵纹理合并成一个大纹理图集的工具这有助于减少纹理加载次数和内存占用提高渲染性能
3.运行时动态合并图集
当然UI运行时动态合并图集性能 1.减少合并频率 2.合并前筛选出真正需要合并的元素避免不必要的操作 3.尽量采用多线程技术来处理合并任务防止阻塞主线程 4.对图集大小合理限制防止内存占用过大 4.自动布局组件
不要使用Layout组件Layout组件性能消耗相对昂贵会大大地增加Canvas.SendWillRenderCanvases函数耗时利用好RectTransform同样可实现简单布局。
5.动态加载和裁剪
对于UI动态加载可以采用对象池来管理UI元素避免频繁的实例化和销毁在裁剪方面设置合理的裁剪区域减少不必要的计算同时利用层级结构和遮挡关系减少渲染压力。
6.组件中自定义材质球打断合批
在UI组件中自定义的材质球打断合批主要是因为其改变了渲染状态当材质球的shader纹理等属性与其他UI组件不同时就无法合批渲染可以通过统一材质属性或者使用相同的材质模板来减少这种打断提高渲染效率
7. Raycat Target 1.只需要在交互的UI元素上勾选如按钮等。 2.使用射线检测范围更小的组件替换 3.将不需要检测的UI元素放在不勾选Raycat Target的父物体下利用层级关系减少不必要的检测 8.不可见元素 Cull Transparent Mesh
对于UI中不可见元素使用Cull Transparent Mesh剔除透明网格可以提高性能它通过不渲染这些不可见的透明元素减少了渲染计算量和内存占用一般在合适的渲染管线设置中开启此功能即可 9.UI 字体TTF和OTF 1.选择简洁的字体减少复杂笔画 2.使用字体图集合并常用字符纹理 3.根据需要动态加载字体资源 4.避免字体框重叠造成合批打断 5.字体网格重建UIText组件发生变化时父级对象发生变化时UI组件或其父对象enable和disable时 谨慎使用Text的Best Fit选项虽然这个选项可以动态的调整字体大小以适应UI布局而不会超框但其代价是很高的一方面是适配本身在调整文本框大小时有CPU耗时开销另一方面每个字号下新生成的字都会在Font Texture上占用一个字的大小容易导致Font Texture过大这个类似图集当Font Texture当前大小放不下时才会占用更多内存。这个特定问题已在 Unity 5.4 中得到纠正Best Fit 不会不必要地扩展字体的纹理图集但仍然比静态大小的文本慢得多。
10.计时器和倒计时触发UI重绘
11.Sprite 九宫格设置
如果是较大的背景图的UI元素建议也要使用Sprite的九宫格拉伸处理充分减小UI Sprite大小提高UI Atlas图集利用率
12.GameObject Active/Deactive - UI CanvasGroup Alpha 13.Canvas Pixel Perfect
谨慎使用Canvas的Pixel Perfect选项该选项会使得ui元素在发生位置变化时造成layout Rebuild。比如ScrollRect滚动时如果开启了Canvas的pixel Perfect会使得Canvas.SendWillRenderCanvas消耗较高 14.shadow 顶点和面数翻倍
15.outline 顶点和面数翻倍
慎用自带组件Outline和Shadow都是通过重复绘制多个Mesh实现的其中Shadow绘制为原文本Mesh的2倍而Outline为5倍对渲染面数、顶点数BuildBatch和SendWillRenderCanvases的耗时Overdraw都有影响。如经常用可考虑其它方式如TextMeshPro或把阴影和描边做到字体里。
16.元素 position Z值不为 0 打断合批
17.Mask vs RectMask2D
Mask依赖Image组件占用两个Batch多一倍Overdraw可以裁剪任意形状。 RectMask2D不依赖Image组件不占用Batch没有Overdraw只能裁剪规则形状。 因此一般情况下规则的裁剪尽量用RectMask2D代替Mask特别是在使用ScrollRect时。 RectMask2D一定比Mask好吗并不是Mask间是可以合批的而RectMask2D间不行因此当要使用多Mask时如背包界面中的道具格子每个格子有裁剪需求时尽量用MaskMask可合批而RectMask2D会导致合批被打断。
因此
当一个界面只有一个Mask那么RectMask2D优于Mask当有两个Mask那么两者差不多当大于两个Mask那么Mask优于RectMask2D。
18.避免多层 激活UI元素堆叠
19.加载页/活动图等几乎充满屏幕的UI关闭场景相机渲染或渲染一张RT模糊后作背景
20.文本组件建议使用Text Mesh Pro
21.界面操作一般会触发UI的开关或者隐藏显示Active 和DeActive必然会造成UI重建。而采用控制Canvas组件的激活与关闭。
22.不需要参与点击事件的Canvas取消激活Graphic Raycaster 脚本。
射线检测遍历所有将Raycast Target设置为true的Graphic组件。每一个Raycast Target都会被进行测试。如果一个Raycast Target通过了所有的测试那么它就会被添加到“被命中”列表中。 每个Graphic Raycaster都将遍历 Transform层次结构一直到根此操作的成本与层次结构的深度成比例线性增长。因此进行射线检测的元素越多层级越深消耗越高。 鉴于所有射线检测目标都必须由Graphic Raycaster进行测试因此最好的做法是仅在必须接收点击事件的UI组件上启用Raycast Target设置。检测目标列表越少遍历的层级越浅每次射线检测的速度越快。
23.持续性的UI动态效果特效最好采用特效的方式制作脱离UI系统。
24.动态合静态的UI 要分开分别挂上canvas。
25. 在使用非全屏但模态对话框时建议使用**OnDemandRendering**接口对渲染进行降频。
26.优化裁剪UI Shader根据实际使用需求移除多余特性关键字。
27.滚动视图Scroll View优化 使用RectMask2d组件裁剪 使用基于位置的对象池作为实例化缓存 这篇文章是摘取自多个大神的文章所以会有知识点重复的情况但是我主张的是可以重复但是知识点一定要全 今天是2024年11月30日
重复一段毒鸡汤来勉励我和你
你的对手在看书
你的仇人在磨刀
你的闺蜜在减肥
隔壁的老王在练腰
而你在干嘛