Skip to main content

重建和重绘

面试题

  1. 重建(Rebuild)和重绘(Repaint)是什么?俩者有什么区别?

在Unity UGUI中,重建(Rebuild)重绘(Repaint) 是UI渲染流程中的两个独立阶段。

维度重建(Rebuild)重绘(Repaint)
阶段CPU端计算(生成网格数据)GPU端渲染(绘制像素)
触发条件UI属性修改(布局、文本、颜色等)网格数据更新或渲染环境变化
性能瓶颈CPU耗时(遍历层级、顶点计算)GPU耗时(片元着色、Overdraw)
优化目标减少重建频率(动静分离、批量操作)减少重叠区域(压缩透明部分)
调试工具Profiler:Canvas.BuildBatch耗时Frame Debugger:Draw Call与Overdraw

🔧 重建(Rebuild)

本质:CPU计算阶段,重新生成UI的网格(Mesh)和布局数据。

触发条件

  • 布局变动:UI元素位置、尺寸变化(如修改RectTransform、启用LayoutGroup)。
  • 视觉属性变动:修改文本内容(Text.text)、图片(Image.sprite)、颜色(Graphic.color)等。
  • 激活状态变化SetActive或父节点激活状态变更。

执行流程

  1. 标记脏数据:通过SetLayoutDirty()(布局变动)或SetVerticesDirty()(视觉变动)标记需要重建的元素。
  2. 加入重建队列:脏元素被注册到CanvasUpdateRegistry的队列中(m_LayoutRebuildQueuem_GraphicRebuildQueue)。
  3. 重建执行:在渲染前(Canvas.willRenderCanvases事件),依次调用队列中元素的Rebuild()方法,重新计算布局(LayoutRebuild)或生成网格(GraphicRebuild)。

性能影响

  • CPU密集型:遍历UI层级、计算顶点数据消耗CPU资源。
  • 卡顿主因:频繁重建(如每帧刷新文本)会导致帧率骤降。

🎨 重绘(Repaint)

本质GPU渲染阶段,将生成的网格数据提交到GPU进行绘制。

触发条件

  • 重建完成后,网格数据更新需提交到GPU。
  • 摄像机移动、UI覆盖关系变化等(即使未修改UI属性)。

执行流程

  1. 提交网格数据CanvasRenderer将重建后的Mesh数据传递给GPU。
  2. 执行绘制指令:GPU根据材质、纹理、混合模式等渲染像素到屏幕。

性能影响

  • GPU密集型:片元着色器处理透明度混合(Alpha Blending)时消耗大。
  • Overdraw问题:半透明UI重叠导致像素重复绘制,增加GPU负载(如多层遮罩)。

优化策略

减少重建频率

  1. 动静分离:动态UI(如血量条)与静态UI(如背景)分属不同Canvas,避免连锁重建。
  2. 批量修改:隐藏UI(SetActive(false))→ 批量更新属性 → 重新显示,合并为单次重建。
  3. 避免高频刷新:文本倒计时用1秒间隔替代逐帧更新。

降低重绘开销

  1. 压缩透明区域:确保Sprite图集的透明区域最小化,减少无效像素填充。
  2. 简化混合层级:减少半透明UI重叠,或用Shader替代多重遮罩。

工具定位瓶颈

  1. CPU卡顿:Profiler中Canvas.SendWillRenderCanvasesCanvas.BuildBatch高耗时 → 优化重建逻辑。
  2. GPU卡顿:Frame Debugger中高Overdraw区域(红色警告) → 优化UI层级或材质。