做 UE 开发的朋友应该都有体会:项目做到中后期,最让人头疼的不是功能做不完,而是“跑不动”。编辑器里看着好好的,打包出来掉帧、卡顿、发热、内存爆掉,各种稀奇古怪的问题全冒出来。有不少人把这个归结为硬件不行,其实大部分时候是性能预算没做好。Unreal Engine 开发与性能优化这个话题,我这些年踩过的坑不少,也积累了一些实打实的经验,这次就系统性地梳理一遍,聊聊优化到底该从哪里下手、每一步怎么做,以及我踩过的那些坑。
这篇文章适合谁看?正在做 UE 项目但遇到性能瓶颈的开发者,准备入行 UE 开发的新人,以及做技术管理需要把关性能的同学。我会先从性能优化的底层逻辑讲起,然后按 CPU、GPU、内存与加载、移动端与多人游戏这几个维度分别拆解,最后再分享一些常用的性能分析工具和真实排障案例。内容偏实操,不聊虚的。
1. 搞清楚瓶颈在哪:UE性能优化的底层逻辑
1.1 性能问题不是玄学,是资源与预算的博弈
我在带项目的时候,最常说的一句话就是:性能优化不是玄学,本质上是一场“资源预算”的博弈。硬件资源就那么多,你要做的就是在这有限的预算里,把画质、玩法、流畅度之间的平衡点找到。
这里有个基本概念必须先搞清楚:帧率与帧时间。大家习惯说“我们要跑 60 帧”,但 60 帧对应的是 16.6 毫秒的帧时间预算。这个 16.6ms 不是你游戏线程一个线程的时间,而是游戏线程、渲染线程、GPU 三者的总预算。换句话说,游戏线程跑 8ms,渲染线程跑 5ms,GPU 跑 6ms,这帧你就超了 2.4ms,表现出来就是掉帧。所以做优化,第一件事就是搞清楚“时间到底花在谁身上了”。
还有一个常见的认知误区:盲目追求高画质。我见过不少项目,美术把材质调到最高,特效拉满,结果全场景平均只有 20 帧,然后来找我“优化”。真正的优化是“在画质下降不明显的前提下大幅提升性能”,而不是“为了性能把所有效果全砍掉”。这两者之间的分寸感,才是优化的核心功力。
另外一个需要建立的概念是“性能只有好坏之分,没有中间态”。任何一次调整,要么有效要么无效,不能靠“感觉好像流畅了一点”。所有改动都必须量化,用数据验证,这就是为什么我后面会专门花一整个章节讲 profiling 工具的使用。先把测量体系建起来,后续的所有优化动作才有据可依。
1.2 优化工作流该怎么搭:从Profiling到验证
很多团队做性能优化特别随意:觉得哪里卡就改哪里,改完跑一下“看着还行”就完事了。这种做法在中小项目里还有一定概率蒙对,但项目一复杂,多半会越改越乱,甚至把之前正常的地方改出问题。
我建议搭一套可重复的优化工作流,本质上是一个闭环:测量→定位→改动→复测。每一步都必须记录数据。具体操作上,我会在项目里建一个性能测试地图,把典型的战斗场景、复杂场景、NPC 密集场景都放进去,每次优化前先跑一遍这地图,用 Unreal Insights 或者简单的 stat 命令记录帧时间数据。改动完再跑一遍,对比数据。
建立性能预算表也是项目启动阶段就该做的事情。预算表长什么样?我列一个简化的例子:
| 环节 | 60帧目标(ms) | 30帧目标(ms) | 说明 |
|---|---|---|---|
| 游戏线程 | ≤6 | ≤12 | AI、物理、蓝图逻辑、网络同步 |
| 渲染线程 | ≤4 | ≤8 | Draw Call提交、网格与材质状态切换 |
| GPU | ≤6 | ≤13 | 像素着色、光照、阴影、后处理 |
这样拆完之后,谁超了预算谁去优化,责任非常清楚。不要指望所有环节都压到最低,只要达标即可,因为你压耦合任何一项性能,都可能牺牲画质或功能。预算表的意义在于让你明确“够用就行”的底线,避免过度优化。
2. CPU侧性能优化:线程开销与逻辑开销专项
2.1 游戏线程瓶颈:Actor数量、Tick与蓝图性能
UE 的性能瓶颈,在 PC 平台上往往先出现在 CPU 的游戏线程。游戏线程负责的东西太多了:Actor 更新、物理模拟、AI 逻辑、蓝图执行、网络同步,全在这一个线程上跑。游戏线程一旦满了,你的 GPU 再闲也白搭。
我经常在项目里遇到的第一类问题:场景里塞了几百上千个 Actor,每个都在每秒 Tick 一次。看起来单次开销不大,但数量一上去,CPU 就扛不住了。这本质上是一个“数量×单位成本”的问题。要解决要么降数量、要么降单位成本。
降数量就走剔除路线。UE 的剔除包括距离剔除、视锥剔除、预计算可见性。但注意,剔除只对渲染有效,Actor 的 Tick 不会因为你离线了就不跑。所以更关键的是控制 Tick。实操上我总结了几个非常有效的招数:
- 能用 Timer 代替 Tick 的,坚决不用 Tick。比如一个每隔 2 秒检查一次玩家距离的机关,你用 Timer 设 2 秒循环,开销比每帧 Tick 小得多。
- Tick 频率可调。不同 Actor 的 Tick 频率完全可以错开,没必要每帧都算。比如 0.1 秒 Tick 一次对大部分 AI 决策来说绰绰有余。用 SetActorTickInterval 就能实现。
- 只让需要反应的 Actor 开启 Tick。比如玩家附近的 NPC 才 Tick,远处的直接禁用,等玩家靠近再启用来。用 Physics Volume 或者距离检测做触发就可以。
再聊蓝图性能。蓝图本身是很好的快速迭代工具,但用它写重型逻辑就得付出性能代价。对此我的态度是:少用蓝图写高频运算,这类逻辑改用 C++ 实现,蓝图只留作调用接口。比如一个每秒跑几十次的复杂数值计算,放在蓝图里哪怕只是几个节点,累加起来也会很不乐观。
还有一个老生常谈但很多新项目还在踩的坑:蓝图里的“事件 Tick”节点里直接做字符串拼接、加载资源甚至 Find Actor。这三个操作任何一个在 Tick 里跑都是灾难。Find Actor 本质上是遍历场景里的 Actor 列表,每秒跑几十次,不卡才怪。这种节点最多在初始化时用一次,日常逻辑里应该缓存引用。
从 UE4.24 左右开始,官方推进了将蓝图转换为 C++ 的 Nativization 方案,不过在 UE5 里蓝图 Nativization 逐渐淡化了。更靠谱的思路是:核心性能组件直接用 C++ 开发,蓝图负责组装和调参。这也是为什么现在招聘 UE 开发基本都要求 C++,性能这一关绕不开 C++。
2.2 渲染线程与Draw Call治理
渲染线程的职责是收集所有要渲染的信息,生成渲染命令提交给 GPU。这里最出名的概念就是 Draw Call。每次让 GPU 绘制一个物体,CPU 都要做一大堆准备工作:设置顶点缓冲、纹理绑定、着色器状态、渲染状态,等等。这些准备工作是 CPU 干的,所以 Draw Call 过高,瓶颈会在 CPU 的渲染线程上。
我见过一个项目,场景里放了上千个独立的静态网格物体,每个网格用了两三个材质。Draw Call 轻松破 2000,渲染线程每帧耗时飙到 10ms 以上,帧率直接锁死在 20 多帧。后来做了一轮合并,把相邻的静态网格合并成少数的几个大网格,Draw Call 降到了三百多,渲染线程降到 4ms 以内,帧率立刻上来了。
合并网格的方式主要有几个:
- 静态网格合并:在编辑器里选中多个 Static Mesh,右键选择 Merge Actors,可以合并成一个网格。简单粗暴,但合并后丢失了独立碰撞和可移动性,适合场景装饰物,比如碎石堆、地面杂物。
- 实例化静态网格(Instanced Static Mesh):大量重复的物体,像树木、路灯、草丛,用 HISM(Hierarchical Instanced Static Mesh)或 ISM 来做。这种方式 GPU 实例化绘制,一套网格数据传一次,能显著降低 CPU 开销。UE 的植被系统底层就是 HISM,这也是为什么同一个场景用植被刷出来的树比手动摆的 Static Mesh 性能好很多。
- 材质合批:如果两个 Mesh 用的材质不同,即使合并了网格也可能产生额外的状态切换。所以合批前先检查材质,尽量共用材质,减少 Render State 切换。
渲染线程还有一个隐藏开销是“状态切换”。GPU 编程里最忌讳的就是频繁改变渲染状态——换个贴图、调个混合模式、换套深度测试参数,每次切换对 GPU 来说都是一次流水线排空。所以材质设计上尽量做 Flatten,比如把一个物体用到的多张贴图合并到一张 Atlas 里,减少贴图绑定切换。
关于 Nanite,需要单独说一下。UE5 的 Nanite 虚拟化几何体在渲染大量高模网格时确实很惊艳,它从根本上改变了 Draw Call 的逻辑,让三角形数量不再是主要瓶颈。但 Nanite 不是万能的,它不支持透明度、不支持带某种特殊的材质属性、对移动端支持也比较有限。选型时要清醒:如果你的项目是 PC/主机端 3A 级画质,场景里有海量高模资源,Nanite 值得上;如果是移动端或者风格化项目,Nanite 不一定适合,老老实实做好 LOD 和合并可能更实际。
3. GPU侧性能优化:渲染管线的降本增效
3.1 渲染路径的选择与像素成本控制
GPU 侧的开销大头,一是顶点处理,二是像素填充,三是带宽吞吐。很多项目在 CPU 侧优化做得不错,帧率还是上不去,多半问题就出在 GPU 的像素填充率上。
先说渲染路径。UE 支持前向渲染和延迟渲染两种主流路径。延迟渲染适合动态光源很多的场景,灯光开销相对固定,但带宽消耗大,对移动端很不友好。前向渲染在像素填充上更经济,支持 MSAA 抗锯齿,但光源数量一多性能就会明显下降。项目早期就应该根据目标平台定好渲染路径,后期再换会带来巨大的工程量。
UE5.1 之后移动端开始支持 Forward+,这一代方案结合了前向的低带宽优势和集群光源的批量处理,目前中高端手机上的主流选择。这里不展开源码,只说结论:移动端优先考虑 Forward+ 或 Mobile Forward,别在移动端硬上延迟渲染。
像素填充率的核心控制手段是屏幕分辨率与输出缩放。UE 里有几个常用的控制台命令,任何时候都能用:
- r.ScreenPercentage:控制实际渲染分辨率相对于显示分辨率的百分比。降到 80 意味着实际像素量降到 64%,GPU 像素着色压力直接减少三分之一左右。
- r.DynamicRes.TargetFrameTime:动态分辨率的目标帧时间,设置了之后引擎会在帧率紧张时自动降分辨率,帧率恢复后再抬回来。
动态分辨率我实际用下来非常推荐,尤其是主机和移动端的复杂战斗场景。它的本质是“帧率优先,画质让位”,玩家在激烈战斗时注意到的更多是流畅度而不是边缘锯齿,对体验的负面影响非常小。
光影设置也直接决定像素成本。全局光照里,如果不需要动态天光变化,直接用静态光照烘焙贴图,性能远好于 Lumen。Lumen 虽然效果惊艳,但实时全局光追的代价是很大的,至少在移动端和低配 PC 上,不要轻易开 Lumen。如果用传统的级联阴影,阴影贴图分辨率不要盲目开高,根据光源覆盖范围和物体密度调节,实时阴影 + 静态光照烘焙配合,大多数项目画质与性能能达到不错的平衡。
3.2 渲染特性开销:从体积雾到抗锯齿
UE 里有太多“看着高大上、跑起来要命”的渲染特性,这里一个个说。
体积雾在 PC 上确实能营造很深邃的氛围感,但很多人不知道体积雾每一帧都在做三维纹理的迭代计算,采样次数相当惊人。如果你只是想要轻微的大气雾效果,用指数高度雾就能满足需求,成本低一个数量级。如果一定要体积雾,把体积分辨率调低,采样步长调大,至少能省一半 GPU 时间。
屏幕空间反射(SSR)也是性能大户。SSR 在屏幕上做光线步进,对反射质量要求高时计算量尤其大。我的建议是:如果场景里水面、镜面材质不多,直接关 SSR,用反射捕获器(Reflection Capture)来模拟反射效果。反射捕获本质上是一张静态环境贴图,开销几乎可以忽略,打光合理的话观感差距不会太大。
抗锯齿方面,MSAA 抗锯齿效果好但开销大,尤其延迟渲染路径下基本用不了。TAA 是 UE 的默认选择,性能表现均衡。但如果你的项目是快速运动的动作游戏或者 FPS,TAA 在高速运动下会有明显拖影,这时候可以考虑 DLSS 或者 FSR。需要特别注意的是,这些都是基于时间帧合成的方案,对静态画面的确很友好,但一旦镜头动起来,如果上一帧数据有缺陷,拖影和闪烁就会被放大。调参时,要在低速镜头和高速镜头下都测试一遍。
还有一个很容易忽视的 GPU 开销:Overdraw。这是像素被多次重复填充导致的浪费,尤其在使用半透明材质时,每个半透明物体都要被渲染一遍并且混合,重叠起来成本成倍增长。粒子和特效系统是 Overdraw 的重灾区。控制粒子数量、缩小粒子尺寸、减少半透明层叠,是移动端特效优化最重要的手段之一。我以前优化过一个技能特效,只在特效蓝图中把粒子数量从 1000 粒降到 300 粒、粒子大小缩小 20%,GPU 时间就降了差不多 2ms,画面观感几乎没有变化。
4. 内存、加载与资源管理优化
4.1 资源粒度与纹理内存
如果说帧率问题是“看得见的卡顿”,那内存超限就是“看不见的炸弹”。移动端和 PC 32 位程序上,内存用超了就直接闪退。我经手过的项目里,因为内存管理不当导致的闪退绝对排在 Bug 榜前三。
先说纹理内存。一张 2048×2048 的 RGBA 纹理在 GPU 上占的内存是 2048×2048×4 字节,即 16MB。一个项目里如果有 50 张这样的纹理,光贴图就吃 800MB。99% 的美术资源都不需要用到 2048 甚至 4096。我做项目时的资源规范很明确:场景大物体用 1024 或 2048,中小型物体用 512 或 1024,UI 特殊需求才允许 2048 往上。另外一定要开 Mipmap,Mipmap 能让远处物体自动使用低分辨率贴图,既降显存占用又提高渲染速度,一举两得。
纹理压缩格式也很关键。PC 上用 BC7 或 BC3,移动端 iOS 用 ASTC,Android 基本也是 ASTC 为主。ASTC 在相同文件大小下画质要比 ETC2 好一截,支持 4x4、6x6、8x8 等不同分块,分块越大压缩率越高画质越差,可以根据纹理类型灵活选择。后端美术和程序在新项目最开始就要把这个压缩规则定好,否则等几百张美术图做完再批量处理,效果很难保证。
然后是网格和 LOD。UE 支持自动生成 LOD,可以根据距离切换不同精度的模型。很多团队偷懒不上 LOD,我就见过一个机械模型面数 8 万多面,在场景里摆了几十处,结果每帧光顶点处理就占掉不少 GPU 时间。后来用自动 LOD 生成,在 500 距离之外直接切到 2000 面左右的 LOD,画面看不出差别,GPU 顶点处理时间明显下降。LOD 策略没有标准答案,一般在保证观感的前提下尽量激进。
音频和动画资源也占内存,但经常被忽略。音频建议统一用压缩格式,不要直接拉 WAV 进项目。动画序列能使用动画蓝图和动画重定向的情况下,尽量共用资源,别每个角色都导入一套完整动画。
4.2 加载时间与流送优化
加载慢这个问题,在客户端游戏里几乎等同于劝退。尤其现在移动端玩家耐心都很有限,启动超过 10 秒基本就會流失。UE 里加载时间的主要来源是资源同步加载和关卡全量加载。
先说启动加载。默认情况下,UE 在进入一个 Map 时会加载这个 Map 里所有引用的资源。如果主关卡里的所有艺术场景都直接放在同一个 Level 里,启动时间必然爆炸。正确做法是拆 Level Streaming。把场景拆成多个子关卡,主关卡只保留必要的框架,玩家接近某个区域时再异步流送加载对应的子关卡。UE 里基于距离的 Level Streaming 已经相当成熟,配置好 Streaming Distance 就行。
异步加载也是降卡顿的关键。同步加载意味着加载期间游戏线程被锁死,画面直接卡住。用 FStreamableManager 或异步加载节点,让资源在后台加载,完成后通过回调通知逻辑使用。这里要提醒的是,异步加载需要配合软引用(Soft Object Reference),硬引用(Hard Reference)会在启动时无条件加载。很多人加载卡顿,就是因为蓝图里拖了一个硬引用。
资源加载还有一个隐藏坑:资源依赖链。你加载一个红绿灯模型,它引用了某个材质,那个材质又引用了某个贴图,这一整条依赖链都会加载。所以控制依赖深度很重要,比如不要把全局通用的 Master Material 设置成“仅节省节点而互相引用太多”。可以用 Asset Audit 工具检查每个资源的内存占用和依赖关系,定期清理无引用资源。
5. 移动端与多人联机专项优化
5.1 移动端特性与功耗
移动端和 PC 端最根本的区别,在于带宽和功耗。移动 GPU 是 Tile-based 架构,渲染时先把几何体光栅化到一小块片元缓存里,完成后才写进主内存。这种架构下的瓶颈往往不是像素填充率而是带宽,过量的 Overdraw 和全屏后处理输出,在手机上消耗的带宽尤其致命。
很多人会问,为什么同一台手机,跑个普通游戏 60 帧稳稳的,跑 UE 的 Demo 就发热、掉帧、亮度变低?原因很简单:功耗墙。手机 SoC 在温度升高时会自动降频保护,所以即使你的游戏平均 GPU 负载不高,只要短时间冲到功耗墙,也会被强制降频。这也是为什么移动端优化要特别关注峰值而不是平均值。
移动端项目设置的几个点,我觉得任何项目启动前都应该确认:
- r.Mobile.ShadingPath:移动端渲染路径明确选好,前面说过优先 Forward。
- 分辨率和屏幕百分比:很多手机屏幕分辨率接近 2K,实际游戏根本不需要渲染那么高,把渲染分辨率降到 70% 左右,观感影响很小,性能大幅提升。
- 关闭或降低全屏特效:Bloom 的强度、Motion Blur 在移动端能关就关,这些后处理在移动带宽下非常昂贵。
- 热能管理:iOS 的 Metal 能查询 GPU 温度,Android 也出现了类似的 Thermal API。有条件的话,在温度升高时主动降分辨率或降帧率,好过被系统强制降频。
移动端还有个基础格式问题:纹理格式统一用 ASTC,音频格式 M4A 或 OGG,网格资源严格控制三角面数量。移动端单屏顶点数建议控制在 50 万以下,再高就算 GPU 顶点处理能顶住,带宽也未必吃得消。
5.2 多人游戏的网络与同步优化
多人联机项目的性能问题往往在“逻辑与网络”这一层。服务器跑的是权威逻辑,客户端要把所有玩家的状态同步下来。如果同步机制设计得粗糙,带宽和 CPU 就会被大量浪费。
最典型的优化点:属性同步频率和相关性。UE 的网络同步基于属性复制,你在 Actor 的 Replicated 属性上加一个 bReplicates,引擎就会在属性变化时同步给客户端。但并不是所有属性都需要高频率同步。比如玩家的生命值、弹药数,可以接受低频率或事件驱动同步;而角色的位置、朝向,如果需要平滑移动,才需要高频同步。
很多时候网络卡顿的根源是服务器帧率太低。UE 服务器默认帧率由 NetTickRate 控制,如果服务器帧率只有 15Hz,那不管客户端性能多好,整体体验也只有 15Hz 的手感。多人游戏的上手第一步就是确认服务器心跳频率。
RPC(远程过程调用)也要克制使用。每次 RPC 都要经过序列化和网络传输,密集的 RPC 会瞬间打满带宽。我见过一个射击项目的伤害处理,命中后同时发三个 RPC:伤害事件、特效事件、音效事件。其实完全可以合并成一个 RPC,带上类型参数,由接收端分支处理。RPC 合并能直接减少一半以上的网络包。
带宽预算的概念在多人项目里应该建立起来。假设你有 20 个玩家,每秒钟同步位置信息,每个位置用 3 个 float(12 字节)再加包头,光位置同步就是 20×12×30=7200 字节每秒。看着不多,但加上各种事件、动画状态、AI 信息,很快就能触顶。可以利用 UE 里的网络分析工具(Network Profiler)看哪些 Actor 占用了大量带宽,按图索骥去精简。
6. 性能分析工具与典型问题排查实录
6.1 自带工具怎么用:Stat命令与Unreal Insights
工具链是性能优化的基础设施,不会用工具就谈优化,等于闭眼开车。UE 自带的工具链相当齐全,关键是你要会用。
先说控制台命令,这是最快的定位手段。游戏运行时按 ~ 打开控制台,输入以下命令:
- stat unit:显示游戏线程、渲染线程、GPU 三者的帧时间,这是最基础的第一诊断命令。
- stat gpu:显示 GPU 各个渲染阶段的耗时明细,能直接看到是不是某个渲染特性吃掉了大量时间。
- stat scenerendering:查看 Draw Call 数、网格体绘制次数、三角形数量等。
- stat streaming:查看资源流送状态,有没有资源一直在加载。
我遇到一个项目帧率波动严重,就是用 stat unit 发现游戏线程稳定 5ms,但 GPU 时间在某些视角下从 6ms 飙到 15ms,再输入 stat gpu 后定位到是阴影渲染(Shadow Depths)在复杂洞穴场景里开销剧增。后来把级联阴影的数量和阴影贴图分辨率做了两级调整,GPU 时间稳定在了 8ms 以内。
Unreal Insights 是更全面的分析工具,它记录引擎各个模块的耗时并生成时间线,可以看到帧内所有线程的完整活动轨迹。有一次我们排查一个 3 秒一次的卡顿,用 stat unit 看不出规律,Unreal Insights 时间线里发现是某个异步加载任务每 3 秒触发一次,加载的还是一个几十兆的大资源,没做软引用管理。换成分块加载后,卡顿点彻底消失。这种偶发卡顿如果没有深入 profiling,光靠肉眼真的很难定位。
如果是渲染线程侧的深度分析,RenderDoc 和 PIX 这类图形调试器也要会用。RenderDoc 能抓取单帧渲染,看到每一个 Draw Call 的输入输出,非常有利于分析 Overdraw 和贴图绑定问题。PIX 是 DX12 平台的利器,针对 Windows PC 项目很值得掌握。
6.2 避坑指南:我踩过的性能大坑
最后分享几个实打实踩过的坑,希望你能绕开。
第一,不要小看 UI 的开销。我们有个项目战斗界面动态显示大量伤害数字,每帧在 UMG 里更新文本。UI 的 Slate 和 UMG 在更新文本时会重建布局,高频率更新非常费 CPU。后来把所有高频变化的伤害数字改成了材质方案,用一个 Texture2D 渲染数字并以材质方式绘制,CPU 开销降了一大截。UI 能不用 UMG 跑高频动效,就别用。
第二,小心蓝图里的“隐形重复调用”。比如在 Actor 的 BeginPlay 里调用了某个获取玩家 Pawn 的函数,但是在一个自定义事件里也用,甚至在 Tick 里微调时时不时调用。每次 FindPawn 都是遍历。我的习惯是:所有频繁使用的对象引用,在初始化时缓存到变量里,后续只用变量访问,绝不在执行频率高的地方做查询操作。
第三,不要盲目堆特效,哪怕它们很帅。GPU 粒子系统在场景多个特效叠加时,Overdraw 可以瞬间打满移动端带宽。特效兑现给美术时应该设排队预算:同屏最多几个全屏特效、粒子发射总量多少、单粒子最大尺寸多少。这不是限制创意,而是保证游戏真正可玩。
第四,烘焙光照时不要忽略 Lightmap 分辨率。分辨率太低阴影是糊的,太高又吃显存。这里没有统一标准,我的经验是:一个 100×100 米的操场区域,Lightmap 分辨率从 64 起步,通过连续测试找到观感与内存的折中。Lightmass 设置里的静态光照级别(GI 质量)从 Preview 保鲜开始调,不要在项目初期就最高质量烘焙,迭代速度太慢了。
7. 建立你自己的性能优化检查清单
玩过这么多项目,我越来越觉得性能优化最难的其实是“坚持”。因为性能问题不像功能 Bug 那样直接摆在桌面上,它藏在一次掉帧、一次发热、一次加载变慢里,需要长期维护和关注。我自己会在每个项目里做一份性能检查清单,每次版本提交前都过一遍,这里分享给你:
- [ ] stat unit 数据是否在目标范围内?有无明显尖峰?
- [ ] Draw Call 是否超标?场景里有没有忘记合并的零散网格?
- [ ] 是否还有高频 Tick?Tick 里有没有做了查询、加载类操作?
- [ ] 纹理资源内存是否在预算内?压缩格式是否正确?
- [ ] 关卡是否做了 Streaming?进入新区域时是否会出现同步加载卡顿?
- [ ] 特效粒子数量是否在预算内?有没有半透明过度叠加?
- [ ] 移动端项目:分辨率缩放是否合理?是否过热降频?
这份清单可以根据你的项目类型做增减,但核心逻辑是一样的:把性能优化变成流程的一部分,而不是最后一刻的救火。
我个人的体会是,性能优化与功能开发其实是相伴而行的。每写一个新功能,都应该顺手问一句“这个功能每帧要跑多少次?会不会成为热点?”。把这种思维变成习惯,你的项目就不会走到“画质很美但玩不了”的绝路上。也希望这篇文字能让你少走一些弯路,在实际项目里跑得更稳。