3. 物理引擎调优:理解PhysX核心参数,平衡精度与性能
物理引擎是仿真世界的「重力法则」。你场景里每一个物体的下落、碰撞、堆叠,都靠它算。但算得越精细,CPU就越累。我见过不少团队,场景里就几百个箱子,仿真却卡得像幻灯片——问题往往出在PhysX参数上。
今天我们就来拆解几个核心参数。搞懂了它们,你就能在精度和性能之间找到那个「甜点」。
3.1 子步数(Substep Count)——时间切得越细,碰撞越准
先问个问题:为什么高速运动的物体会「穿模」?
因为物理引擎不是连续计算时间的。它把1秒切成若干帧,每帧只算一次。如果一个薄板在1帧内从球左边穿到了右边,引擎根本不知道它们曾经重叠过——这就是「隧道效应」。
子步数就是解决这个问题的。它把每一帧再切成更小的步长,在每个子步里都做一次碰撞检测。
| 子步数 | 每帧计算次数 | 碰撞精度 | CPU开销 |
|---|---|---|---|
| 1(默认) | 1次 | 低,易穿模 | 最低 |
| 2 | 2次 | 中等 | 约2倍 |
| 4 | 4次 | 高 | 约4倍 |
| 8 | 8次 | 极高 | 约8倍 |
3.2 碰撞检测模式——选对了,省一半算力
PhysX提供了几种碰撞检测模式。说白了,就是「用什么形状去算碰撞」。
- Primitive(基本体):用球体、立方体、胶囊体代替复杂模型。最快,但精度最低。
- Convex Hull(凸包):用物体外轮廓的凸包。精度中等,性能也不错。
- Triangle Mesh(三角网格):直接用模型的三角面。最精确,但最慢。
- Height Field(高度场):专门用于地形。效率高,适合地面。
我建议你遵循一个原则:能用基本体就别用凸包,能用凸包就别用三角网格。
避坑指南:我曾经接手一个项目,场景里所有物体都用了三角网格碰撞。结果仿真帧率只有5 FPS。后来我把静态物体(墙壁、地面)换成基本体,动态物体(箱子、零件)换成凸包,帧率直接飙到30 FPS。精度损失?肉眼几乎看不出来。
3.3 刚体睡眠阈值——让不动的物体「睡过去」
场景里总有些物体是静止的——比如地上的箱子、桌上的零件。如果引擎每帧都去算它们的碰撞,那就是白费力气。
刚体睡眠机制就是干这个的。当一个物体的速度和角速度低于某个阈值,且持续一段时间,PhysX就会把它标记为「睡眠」状态,不再参与物理计算。
两个关键参数:
- Linear Sleep Threshold:线速度阈值,默认0.001 m/s
- Angular Sleep Threshold:角速度阈值,默认0.001 rad/s
你可以适当调高这两个值。比如在物流仿真场景里,我习惯设到0.01。这样箱子一停下来就立刻「睡着」,CPU负担明显下降。
3.4 求解器迭代次数——收敛速度的开关
当多个物体堆叠在一起时(比如一摞箱子),PhysX需要反复计算它们之间的接触力,直到所有力达到平衡。这个计算过程叫「求解」。
求解器迭代次数决定了每次求解时,引擎最多算多少轮。迭代越多,堆叠越稳定,但CPU开销也越大。
| 迭代次数 | 堆叠稳定性 | 性能影响 |
|---|---|---|
| 4(默认) | 一般,小堆叠还行 | 低 |
| 8 | 良好,适合中等堆叠 | 中等 |
| 16 | 优秀,适合高堆叠 | 高 |
| 32 | 极高,几乎不抖动 | 极高 |
我个人习惯:如果场景里堆叠不超过5层,用4次就够了。超过10层,我会提到8次。再往上?说实话,16次和32次的差别,肉眼很难分辨,但CPU已经快冒烟了。
3.5 核心参数调优流程图
下面这张图总结了调优的核心逻辑。你可以把它贴在工位上。
3.6 实战:一个典型的调优案例
假设你要仿真一个仓库场景:AGV小车搬运箱子,箱子堆叠6层,AGV速度2m/s。
我的调优步骤:
- 子步数:AGV速度不算快,2m/s。子步数设为2,防止偶尔穿模。
- 碰撞模式:箱子用凸包,地面和墙壁用基本体。
- 迭代次数:堆叠6层,超过5层了。设到8。
- 睡眠阈值:设到0.005,让静止的箱子尽快睡眠。
跑一轮测试。如果FPS低于30,我会先降迭代次数到4,看看堆叠是否稳定。如果还卡,再降子步数到1——但这时候要留意AGV会不会穿模。
核心原则:精度够用就行,别追求完美。仿真不是电影特效,工业场景里,95%的精度 + 30 FPS,远比99%的精度 + 5 FPS更有价值。
3.7 常见误区总结
- 误区一:所有物体都用三角网格碰撞。→ 其实90%的场景用凸包就够了。
- 误区二:子步数越高越好。→ 子步数翻倍,CPU开销也翻倍。够用就行。
- 误区三:迭代次数设到32,堆叠纹丝不动。→ 但你的仿真已经卡成PPT了。先试试8。
- 误区四:睡眠阈值设到0.1,所有物体秒睡。→ 然后你发现箱子还在半空中就睡着了,直接悬停。
嗯,调优这件事,说白了就是「试错」。我每次调完参数,都会跑一个5分钟的测试场景,盯着FPS和碰撞效果看。别指望一次调对——物理引擎的参数之间会互相影响,慢慢来,找到那个平衡点。