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.逻辑与状态的不清晰(比如放在布局组中依然会占位)

相关推荐
Zik----4 小时前
Unity基础学习笔记(B站视频课整理)
unity·vr
mit6.8244 小时前
CUDA Mode - Lecture 8
性能优化
郝学胜-神的一滴17 小时前
罗德里格斯旋转公式(Rodrigues‘ Rotation Formula)完整推导
c++·unity·godot·图形渲染·three.js·unreal
We་ct20 小时前
React 性能优化精讲
前端·javascript·react.js·性能优化·前端框架·html·浏览器
田鸡_1 天前
Unity新输入系统(Input System)教学篇
unity·游戏引擎·游戏程序
EQ-雪梨蛋花汤1 天前
【Unity笔记】Unity 音游模板与免费资源:高效构建节奏游戏开发全指南
笔记·unity·游戏引擎
星辰徐哥1 天前
Unity基础:游戏对象的激活与隐藏:SetActive方法详解
游戏·unity·lucene
微莱羽墨1 天前
零、0基础入门Unity 安装详细教程(2026最新版教程,安装Unity看这一篇就够了!)
unity·游戏引擎·unity安装
星辰徐哥1 天前
Unity C#入门:变量的定义与访问权限(public/private)
unity·c#·lucene