您现在的位置是:首页 >技术杂谈 >Unity中频繁调用SetActive导致的性能问题网站首页技术杂谈
Unity中频繁调用SetActive导致的性能问题
和Native层的穿梭调用
SetActive 方法的调用涉及跨越 C# 层 和 Native 层 之间的通信,这比单纯在 C# 层内进行的操作要慢一些。因此,频繁调用 SetActive 可能会导致性能下降,尤其是在大量对象需要频繁被激活或禁用的情况下。
为了更好地理解这个问题,我们可以分解它的几个要点:
1. C# 层和 Native 层
- C# 层:这是我们在Unity中编写的脚本部分,运行在.NET环境中。Unity的用户代码通常是通过C#来编写的。
- Native 层:这是指Unity底层的原生代码部分,通常用C++编写,负责处理渲染、物理模拟、输入事件等。Unity引擎的核心功能大多是在Native层中实现的。
SetActive 的调用不是仅仅在 C# 层完成的。它需要将操作传递给底层的Native代码进行实际的对象激活或禁用。因此,调用 SetActive 时会涉及 C# 层到 Native 层的穿梭调用,这需要一定的开销。
2. C#层到Native层的穿梭调用
- 这种跨层调用会增加额外的性能开销,因为它需要在两者之间进行上下文切换。具体来说,C# 层的操作需要将信息传递给底层的引擎,后者再执行实际的激活或禁用操作。
- 这个过程不仅仅是简单的函数调用,它还涉及线程同步、内存访问等系统级操作,可能会带来性能瓶颈,特别是在频繁调用时。
3. 频繁调用 SetActive 的性能问题
- 当
SetActive被频繁调用时,Unity引擎需要处理大量的激活和禁用操作,这不仅会占用CPU时间,还可能导致垃圾回收(GC)和其他性能问题。因为每次激活/禁用对象时,Unity会重新计算和更新对象的状态(包括它们的渲染状态、层级关系、组件启用状态等)。
渲染开销
SetActive 会导致 Canvas 抛弃其 VBO(顶点缓冲对象)数据:
SetActive是一个用来启用或禁用游戏对象(包括UI元素)的方法。当一个对象被禁用时,它会从场景中移除(不再渲染)。- 对于
Canvas组件来说,禁用后,它会丢失与渲染相关的顶点缓冲区(VBO,Vertex Buffer Object)。VBO 存储了渲染物体所需的顶点数据。当Canvas被禁用时,这些缓存数据会被丢弃。
重新启用 Canvas 会强制进行 rebuild 和 rebatch:
- 当你重新启用一个禁用的
Canvas时,Unity 会强制重新构建(rebuild)和重新批处理(rebatch)所有的渲染数据。 - Rebuild 是指重新计算和生成
Canvas上的 UI 元素的渲染数据,比如重新生成UI元素的顶点、材质等。 - Rebatch 是指对这些渲染数据进行批处理,使得在 GPU 上的渲染调用尽可能地合并,减少过多的绘制调用,从而提高渲染性能。
Rebuild是什么
在Unity中,rebuild 过程通常指的是 重新构建 场景、UI、或者其他资源的渲染数据。对于 Canvas,rebuild 过程尤为重要,因为它涉及到UI元素的布局、渲染数据的生成、以及与图形管线的交互。这里详细讲解Unity的 rebuild 过程,主要集中在 Canvas 组件上的UI重建过程。
Unity的Rebuild过程
-
UI元素的布局计算:
在
Canvas中,每个UI元素(如按钮、文本、图片等)都有自己的布局需求(例如尺寸、位置、对齐方式等)。rebuild过程的第一步通常是根据当前的布局设置重新计算这些UI元素的尺寸和位置。这一步骤会触发UI元素之间的关系计算,例如父子层级关系的传播、布局规则(如Horizontal Layout Group,Vertical Layout Group)的应用等。在这阶段,Unity会检查是否需要更新UI元素的世界坐标、局部坐标,以及与其他UI元素的对齐方式。 -
重新生成顶点数据:
每个UI元素通常会被转换为多个顶点来渲染。例如,一个
Image组件会由四个顶点组成,用来表示其矩形区域。Text组件会根据文本内容生成一系列顶点。rebuild过程中,Unity会为每个UI元素重新计算这些顶点的属性,包括它们的坐标、颜色、UV坐标等。这些顶点数据是渲染过程的基础,UI元素的形状和样式都依赖于这些数据。 -
生成材质和纹理数据:
Unity会根据UI元素的渲染需求生成或者更新所需的材质、纹理和着色器参数。这对于每个UI元素是独立的,尤其是当UI元素使用不同的材质(例如
Image使用不同的Sprite时)时。rebuild过程会涉及到根据UI元素的状态(例如切换不同的按钮样式、文本字体变化等)来调整材质或纹理的生成。这个过程也涉及到Canvas下所有UI元素的材质和纹理的管理。 -
重新计算和更新批处理信息(Rebatching):
一旦UI元素的顶点数据、材质和纹理计算完成,Unity会尝试将多个渲染相同材质的UI元素进行批处理(batching),以减少渲染调用。
Rebatching过程意味着把多个UI元素的渲染数据合并到一个或多个渲染批次中,从而减少GPU绘制调用的次数。Unity会根据UI元素使用的材质、图层等来决定如何批处理。批处理可以极大提升渲染性能,因为每次渲染一个UI元素都会涉及到与GPU的通讯,而减少这些通讯次数可以减少性能开销。 -
更新CanvasRenderer:
在
rebuild过程中,每个UI元素的CanvasRenderer会被更新。CanvasRenderer是Unity的UI渲染组件,负责将UI元素的顶点数据、材质、颜色等信息传递给图形管线。如果UI元素发生了变化(例如位置、尺寸、材质),CanvasRenderer会进行更新,确保渲染到屏幕上时能够正确显示。 -
UI元素的绘制顺序和透明度计算:
如果UI元素的透明度、层级(sorting order)或者排序方式(如
CanvasGroup、Graphic Raycaster)发生了变化,rebuild过程还需要重新计算这些信息,确保UI的显示顺序和透明度效果正确。例如,当多个UI元素处于不同的Canvas上时,Unity会重新计算每个元素的渲染顺序,以确保屏幕上的显示效果是正确的。 -
渲染数据的提交到GPU:
最终的渲染数据会被提交到GPU,这时候所有的UI元素的渲染状态、顶点数据、材质和纹理等信息都被传输给GPU,等待绘制到屏幕上。
Canvas的Rebuild与Rebatch
- Rebuild 是对UI结构和渲染数据进行重新计算和生成,而 Rebatch 则是对渲染调用的优化,减少绘制调用的次数。
- 频繁的
rebuild操作会导致大量的 CPU 和 GPU 工作,因为每次rebuild都会重新计算顶点数据、材质、布局等。如果一个Canvas中的UI元素频繁变化,或者SetActive调用太频繁,会导致性能下降。 - 如果需要避免频繁的
rebuild,可以通过优化UI元素的更新机制,减少不必要的Canvas更新操作。比如避免每帧都更新UI的布局,或者使用Canvas的 RenderMode 设置来管理多个UI层。





U8W/U8W-Mini使用与常见问题解决
QT多线程的5种用法,通过使用线程解决UI主界面的耗时操作代码,防止界面卡死。...
stm32使用HAL库配置串口中断收发数据(保姆级教程)
分享几个国内免费的ChatGPT镜像网址(亲测有效)
Allegro16.6差分等长设置及走线总结