U
章 05导出到手机7 课 — 点击打开
03 / 07 · 11 分钟
导出到手机

移动端性能预算

到目前为止的项目

Assets/

link.xml

Scripts/

MobileBoot.csQualityAutoSetter.cs

Settings/

URP mobile asset

项目设置

IL2CPP + ARM64texture compression

你已经有的这一课新增

你在 tab 04 里已经让 Arena 达到了 batch 和三角形数量的预算 —— 但那是在桌面上。中档手机的 GPU 大概只有那股力的十分之一,而且发热之后还会自己降频,差不多五分钟就开始。

动态图解

四个数要压下去,一个数要提上来。

移动端的预算

  • Draw call / batch:100 以下比较宽松,60 以下在低端机上也稳。

  • 屏幕上的三角形数:100k–300k。再往上,中档 GPU 就开始冒汗了。

  • 实时灯光:一个 directional,就这样。其余全部 bake 好。

  • 贴图内存:200 MB 以内。别靠猜,去 Profiler 的 Memory 模块里看。

  • 目标:稳定的 60 FPS;如果机器撑不住 60,就老老实实锁死 30。

1. URP 设置 —— 单项收益最大的地方

  1. 1

    找到你的 URP Asset(在 Project Settings▸Graphics 里能看到当前生效的是哪一个)。

  2. 2

    Shadows → Max Distance 设为 40,Cascade Count 设为 1,Shadow Resolution 设为 1024。

  3. 3

    在移动端的 URP asset 上取消勾选 HDR 和 MSAA。基于 tile 的移动 GPU 上这两样都很贵。

  4. 4

    低端机上把 Render Scale 设成 0.8 —— 分辨率降 20% 几乎看不出来,但提速非常明显。

  5. 5

    每个画质等级各留一份 URP asset:Mobile Low、Mobile High、Desktop。

2. Texture——通常占掉你包体的一半

  1. 1

    全选所有 texture,把 Max Size 设为 1024(道具用 512,2048 只留给主角级资源)。

  2. 2

    Compression Format → Android 用 ASTC 6x6。这是现在的标准格式,同样大小下画质比 ETC2 好得多。

  3. 3

    除非你真的在代码里读像素,否则把 Read/Write Enabled 取消勾选 —— 开着它内存会翻倍。

  4. 4

    UI 的 sprite 关掉 mipmap;凡是在 3D 空间里的都保持开启。

3. Script —— 那些让你掉帧的错误

do not do this
void Update()
{
    // 1. searching the whole scene, 60 times a second
    GameObject player = GameObject.Find("Player");

    // 2. allocating a new object every frame
    Enemy[] all = FindObjectsOfType<Enemy>();

    // 3. building a string every frame — this is garbage
    label.text = "Score: " + score;

    // 4. a component lookup every frame
    GetComponent<Rigidbody>().AddForce(Vector3.up);
}
do this instead
private Transform player;
private Rigidbody rb;
private int lastScore = -1;

void Awake()
{
    player = GameObject.FindWithTag("Player").transform;   // once
    rb = GetComponent<Rigidbody>();
}

void Update()
{
    rb.AddForce(Vector3.up);

    if (score != lastScore)          // only build the string when it changed
    {
        label.text = "Score: " + score;
        lastScore = score;
    }
}
  • 手机上每隔几秒卡一下,元凶就是垃圾回收。其中几乎全部来自 Update 里的字符串和新的内存分配。

  • 不需要每帧跑的东西就交给定时器 —— 敌人 AI 改成每 0.2 秒判定一次,开销只有原来的十二分之一。

  • 空的 Update() 照样会被 engine 调用一次。删掉。

4. 识别设备,然后降档

QualityAutoSetter.cs
using UnityEngine;

public class QualityAutoSetter : MonoBehaviour
{
    void Awake()
    {
        int ram = SystemInfo.systemMemorySize;       // in MB
        int cores = SystemInfo.processorCount;

        if (ram < 3000 || cores <= 4)
        {
            QualitySettings.SetQualityLevel(0, true);          // Mobile Low
            Application.targetFrameRate = 30;
        }
        else if (ram < 6000)
        {
            QualitySettings.SetQualityLevel(1, true);          // Mobile Medium
            Application.targetFrameRate = 60;
        }
        else
        {
            QualitySettings.SetQualityLevel(2, true);          // Mobile High
            Application.targetFrameRate = 60;
        }

        Debug.Log($"Device: {SystemInfo.deviceModel}, RAM {ram}MB, quality {QualitySettings.GetQualityLevel()}");
    }
}

在真机上 profile,而不是在编辑器里

  • 编辑器跑在你桌面机的 CPU 上。它给出的数字说明不了手机上会怎样。

  • 在 Build Profiles 里勾上 Development Build 和 Autoconnect Profiler,构建到设备上,再打开 Profiler。

  • 连续玩满五分钟。由于发热降频,第五分钟会比第一分钟慢 20–30% —— 这个才是你在意的数字。