重建和重绘
面试题
- 重建(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或父节点激活状态变更。
执行流程
- 标记脏数据:通过
SetLayoutDirty()(布局变动)或SetVerticesDirty()(视觉变动)标记需要重建的元素。 - 加入重建队列:脏元素被注册到
CanvasUpdateRegistry的队列中(m_LayoutRebuildQueue或m_GraphicRebuildQueue)。 - 重建执行:在渲染前(
Canvas.willRenderCanvases事件),依次调用队列中元素的Rebuild()方法,重新计算布局(LayoutRebuild)或生成网格(GraphicRebuild)。
性能影响
- CPU密集型:遍历UI层级、计算顶点数据消耗CPU资源。
- 卡顿主因:频繁重建(如每帧刷新文本)会导致帧率骤降。
🎨 重绘(Repaint)
本质:GPU渲染阶段,将生成的网格数据提交到GPU进行绘制。
触发条件
- 重建完成后,网格数据更新需提交到GPU。
- 摄像机移动、UI覆盖关系变化等(即使未修改UI属性)。
执行流程
- 提交网格数据:
CanvasRenderer将重建后的Mesh数据传递给GPU。 - 执行绘制指令:GPU根据材质、纹理、混合模式等渲染像素到屏幕。
性能影响
- GPU密集型:片元着色器处理透明度混合(Alpha Blending)时消耗大。
- Overdraw问题:半透明UI重叠导致像素重复绘制,增加GPU负载(如多层遮罩)。
优化策略
减少重建频率
- 动静分离:动态UI(如血量条)与静态UI(如背景)分属不同Canvas,避免连锁重建。
- 批量修改:隐藏UI(
SetActive(false))→ 批量更新属性 → 重新显示,合并为单次重建。 - 避免高频刷新:文本倒计时用1秒间隔替代逐帧更新。
降低重绘开销
- 压缩透明区域:确保Sprite图集的透明区域最小化,减少无效像素填充。
- 简化混合层级:减少半透明UI重叠,或用Shader替代多重遮罩。
工具定位瓶颈
- CPU卡顿:Profiler中
Canvas.SendWillRenderCanvases或Canvas.BuildBatch高耗时 → 优化重建逻辑。 - GPU卡顿:Frame Debugger中高Overdraw区域(红色警告) → 优化UI层级或材质。