🎬 开场:一个"逻辑没多少却卡爆 CPU"的谜团
小王的游戏逻辑很简单,可 Profiler 一看 CPU——Physics 和 Animation 两块红得发紫!
“我游戏逻辑就那么点,怎么 CPU 全耗在物理和动画上了?
一堆刚体、一堆碰撞、几十个动画角色……
这两块到底怎么优化?有哪些坑?”老鸟说:“物理和动画是 CPU 优化的两座大山!
物理靠’碰撞检测、刚体模拟’吃 CPU,
动画靠’骨骼计算、曲线采样’吃 CPU,
它俩优化得好,CPU 能省一大截!今天把这两块掰开讲透!”
第一部分:物理优化 🏀
🤔 第一幕:物理为什么吃 CPU
物理引擎在忙什么
物理引擎每帧要做: ① 碰撞检测:谁和谁撞了? ② 刚体模拟:算速度、受力、位置 ③ 约束求解:关节、堆叠等 ↓ 物体越多、碰撞越复杂 → 计算量爆炸增长!碰撞检测的开销核心
碰撞检测 = 物理开销大头: N个物体两两检测 → 接近N²增长! 100个物体 → 可能上千次检测 ↓ 所以物理优化核心之一: 减少碰撞检测的量和复杂度!生动理解物理开销
物理模拟像"裁判盯着一群人防碰撞": 场上人越多(物体多) 裁判越要拼命盯"谁会撞谁"(碰撞检测) 还要算"撞了怎么弹开"(刚体模拟) ↓ 人一多,裁判累到崩溃(CPU爆)!📐 第二幕:物理优化核心手段⭐
手段1:优化碰撞体形状
碰撞体复杂度(从便宜到贵): Sphere(球) < Capsule(胶囊) < Box(盒) <<< Mesh Collider(网格)! ↓ ✅ 优化: - 尽量用简单碰撞体(球/胶囊/盒) - 避免Mesh Collider(超贵!) - 用几个简单碰撞体拼,别用网格碰撞手段2:Mesh Collider 用凸包
必须用Mesh Collider时: ✅ 勾选"Convex"(凸包) → 简化成凸多面体,便宜很多 ↓ ⚠️ 非凸(Concave)网格碰撞超贵 且不能做动态刚体!手段3:用好碰撞矩阵(Layer)⭐
Layer Collision Matrix(层碰撞矩阵): 设置哪些层之间"需要检测碰撞" ↓ ✅ 关闭不需要的层之间的碰撞: - 子弹层 vs 子弹层 → 关(子弹不互撞) - 特效层 vs 任何层 → 关 ↓ Edit > Project Settings > Physics → 取消勾选不需要的交叉! ↓ 大幅减少无谓的碰撞检测!手段4:静态物体标记正确
✅ 不动的碰撞体: - 不要加Rigidbody(保持静态) - 静态碰撞体物理引擎有优化 ↓ ⚠️ 千万别给静态碰撞体的 Transform频繁移动! → 会导致物理引擎重建,超贵!生动理解物理优化
物理优化像"给裁判减负": ① 简单碰撞体 → 让裁判判简单形状(快) ② 层矩阵 → 告诉裁判"这些人不用管" ③ 静态标记 → "这些人不动,别老盯着" ↓ 裁判轻松 → CPU省!🔬 第三幕:物理的高级优化
优化1:降低 Fixed Timestep
物理在FixedUpdate运行,固定频率: 默认Fixed Timestep = 0.02(每秒50次) ↓ ✅ 如果物理精度要求不高: 调大到0.03~0.04(每秒25~33次) → 物理计算次数减少! ↓ ⚠️ 别太大,否则物理不稳定/穿透 Edit > Project Settings > Time优化2:Rigidbody 休眠
Rigidbody静止后会自动"休眠(Sleep)": → 休眠的刚体不参与模拟(省CPU) ↓ ✅ 别做打断休眠的事: - 别每帧对静止刚体施加微力 - Sleep Threshold可调 ↓ 让静止物体好好睡觉!优化3:减少物理查询
物理查询(Raycast/OverlapSphere等)也耗CPU: ✅ 优化: - 别每帧大量Raycast - 用LayerMask限定检测层(减少检测量) - 降低查询频率(不用每帧查) - RaycastNonAlloc避免GC// ✅ 用LayerMask + NonAllocRaycastHit[]results=newRaycastHit[10];intcount=Physics.RaycastNonAlloc(ray,results,maxDist,layerMask);// ↑ 限定层 + 不产生GC优化4:碰撞事件按需用
⚠️ OnCollisionStay/OnTriggerStay每帧调用! 物体多时开销大 ↓ ✅ 优先用Enter/Exit Stay能不用就不用生动理解高级优化
高级优化像"进一步精简裁判工作": ① 降低判罚频率(Fixed Timestep) ② 让不动的人休息(休眠) ③ 少发起主动检查(少Raycast) ④ 少用持续性监控(少Stay) ↓ 裁判工作量再降一档!第二部分:动画优化 🎭
🤔 第四幕:动画为什么吃 CPU
动画在忙什么
动画每帧要做: ① 采样动画曲线(算每根骨骼的位置/旋转) ② 混合多个动画(Blend) ③ 更新骨骼矩阵 ④ 蒙皮计算(骨骼影响顶点) ↓ 骨骼越多、角色越多 → 计算量越大!Animator 的隐藏开销
⚠️ Animator(Mecanim)比较重: - 状态机评估 - 即使角色没动,也在跑评估! ↓ 大量角色用Animator → CPU吃紧生动理解动画开销
动画像"提线木偶师操控木偶": 每个木偶(角色)有很多线(骨骼) 木偶师每帧要拉动所有线(采样) 还要平滑过渡动作(混合) ↓ 木偶越多、线越多 → 木偶师累爆(CPU)!📐 第五幕:动画优化核心手段⭐
手段1:剔除看不见的动画⭐
✅ Animator的Culling Mode: 设为"Cull Completely"或 "Cull Update Transforms" ↓ 角色不可见时: → 不更新动画(省CPU!) ↓ 在Animator组件设置Culling Mode!Culling Mode选项: - Always Animate: 总是更新(最贵) - Cull Update Transforms: 不可见时不更新Transform - Cull Completely: 不可见时完全停止(最省)手段2:降低动画更新频率(LOD)
✅ Animator LOD / 远处降频: 远处的角色: → 降低动画更新频率 → 或用更简单的动画 ↓ 远处角色动画糙点没人看得出!手段3:减少骨骼数量
✅ 角色骨骼优化: - 远处/次要角色用少骨骼模型 - Quality Settings的Blend Weights (每顶点受几根骨骼影响)调低 ↓ 骨骼少 → 计算少!手段4:大量角色用 GPU 方案
✅ 超大量角色(人群): - 用GPU Instancing + 顶点动画(VAT) - 把动画烘焙到纹理,GPU播放 → 绕开CPU的骨骼计算! ↓ 万人同屏的方案!生动理解动画优化
动画优化像"给木偶师减负": ① 看不见的木偶不操控(剔除)⭐ ② 远处木偶随便动动(降频/LOD) ③ 减少每个木偶的线(减骨骼) ④ 大量木偶改用机器批量(GPU) ↓ 木偶师轻松 → CPU省!🔬 第六幕:动画的进阶优化
优化1:Optimize Game Objects
✅ 模型导入设置: Rig > Optimize Game Objects ↓ 把骨骼Transform层级"优化掉" → 减少Transform开销 ↓ ⚠️ 优化后骨骼不在Hierarchy 要访问特定骨骼需"Extra Transforms"暴露优化2:Animator vs 简单动画
⚠️ 简单动画别用重量级Animator: 简单的开关门、UI动画: → 用Animation组件(轻) 或DOTween等补间(更轻) 或直接代码控制 ↓ Animator适合复杂状态机 简单动画杀鸡别用牛刀!优化3:避免每帧改 Animator 参数
// ❌ 坏:每帧设置(即使没变)voidUpdate(){animator.SetFloat("Speed",speed);// 每帧!}// ✅ 好:变了才设置voidUpdate(){if(speed!=lastSpeed){animator.SetFloat("Speed",speed);lastSpeed=speed;}}⚠️ 用Hash代替字符串参数名: int speedHash = Animator.StringToHash("Speed"); animator.SetFloat(speedHash, speed); → 避免字符串查找开销优化4:控制 Animator 数量
✅ 场景里的Animator: - 不需要的角色禁用Animator - 用对象池管理(复用) - 远处/静止的可禁用 ↓ Animator数量直接影响CPU!生动理解进阶优化
进阶优化像"精细化管理木偶师": ① 简化木偶结构(Optimize GameObjects) ② 简单动作别请大师(别滥用Animator) ③ 没变化别瞎指挥(参数按需设+Hash) ④ 控制木偶数量(管理Animator) ↓ 方方面面省CPU!📊 第七幕:物理与动画优化对照总结
物理优化清单
✅ 物理优化: □ 用简单碰撞体(球/胶囊/盒) □ 避免Mesh Collider(用就勾Convex) □ 配置Layer碰撞矩阵(关无用碰撞)⭐ □ 静态物体不加Rigidbody □ 别移动静态碰撞体 □ 调整Fixed Timestep □ 利用Rigidbody休眠 □ 减少Raycast+用LayerMask+NonAlloc □ 少用OnCollisionStay/TriggerStay动画优化清单
✅ 动画优化: □ 设置Culling Mode剔除不可见⭐ □ 远处角色动画降频/LOD □ 减少骨骼数量 □ 大量角色用GPU方案(VAT) □ Optimize Game Objects □ 简单动画别用Animator □ 参数按需设置+用Hash □ 控制Animator数量🔍 第八幕:如何定位物理/动画瓶颈
用 Profiler 定位
✅ Unity Profiler: - Physics模块: 看物理开销 - 找Physics.Processing等耗时 - CPU模块看Animators.Update耗时 ↓ 看清是物理还是动画的锅!关键指标
物理: 看Physics.Simulate、碰撞检测耗时 看物理查询(Raycast)数量 动画: 看Animator.Update耗时 看有多少Animator在跑 ↓ 定位到具体开销源!✅ 物理与动画优化检查清单
物理理解: □ 明白物理靠碰撞检测+刚体模拟吃CPU? □ 明白物体越多碰撞越贵(接近N²)? 物理优化: □ 会用简单碰撞体? □ 会配置Layer碰撞矩阵?⭐ □ 会调Fixed Timestep? □ 会优化Raycast(LayerMask+NonAlloc)? 动画理解: □ 明白动画靠骨骼采样+混合吃CPU? □ 明白Animator即使不动也有开销? 动画优化: □ 会设Culling Mode剔除不可见?⭐ □ 会远处降频/LOD? □ 知道大量角色用GPU方案? □ 会参数按需设置+用Hash? 定位: □ 会用Profiler分辨物理/动画瓶颈?🎬 一句话总结
CPU 优化之物理与动画:
【物理】靠"碰撞检测 + 刚体模拟"吃 CPU,物体越多碰撞越贵(接近 N² 增长)。
核心优化:用简单碰撞体(球/胶囊/盒,别用 Mesh Collider,用就勾 Convex)、
配置 Layer 碰撞矩阵关掉无用的层间碰撞(最有效!)、静态物体别加 Rigidbody 也别移动、
调大 Fixed Timestep、利用刚体休眠、Raycast 用 LayerMask + NonAlloc 且别每帧狂射、少用 Stay 类回调。【动画】靠"骨骼采样 + 动画混合 + 蒙皮"吃 CPU,Animator 即使角色没动也在跑状态机评估。
核心优化:设置 Culling Mode 剔除看不见的动画(最有效!)、远处角色降频/LOD、减少骨骼数量、
大量角色(人群)用 GPU Instancing + 顶点动画(VAT)绕开 CPU、Optimize Game Objects、
简单动画别用重量级 Animator、参数按需设置且用 Hash 代替字符串、控制 Animator 数量。定位:用 Profiler 的 Physics 模块和 Animator.Update 分辨到底是哪块的锅,针对性优化!
核心口诀:物理靠碰撞模拟吃CPU用简单碰撞体+层矩阵+静态标记+降频,动画靠骨骼采样吃CPU用Culling剔除+远处降频+GPU方案+参数按需设,Profiler定位对症下药!
💡 物理与动画优化速查表
| 领域 | 核心优化 | 关键点 |
|---|---|---|
| 物理-碰撞体 | 用简单形状 | 避免Mesh Collider |
| 物理-层矩阵 | 关无用碰撞⭐ | Physics Settings |
| 物理-静态 | 不加Rigidbody | 别移动静态碰撞 |
| 物理-频率 | 调Fixed Timestep | 别太大 |
| 物理-查询 | LayerMask+NonAlloc | 别每帧狂射 |
| 动画-剔除 | Culling Mode⭐ | 不可见不更新 |
| 动画-LOD | 远处降频 | 骨骼数量减 |
| 动画-大量 | GPU方案(VAT) | 绕开CPU |
| 动画-参数 | 按需设+Hash | 别每帧设 |
💡 一句话记住核心:
物理——简单碰撞体 + Layer 矩阵关无用碰撞 + 静态别动 + Raycast 省着用。
动画——Culling 剔除不可见 + 远处降频 LOD + 大量角色用 GPU + 参数按需设。
两大 CPU 杀手,Profiler 定位后对症下药!
🔮 延伸:CPU 优化的全景
【物理与动画只是CPU优化的两块】 CPU优化的完整战场: ① 脚本逻辑: - 避免Update里重活 - 缓存组件引用 - 减少GC(字符串/装箱) ② 物理: ← 本篇 碰撞体/层矩阵/查询优化 ③ 动画: ← 本篇 剔除/LOD/GPU方案 ④ 渲染相关的CPU开销: - DrawCall/批处理 - 剔除(Culling) ⑤ GC与内存: - 减少堆分配 - 对象池 ↓ CPU优化 = 全方位减少每帧的计算量! 核心思想: "不做无用功、能省则省、能缓存则缓存"