搞物理模拟最让人头疼的,就是“动力学参数设置”这几个字。看起来只是填几个数字,但稍有不对,物体会像被风吹跑一样乱飘,或者落地之后原地抖个不停,严重的直接穿模穿到地心去。我在这个坑里反复摔了几年,现在基本扫一眼现象就能猜到是哪个参数在捣乱。这篇文章就把我积累的经验整理出来,按“底层逻辑—基础参数—接触参数—阻尼与求解—关节约束—实战排查”的顺序讲透,对于调参总是调不明白,或者刚接触物理引擎还不清楚各参数之间内在联系的开发者,应该能省下大量瞎试的时间。
1. 动力学参数设置的核心思路与底层逻辑
很多新手拿到物理引擎的第一反应是:质量给个 1,摩擦给个 0.5,弹性给个 0,然后跑一下——结果发现跟想象完全不一样。其实这不是引擎的问题,是我们没搞懂动力学参数到底是干什么用的。
1.1 动力学参数到底解决什么问题
先理解一个核心事实:现代物理引擎在实时模拟时,并不是真的在精确解物理方程,而是在每个时间步里做一次“近似求解”。动力学参数,本质上就是喂给这个求解器的边界条件。
- 稳定性:迭代不收敛、抖动、爆炸,都和参数给得不合理有关。
- 真实感:参数决定了物体看起来“重不重”“滑不滑”“弹不弹”。
- 性能:某些参数(比如迭代次数、接触块大小)直接决定了物理计算的开销。
拿一个掉在地上的球来说。如果质量特别大,碰撞时的冲量就大,约束求解器需要更多迭代才能稳住;如果物体的恢复系数很高,速度在碰撞后几乎不损失,多次弹跳后依旧剩下不少动能,看起来就很“假”。所以动力学参数不是在“设置物体的属性”,而是在“告诉求解器该怎么处理物体之间的关系”。
1.2 参数之间的耦合关系
动力学参数最容易被忽视的,是它们之间高度耦合。单独把某个参数调到“自认为合理”,其他参数不配合,最后结果依然崩。
举个例子:摩擦系数和恢复系数不是独立的。一个恢复系数为 0 的物体撞到地面,法向速度变成 0,这时摩擦才会显著起效。但如果你把恢复系数调到 0.8,物体撞地后还会往上弹,计算摩擦的时间变短,实际滑动的距离反而变长了。
阻尼也和重力加速度耦合。如果你的场景里重力加速度调的比默认值大,线性阻尼不跟着提高,物体会出现一种“又重又飘”的违和感——下落很快,但速度一进来就被阻尼吃掉一大块,停得突兀。
所以真正靠谱的调参方法,不是“哪个参数不对就调哪个”,而是先搞清楚现象背后涉及哪几个参数,再一起调。后面我会专门讲这套排查思路。
2. 刚体基础参数:质量、密度、质心与睡眠参数
刚体参数是整个动力学的基石。很多看起来复杂的异常行为,追到根上就是一个刚体参数设置错了。
2.1 质量与密度:优先用密度而不是直接给质量
在大多数物理引擎里,你可以直接指定质量,也可以指定密度让引擎根据体积计算质量。我强烈建议用密度,除非有特殊需求。
为什么?因为质量是一个“标量”,它不携带形状信息。同一个质量,分布在一个大木箱上和分布在一个小铁球上,物理行为完全不同。用密度的话,引擎会根据碰撞体的体积自动计算质量,这不仅更真实,也能避免你手工为每个物体填质量时遗漏或填错。
举个例子:一个半径 1 米、密度为 1 的球体,体积大约是 4.19 立方米,质量就是 4.19。同样一个球,密度调到 7.8,质量就是 32.6 左右——大约 7.8 倍。这个差距直接决定它撞到别人时谁被推得更远。所以在做一辆车、一个角色、一堆杂物的时候,先想想它们的真实材质密度大概是多少,再设置参数。
直接给质量的场景也有,但在用的时候要额外小心:因为引擎求解约束时依赖质量比来计算冲量分配,如果你把两三个物体的质量都设成 1,比例完全一样,就会出现“大箱子推不动小石头”的搞笑物理效果。
2.2 质心偏移不能忽略
比质量更容易被忽略的是质心位置。很多引擎允许你手动设置质心的局部坐标,默认情况下它会取碰撞体的几何中心。但这只在物体密度均匀时才成立。
实际项目中,我见过一个“翻车幽灵”案例:一辆小车,车身模型没问题,但碰撞体是把几个长方体简单拼出来的,质心被默认算在了整个组合体的中心,而实际电池、引擎、乘客的重量都在偏后偏下的位置。结果车在刹车时后轴总是抬起来,转弯时侧翻概率大增。这不是物理引擎的问题,是质心没调对。
排查方法也很直接:给物体一个初始角速度,看它是否绕着你期望的轴稳定旋转。如果旋转轴在漂移,或者静止时物体明显倾斜,十有八九就是质心位置不合理。
2.3 睡眠参数:性能与稳定的隐形开关
刚体的睡眠参数(sleep threshold)平时很少人关注,但它直接影响性能和稳定性。所谓睡眠,就是物体速度和角速度低于某个阈值持续一段时间后,引擎判定它“睡着了”,不再参与物理求解。
这个机制非常有用。一个场景里堆了几百个箱子,如果它们永远处于激活状态,每个时间步都要做接触求解,性能直接崩掉。睡眠就是让静止物体“退休”,大幅减少计算量。
参数设置经验是这样的:
- 阈值设得太大,物体稍微碰一下就“睡死”了,玩家踢一脚没反应,体验很差。
- 阈值设得太小,物体永远不睡觉,性能白损耗,而且微小的数值抖动会被不断放大,表现为物体缓慢漂移。
我一般把睡眠阈值设为默认值的一半左右,然后单独检查“长时间静止后是否还会自移动”。如果自移动,就适当提高阈值,而不是去调求解器。
3. 接触与材质参数:摩擦、恢复系数与碰撞行为
刚体的稳定性调好之后,物体之间怎么交互,就归接触参数管了。摩擦和恢复系数是这里的两大主角。
3.1 静摩擦与动摩擦:为什么物体会打滑
摩擦参数在大多数引擎里分成静摩擦和动摩擦。静摩擦是物体从静止到开始滑动需要克服的力,动摩擦是匀速滑动时受到的阻力。如果一个物体放在斜面上慢慢往下滑,而不是静止不动,往往就是静摩擦不够。
我的经验是一个大致参考:
- 地面和木箱:静摩擦 0.7~0.8,动摩擦 0.5~0.6。
- 光滑冰面:静摩擦 0.05,动摩擦 0.03。
- 金属之间的接触:静摩擦 0.3 左右,动摩擦 0.2 左右。
注意,动摩擦最好不要设为 0,否则物体会在碰撞后表现出“永远滑下去”的诡异状态。除非你刻意做冰面关卡,否则纯 0 摩擦会让玩家以为地面装了传送带。
还有一个调参细节:摩擦力的作用点在接触面中心,如果你把两个物体的接触面做得很小(比如用一堆细杆模拟一个平台),摩擦力的表现会非常不稳定。这种情况下优先改碰撞体形状,而不是死磕摩擦系数。
3.2 恢复系数不是“弹性”,是对冲量损失的模拟
恢复系数这个概念我见过很多误解。它不是“弹性程度”,而是碰撞后法向速度与碰撞前法向速度的比值。取值 0 代表完全非弹性碰撞,碰撞后法向速度归零;取值 1 代表完全弹性碰撞,法向速度不损失。
所以如果你想要“球落在地上弹几下然后停住”,恢复系数取 0.5~0.6 就够了,而不是 1.0。真正取 1.0 的后果是球永远不会停,每次弹跳高度都一样,看起来像反重力特效。
另外不同物体碰撞时,引擎默认会做组合计算。比如两个物体的恢复系数分别是 0 和 1,按乘法组合就是 0,按平均值组合就是 0.5。结果完全不同。调参之前,先确认你用的组合模式是什么。
3.3 摩擦组合模式怎么选
主流物理引擎一般提供四类组合模式,有必要把它们记住:
| 组合模式 | 计算方式 | 适用场景 |
|---|---|---|
| Average | 取平均值 | 默认且通用,不同材质混合时表现均衡 |
| Min | 取较小值 | 模拟“光滑面优先”,比如冰块合路面 |
| Multiply | 取乘积 | 需要强烈反差时,混合结果更极端 |
| Max | 取较大值 | 模拟“粗糙面优先”,比如粗糙水泥地 |
我在项目里最常用的组合是 Average,因为它的可预测性最好。如果你遇到“明明把摩擦设定的很高,但物体还是滑”的情况,优先检查组合模式,大概率是被 Min 或 Multiply 把数值拉低了。
3.4 接触法线与边缘摩擦的实际影响
很多人调的摩擦在理论计算里没问题,但一跑起来就废,原因在于接触几何有问题。最常见的是用非常薄的盒子做地板,碰撞体只有一条边缘接触到球体,接触面小,摩擦表现极不稳定。
这种问题从参数上基本调不出来,唯一办法是给碰撞体加厚度,或者换成凸包碰撞体。经验值:任何作为“地面”的碰撞体,厚度至少要在 0.1 以上,否则高速度物体冲过来时,引擎很容易把接触点算在边缘尖角上,产生奇怪的弹射。
4. 阻尼与运动学限制参数:手感调优的关键旋钮
阻尼是“手感”的灵魂。质量和摩擦决定物体在静态接触下的表现,阻尼则决定物体在空中和运动中的体感。
4.1 线性阻尼与角阻尼的适用场景
线性阻尼模拟的是空气阻力,它会让速度随时间指数衰减。角阻尼则让物体旋转变慢。默认值通常接近 0,表现是物体失去推力后会滑行很远、转个不停——这在物理上没错,但在游戏手感里往往是灾难。
我的调参心得:
- 做“沉重感”的角色或载具时,线性阻尼调到 0.5~1.0,角阻尼调到 0.5~1.0。
- 做飘浮、太空场景时,两个阻尼都调 0,营造无阻力的感觉。
- 做爆炸冲击效果时,临时调低阻尼让碎片飞得更远,等特效结束后再调回正常值。
需要注意的是,阻尼不是越高越好。线性阻尼过高会让物体运动显得“胶水一样黏”,下落过程中突然减速,非常不自然。角阻尼过高则会导致旋转物体在碰撞时没有足够的转动反馈,看起来像被定住一样。
4.2 最大速度与最大角速度限制
引擎为了防止数值失控,会给物体设置最大速度限制。这项参数平时不用动,但做高速运动物体(比如子弹、赛车)时一定要检查。
如果你把一枚子弹的速度设成 500 米/秒,而默认最大速度只有 100,引擎会直接截断速度,导致子弹飞得比预期慢,高空抛物时还会出现轻飘飘的感觉。更大问题是“隧穿”——物体速度快到在一个物理时间步内穿越了整个碰撞体,引擎完全检测不到碰撞。
处理方式有两个方向:
- 提高最大速度限制,同时调高物理子步数(比如一帧做 4 次子步),保证高速物体不会穿模。
- 对于子弹这类高速小物体,不依赖物理碰撞,改用射线检测(raycast)配合物理参数做简化模拟。
4.3 速度迭代与位置迭代次数的平衡
迭代次数是物理引擎里最难直观理解、也最能决定稳定性的参数。它决定求解器每帧用多少轮迭代来修正速度误差和位置误差。
直觉上,迭代次数越多越稳定,但实际表现是:速度迭代多了,堆叠物体不容易滑动;位置迭代多了,穿透纠正更快。问题在于迭代是要花时间的,翻倍可能让物理性能直接打五折。
经验参考值:
- 默认速度为 8、位置为 4 左右,适合大多数场景。
- 堆叠物体(比如积木塔)出现抖动时,把速度迭代调到 12~16,先把速度误差压住。
- 物体穿透频繁时,把位置迭代调到 6~8,并同时确认最大速度不过高。
调迭代次数前,先确认时间步长是干净的。如果你在渲染帧率不稳定时直接把固定时间步长拉大,再调迭代次数也救不回来。
5. 关节与约束参数调试:让连接件不抖不飘
关节(joint)是动力学里最容易让人血压飙升的部分。无论是门铰链、机械臂、汽车悬挂,还是布娃娃,调不好的表现基本都是两种:抖动或者漂移。
5.1 约束漂移的本质
关节的本质是一个约束方程:它规定两个刚体之间的相对位置和角度差必须保持某个值。但物理引擎是分步求解的,每帧只能修正一部分误差,所以实际结果总是会有积累误差。约束漂移就是这个误差的宏观体现。
最常见的表现形式:一个用铰链连接的门,开着开着角度慢慢变大,或者关门时回弹一下。原因通常是位置迭代次数不够,导致每次修正都不彻底,误差一点点累积。
我常用的一种排查方法:把时间步长缩小一半,看漂移是否明显减少。如果减少,说明是求解精度不够,优先调迭代次数;如果毫无变化,说明约束本身设置有毛病,比如锚点位置错了。
5.2 弹簧与马达参数的经验调法
很多关节都支持驱动器,比如弹簧、马达。这个驱动器的参数有三个核心量:刚度、阻尼、最大输出力。
刚度过大,约束会被“拽”得很紧,但只要一超限就容易抖动,类似吉他弦拨动后的高频振动。刚度过小,物体会像果冻一样软绵绵。阻尼的作用是抑制振动,阻尼越大,反馈越迟钝,但越不容易抖;阻尼越小,反馈越灵敏,但更容易产生振荡。
调参数我的习惯是先定刚度,再调阻尼,最后限制最大力:
- 刚度从 0 开始,慢慢加,直到物体回到目标位置的速度“快但无感”。
- 阻尼调到刚度的 0.2~0.3 倍左右,作为初始值,再根据抖不抖微调。
- 最大输出力设为目标工况下所需推力的 1.2~1.5 倍,留出余量又不至于过冲。
举个实际例子:我做机械臂的关节电机,目标是把一段 2 米长的臂在 1 秒内抬到指定角度。先粗调刚度到能快速响应,发现末端有点抖,于是把阻尼往上加,抖动消失后,再把最大力限制在电机标称扭矩附近,防止它把整辆小车掀翻。
6. 实战调优方法:从现象反推参数问题
前面讲的都是单个参数,到了真实环境里,问题很少是单一参数引起的。更重要的是学会“看现象定位参数”。
6.1 常见异常现象与参数排查对照表
这张表是我每次调试都会对照的速查表,建议按这个顺序走:先看稳定性,再看手感,最后看性能。
| 异常现象 | 可能原因 | 优先检查项 |
|---|---|---|
| 物体落地后持续抖动 | 迭代次数不足 / 恢复系数过高 | 速度迭代提到 12,恢复系数降到 0.2 |
| 堆积物体缓慢滑动 | 摩擦组合被拉低 / 静摩擦太低 | 检查组合模式,静摩擦调到 0.6 以上 |
| 高速子弹穿过墙壁 | 最大速度过大 / 子步数不足 | 调大子步数或改用射线检测 |
| 物体静止后缓慢漂移 | 睡眠阈值太小 / 阻尼太低 | 提高睡眠阈值,或把阻尼加到 0.8 |
| 关节回弹且晃个不停 | 驱动器刚度过大 / 阻尼不足 | 降低刚度,增加阻尼 |
| 车转弯就翻 | 质心偏高 / 悬架刚度不够 | 下移质心,增加悬架刚度 |
| 物体被推一下飞得离谱 | 恢复系数被组合成 1 / 阻尼为 0 | 恢复系数降到 0.1,阻尼加 0.5 |
先看表格里和自己现象最像的一行,把优先检查项调到位,90% 的诡异行为都能解决。
6.2 参数梯度测试法
遇到多个参数同时可疑的时候,不要直接“凭感觉一起改”——一次只改一个参数,改完跑一遍,记录结果,再改下一个。这是我从工程调试里学到最实用的方法论。
具体做法是:
- 把当前参数组合存成一份基线配置。
- 选一个可疑参数,从基线值往上调 50%,跑一遍,记录是否变好。
- 再往下调 50%,跑一遍,记录是否更差。
- 如果两个方向都变差,说明基线值就是局部最优;如果一个方向变好,就顺着那个方向继续二分步进。
- 确定这个参数后,再选下一个参数重复。
这套方法看着蠢,但比“连改五个参数后不知道是哪一步救了回来”要高效得多。每一次都留下记录,下次遇到类似现象直接翻记录,省下的时间远超调参本身。
还有一个独门技巧:很多物理引擎支持在运行时动态修改参数。调试不要停下来改代码再重新跑,应该把参数暴露到控制台或者调试面板上,用滑条实时调整。这样你几乎马上就能感受到参数对物理行为的影响,比改一次跑一次快十倍以上。
7. 写在最后的实战体会
动力学参数设置没有一劳永逸的“标准答案”,但有几个原则基本上每次都适用:优先用密度代替直接质量、每次只改一个参数并做记录、稳定输出优先于物理正确性、以及永远先检查碰撞体几何是否正确再调参数。我见过太多人花几个小时去调摩擦,最后发现是碰撞体太薄导致的接触点异常。搞物理模拟的第一课不是学公式,而是学会怀疑自己的每个假设。这是我的经验,也是新手最容易忽视却收获最大的一步。调参这东西,急不来,但只要思路对了,参数是会开口说话的。