4、材质与摩擦:物理材质的定义,摩擦系数与恢复系数(弹性)的实际调参经验
好,咱们今天聊点实在的。物理材质这个东西,说白了就是告诉物理引擎:「这个物体摸起来像什么?」是像冰面一样滑,还是像橡胶一样弹?
我刚开始做物理集成的时候,以为只要把刚体加上重力就完事了。结果呢?物体掉地上直接弹飞了,或者两个箱子叠在一起像抹了油一样滑开。嗯,这就是没调好材质参数。
4.1 物理材质的核心属性
在Three.js里集成物理引擎(比如Cannon-es或Ammo.js),每个刚体都需要绑定一个材质。这个材质主要管两件事:
- 摩擦系数(Friction):物体表面有多「涩」
- 恢复系数(Restitution):物体有多「弹」
我个人习惯把这两个参数看作一对「冤家」。摩擦大了就不容易滑,恢复大了就容易弹。但两者之间其实没有直接数学关系,你得分别调。
4.2 摩擦系数的调参经验
摩擦系数一般取值在0到1之间。0代表完全光滑,1代表非常粗糙。但实际项目中,我很少用极端值。
| 材质类型 | 摩擦系数 | 典型场景 |
|---|---|---|
| 冰面 | 0.01 - 0.05 | 滑冰、推箱子 |
| 金属 | 0.3 - 0.5 | 机械零件、工具 |
| 橡胶 | 0.7 - 0.9 | 轮胎、鞋底 |
| 砂纸 | 0.9 - 1.0 | 打磨、防滑表面 |
我在项目中遇到过一个问题:一个木箱放在木地板上,按理说应该能稳稳停住。但实际跑起来,箱子轻轻一推就滑出去老远。后来发现是摩擦系数设成了0.2,改成0.5就正常了。你想想看,木头之间的摩擦其实不小,0.2太低了。
4.3 恢复系数(弹性)的调参经验
恢复系数决定了物体碰撞后能「弹」回多少能量。1代表完全弹性(像超级球),0代表完全非弹性(像一袋面粉)。
| 材质类型 | 恢复系数 | 典型场景 |
|---|---|---|
| 超级球 | 0.9 - 1.0 | 弹跳球、蹦床 |
| 篮球 | 0.7 - 0.8 | 运动模拟 |
| 木头 | 0.2 - 0.4 | 家具、地板 |
| 沙袋 | 0.0 - 0.1 | 软体、缓冲 |
为什么会这样?因为现实世界中没有完全弹性的物体。就算是一个钢球掉在钢板上,也会损失一部分能量(变成声音和热量)。所以恢复系数永远小于1。
我曾经犯过一个错误:把恢复系数设成1.0,结果一个球掉地上后越弹越高,最后直接飞出场景了。嗯,物理引擎可不会跟你讲客气,参数设得离谱,行为就离谱。
4.4 代码示例:在Cannon-es中定义物理材质
下面是一个实际的代码片段,展示了如何在Cannon-es中创建材质并应用到刚体上:
// 创建物理材质
const groundMaterial = new CANNON.Material('ground');
const boxMaterial = new CANNON.Material('box');
// 定义接触材质对
const contactMaterial = new CANNON.ContactMaterial(
groundMaterial,
boxMaterial,
{
friction: 0.5, // 摩擦系数
restitution: 0.3 // 恢复系数
}
);
// 添加到物理世界
world.addContactMaterial(contactMaterial);
// 应用到刚体
const groundBody = new CANNON.Body({ mass: 0, material: groundMaterial });
const boxBody = new CANNON.Body({ mass: 1, material: boxMaterial });
注意看,这里我用了ContactMaterial来定义两种材质之间的交互参数。为什么不是直接在材质上定义?因为摩擦和恢复其实是「两个物体之间」的属性,不是单个物体的属性。一个橡胶球在冰面上和在砂纸上的表现完全不同,对吧?
4.5 实际调参经验总结
做了几个项目后,我总结了一套自己的调参流程:
- 先调恢复系数:让物体掉地上,观察弹跳高度。如果弹得太高就降低,如果完全不弹就提高。
- 再调摩擦系数:推一下物体,看它滑多远。滑得太远就提高摩擦,停得太快就降低。
- 最后微调:两个参数一起调,因为有时候摩擦和恢复会互相影响。比如恢复系数高了,物体弹跳时接触时间短,摩擦效果就不明显。
好了,这一章就到这里。下一章我们会聊碰撞检测的优化,到时候我会分享一些让物理模拟跑得更流畅的实战技巧。记得动手试试上面的代码,亲手调一调参数,比看十遍文章都管用。