Unity UI性能优化一之插件【Unity UI Optimization Tool】

一.Unity UI Optimization Tool下载安装

访问主页可阅读基础使用流程,性能优化的方案:

https://github.com/JoanStinson/UnityUIOptimizationTool#reduce-game-objects-inside-prefabs

下载unitypackage包

https://github.com/JoanStinson/UnityUIOptimizationTool/releases

导入到unity:

二.Unity UI Optimization Tool支持的优化技术.

2.1 对于不属于Button的 Image 组件,禁用Raycast Target

每次有 UI 输入(单击、点击、滚动等)时,Unity 的GraphicsRaycaster 都会迭代场景中的所有Raycast 目标,因此我们的处理量越少,节省的处理就越多。

cs 复制代码
        private static void DisableRaycastTargetForNonButtonImages(Transform child)
        {
            bool childHasInteractable = child.gameObject.TryGetComponent<Button>(out var childButton) || child.gameObject.TryGetComponent<Toggle>(out var childToggle);
            bool childHasImage = child.gameObject.TryGetComponent<Image>(out var childImage);

            if (!childHasInteractable && childHasImage)
            {
                childImage.raycastTarget = false;
            }
        }

2.2 避免在UI中使用 Animator 组件

Unity 的 Animator 组件主要用于3D动画。将其用于 UI 元素会导致额外的处理。

相反,最好的方法是使用自定义补间工具,例如 DOTween。

cs 复制代码
        private static void LogWarningIfAnimatorComponentsAreFound(Transform child, string selectedGameObjectName)
        {
            bool childHasAnimator = child.gameObject.TryGetComponent<Animator>(out var childAnimator);

            if (childHasAnimator)
            {
                Debug.LogWarning($"Child <b>{child.name}</b> of <b>{selectedGameObjectName}</b> has an Animator component. Please consider using a DOTween Animation or ShowHideAnimator instead if possible.");
            }
        }

2.3 在ScrollView中使用RectMask2D组件

做法:找到ScrollView子对象Viewport ,若发现它身上挂着的是Mask组件。直接移除Mask组件,然后添加RectMask2D组件。
效果:假设你的 ScrollView里有一个超长的列表,包含100个列表项。屏幕一次只能看到5个。如果没有 RectMask2D,Unity仍然会尝试生成全部100个项的网格顶点,并向GPU提交渲染,只是最终被模板(stencil)测试丢弃或遮挡,这浪费了大量CPU和GPU资源。有了 RectMask2D,只有可见的那5-8个附近项的UI元素会真正进入渲染管线。

cs 复制代码
        private static void AddARectMask2DToTheScrollRectIfItsMissingOne(Transform child, out bool childHasScrollRect)
        {
            childHasScrollRect = child.gameObject.TryGetComponent<ScrollRect>(out var childScrollRect);
            bool childHasRectMask2D = child.gameObject.TryGetComponent<RectMask2D>(out var childRectMask2D);

            if (childHasScrollRect && !childHasRectMask2D)
            {
                child.gameObject.AddComponent<RectMask2D>();
            }
        }

Mask组件和RectMask2D组件的区别:

特性 Mask RectMask2D
实现原理 依赖GPU的模板缓冲区 (Stencil Buffer) 通过CPU进行矩形区域裁剪,精确剔除被遮挡的UI元素
性能 相对较差。视图外的元素仍参与渲染(但被模板测试丢弃),可能增加GPU开销 性能极高 。视图外的元素直接不参与渲染,有效降低DrawCall和Overdraw
灵活性 支持任意形状的遮罩(如圆形、星形) 仅支持矩形遮罩,是最适合ScrollView的形状
额外开销 可能修改材质,破坏UI渲染批处理(Batching) 无需修改材质,无额外DrawCall
适用场景 需要非矩形遮罩效果的UI 滚动视图、列表等标准矩形裁剪区域

为什么ScrollView的标准模板用的是 Mask

这主要是因为历史原因。在Unity的早期版本中,创建ScrollView时默认使用的是Mask组件。这种使用GPU模板缓冲区的做法在当时很普遍。

但随着UI系统的发展,RectMask2D因其针对性的优化性能更好,已经成为了更优的选择。它的裁剪原理非常适合滚动列表------只渲染显示区域内的内容,区域外的直接跳过,完美契合ScrollView的需求

2.4 禁用Canvas的 Pixel Perfect

  • Pixel Perfect的作用:开启后,Unity会尝试将Canvas下所有UI元素的顶点坐标对齐到屏幕的整数像素位置,避免UI元素因浮点坐标产生"模糊"或"像素边缘锯齿"。

  • 性能影响:为了实现这种对齐,Unity需要在每帧或每次UI布局变化时,对每个顶点的位置进行额外的数学运算(舍入、取整等)。对于包含大量UI元素(文本、图片、复杂布局)的Canvas,这部分计算会显著增加CPU开销,特别是UI频繁变动(如滚动列表、动态数值更新)时。

  • 禁用后:顶点直接使用原始的浮点坐标渲染,跳过了对齐转换步骤,加快了网格构建和布局更新速度。

  • 只有在需要像素级精确显示(如像素风游戏、精细小图标)且性能充裕时,才值得开启此选项。

    最佳实践:默认不勾选Pixel Perfect;只有在发现UI有明显模糊且无法通过其他方式(如调整RectTransform锚点、使用整数坐标)解决时,再评估是否开启。

cs 复制代码
        private static void DisablePixelPerfectForCanvasContainingAScrollRect(ref Canvas canvas, ref bool hasScrollRect, Transform child, bool childHasScrollRect)
        {
            bool childHasCanvas = child.gameObject.TryGetComponent<Canvas>(out var childCanvas);

            if (childHasCanvas)
            {
                canvas = childCanvas;
            }

            if (childHasScrollRect)
            {
                hasScrollRect = true;
            }

            if (hasScrollRect && canvas != null)
            {
                canvas.pixelPerfect = false;
            }
        }

三.文档中提到的优化技巧

3.1 减少Prefab内的gameobject

做法:在可能的情况下,减少Prefab内的gameobject数量

效果:

  1. 降低实例化耗时

    每个GameObject及其组件在实例化时都需要分配内存、初始化属性、建立父子关系。对象越多,实例化时的CPU开销越大,尤其是复杂Prefab在运行时动态生成时,影响明显。

  2. 减少绘制调用(Draw Call)与渲染开销

    即使GameObject使用相同材质,若网格、渲染组件或层级结构复杂,也可能导致渲染批次增加。减少不必要的GameObject可降低渲染管线压力。

  3. 降低场景加载与内存占用

    每个GameObject都会增加场景序列化数据量,加载时需解析更多数据。同时,Transform等组件的内存开销虽小,但大量对象累积会显著增加内存占用,并可能触发频繁的GC

减少Prefab内的GameObject数量本质上是降低整体复杂度,减少CPU/内存/渲染管线的负载

3.2 不要使用 Alpha 来隐藏 UI 元素

做法:通过gameObject.SetActive(false)隐藏UI元素,不用通过color.alpha = 0隐藏

原因:

1.即使 Alpha = 0,UI 元素的 Mesh(网格)依然会被提交给 GPU 进行渲染,

2.填充率(Fill Rate)浪费

3.仍然会阻挡射线检测(Raycast)

4.不利于节省DrawCall:UI 系统的合批仍然需要考虑它

5.逻辑与状态的不清晰(比如放在布局组中依然会占位)

相关推荐
jump_jump1 天前
流式 HTML:从 htmx 片段装配到浏览器原生增量渲染
javascript·性能优化·前端工程化
小小工匠2 天前
Redis - 事务机制:能实现 ACID 属性吗
数据结构·redis·性能优化·并发·持久化
大鱼>2 天前
地平线BPU部署实战:YOLOv8在J5/X3上的算法适配与性能优化
算法·yolo·性能优化
醉颜凉3 天前
Elasticsearch高性能优化:Bulk API大规模数据导入性能调优全攻略
elasticsearch·性能优化·jenkins
叶帆3 天前
【YFIOs】用C#开发硬件之设备上云
开发语言·unity·c#
隔窗听雨眠3 天前
C语言函数递归从入门到精通(下):性能优化与工程实践
c语言·算法·性能优化
久数君3 天前
AI三维建模工具“造形家”:地理场景三维化的高效解决方案
unity·glb·ai算法·ai三维建模工具·地图框选·造形家·城市建筑模型
昇腾CANN3 天前
【cann-samples系列】GroupedMatmul MX量化矩阵乘的深度性能优化实践
线性代数·性能优化·矩阵·昇腾·cann
霸道流氓气质3 天前
Spring Boot 微服务性能优化完全指南
spring boot·微服务·性能优化
步步为营DotNet3 天前
Blazor 与 Microsoft.Extensions.AI 在客户端性能优化中的协同应用
人工智能·microsoft·性能优化