Unity uGUI优化

Unity uGUI优化

https://unity.com/cn/resources/optimize-mobile-game-performance-unity-2022lts Game Programming Patterns

UGUI的大量元素会导致大量的Draw Call,每个UI元素需要单独进行渲染处理,过多的Draw Call会占用CPU资源,影响帧率

优化目标:

  • 减少Draw Call数量
  • 减少Canvas更新频率
  • 压缩资源
  • 针对平台优化
  • 减少半透明的使用

默认情况下,Canvas会对挂载在其下面的所有UI元素进行一次性绘制(批量处理,合并Draw Call) 当某个UI元素(例如按钮、文本、图片)发生变化,Canvas会重新计算这些元素的布局和绘制信息。 为了确保正确的结果,Canvas通常需要重新计算并重新绘制 整个Canvas 下的内容,而不是只更新改动的部分。

Canvas

利用批处理来降低Draw Call频率,将 UI 层级下的所有内容集中在一次绘制操作中完成

如果你有一个非常巨大的Canvas,拥有上千的元素,更新一个元素会强制整个Canvas做更新,这会产生CPU性能尖刺。

为什么Canvas被设计成更新一个元素就要更新整个Canvas?具体实现是怎样的?

uGUI的源码大量使用对象池 因为Graphic对象需要频繁获取Canvas列表或Component列表

Canvas Rebuild做了什么 实现ICanvasElement接口的类需要实现自己的Rebuild方法 对于视觉UI元素 Runtime.Core.Graphic

  • 如果顶点有更新,那么就为CanvasRenderer重新生成网格
  • 如果材质和纹理有更新,那么就为CanvasRenderer更新纹理和材质 其他非视觉元素,大概就是更新以下各自维护的数据结构

什么情况下会触发Canvas Rebuild - Runtime.Core.CanvasUpdateRegistry

  • LayoutRebuildQueue
  • GraphicRebuildQueue 对外提供接口
  • RegisterCanvasElementForLayoutRebuild
  • RegisterCanvasElementForGraphicRebuild

Graphic Rebuild Runtime.Core.Graphic

  • SetVerticesDirty
  • SetMaterialDirty

Layout Rebuild Runtime.Core.Graphic

  • SetLayoutDirty 由Runtime.Core.Layout.LayoutRebuilder负责实现

Graphic类型由具体的子类在业务逻辑中负责调用各类SetDirty方法

在哪里实现了,改变Canvas的一个子元素就要使整个Canvas的所有子元素都Rebuild?

Layout相关变化会触发Layout Rebuild,如果子元素的布局影响了父元素的布局(ContentSizeFitter或LayoutGroup,动态添加或移除子元素),则会导致整个Canvas的布局重新计算

视觉相关变化(修改Image的Sprite,修改Text内容等),只触发Graphic Rebuild,通常只影响该元素自身,如果子元素的改动影响了父元素的渲染(Mask, CanvasGroup),则父元素也需要进行Rebuild

如果某个子元素的变化导致了顶点数据或渲染顺序的变化,Unity 可能需要重新生成整个 Canvas 的批次数据。

Runtime.Core.GraphicRegistry RegisterGraphicForCanvas(Canvas c, Graphic graphic)

合批规则的源代码在哪? Canvas, CanvasRenderer是在引擎内部代码,C++实现吗?怎么去追踪 找到了Unity C# Binding,但没有实现 https://github.com/Unity-Technologies/UnityCsReference/tree/master

也就是说,合批规则,需要从现有的资料触发,通过观察Frame Debugger,然后实验出来。没办法直接从最新版本的引擎代码里解读出来,因为Canvas的实现代码没有暴露出来。

https://blog.csdn.net/sinat_25415095/article/details/112388638

使用 Hugo 构建
主题 StackJimmy 设计