Unity物理材质与刚体参数详解:实现真实弹跳与冰面滑动效果
1. 项目概述与核心价值
今天我们来聊聊Unity物理引擎里两个最基础、也最容易被新手忽略的组件:物理材质(Physics Material)以及刚体组件中的重力与阻力参数。你可能觉得,不就是让球弹起来、让物体在冰面上滑出去吗,这有什么难的?确实,在Unity里拖一个球体,挂上刚体和碰撞体,它自己就会往下掉,撞到地面也会弹一下。但如果你想让这个弹跳“感觉”对头——比如一个充满气的篮球和一个泄了气的皮球,它们的弹跳高度、次数、落地声音都该不一样——或者想让角色在冰面、泥地、沙地上走出截然不同的步伐,那光靠默认参数是远远不够的。这就是物理材质和阻力参数大显身手的地方。
这个内容适合所有Unity初学者,尤其是那些已经学会了创建物体、添加组件,但想让自己的游戏世界物理反馈更真实、更可控的开发者。我们会从零开始,手把手实现两个经典效果:一个是具有真实弹跳感的“弹跳球”,另一个是模拟低摩擦力环境的“冰面滑动”。过程中,我会穿插很多我早期踩过的坑和总结出的技巧,比如为什么有时候调整摩擦力没效果,如何用简单的参数模拟复杂的物理感觉。这些经验,你在官方文档里可不容易找到。
2. 物理系统基础与核心组件拆解
在动手之前,我们必须先理清Unity物理引擎(默认是NVIDIA PhysX)中几个核心组件的关系,这是理解后续所有操作的基础。很多新手调参数没效果,问题往往出在这里。
2.1 刚体(Rigidbody):物理世界的入场券
刚体组件是让一个游戏对象受物理引擎控制的“许可证”。没有它,物体就是个静态的模型,不会下落,也不会被推动。添加刚体后,物体会立刻受到重力影响,并参与碰撞计算。
核心参数解析:
- 质量(Mass):物体的质量,单位是千克(kg)。它直接影响惯性(改变运动状态的难易程度)和碰撞力度。一个质量10的球撞墙和一個质量0.1的球撞墙,效果天差地别。新手常犯的错误是随意设置质量,导致物理模拟失衡。我的经验是,在游戏世界中建立一个大概的参照系:比如一个标准立方体设为1(代表1kg),那么一个角色可以设为60-80,一辆小车可以设为800-1500。保持比例合理比绝对值更重要。
- 阻力(Drag)与角阻力(Angular Drag):这是我们今天要重点使用的参数。Drag影响物体直线运动(移动)的阻力,Angular Drag影响物体旋转运动的阻力。它们模拟的是物体在介质(如空气、水)中运动受到的阻碍,而不是物体与接触面之间的摩擦力。这一点至关重要,很多人会混淆。空气阻力会让一个飞行的球慢慢停下来,而地面摩擦力会让一个滚动的球停下来。
- 使用重力(Use Gravity):勾选后,物体会受到场景重力设置(Edit -> Project Settings -> Physics -> Gravity)的影响。如果你想做太空失重或自定义重力效果,可以取消勾选,然后通过脚本手动施加力。
2.2 碰撞体(Collider):物理形状的定义者
碰撞体定义了物体在物理世界中的“形状”和“体积”。它告诉物理引擎:“我的物理边界在这里”。渲染用的网格(Mesh)可以很复杂,但碰撞体通常用简单的几何体(如盒子、球体、胶囊体)或凸包来近似,以大幅提升计算效率。
关键点:一个物体可以没有渲染器,但只要有刚体和碰撞体,它就能参与物理模拟。碰撞体是触发物理事件(碰撞、触发)的几何基础。
2.3 物理材质(Physics Material):接触面的“性格”
这是今天的明星组件。物理材质是一种资产(Asset),你可以像创建材质球(Material)一样创建它,然后把它赋给碰撞体(Collider)的Material属性槽。它专门用于定义当两个碰撞体接触时,接触面上的行为特性,主要是摩擦力和弹力。
- 动态摩擦力(Dynamic Friction) & 静态摩擦力(Static Friction):动态摩擦力是物体滑动时受到的阻力,静态摩擦力是让物体从静止到开始滑动需要克服的阻力。通常静态摩擦力略大于动态摩擦力。将这两个值都设为0,就得到了理想的“冰面”或“绝对光滑平面”。
- 弹力(Bounciness):取值范围0到1。0表示碰撞后完全没有反弹(像一团泥巴),1表示理想弹性碰撞,能量无损失(像超级弹力球)。实际应用中,几乎没有用1的情况,因为那会导致物体永远弹跳下去。0.6-0.8可以模拟橡胶球,0.2-0.4模拟皮球或木球。
- 摩擦力合并模式 & 弹力合并模式:当两个拥有不同物理材质的物体碰撞时,如何计算最终的摩擦力和弹力?这里有几种模式(如Average, Minimum, Maximum, Multiply)。最常用的是
Average(平均值),它通常能产生最自然的效果。例如,冰面(摩擦力0)和橡胶鞋底(摩擦力1)接触,平均摩擦力是0.5,角色就会打滑但又不至于完全失控。
注意:物理材质必须被添加到碰撞体上才会生效!你把它挂在渲染器或者刚体上是没用的。这是新手最高频的失误之一。
3. 实战一:实现真实感的弹跳球
理论说再多不如动手做一遍。我们首先来实现一个弹跳球,目标是让它每一次弹跳的高度都规律衰减,最后稳稳停住,而不是胡乱蹦跶。
3.1 场景搭建与基础对象创建
- 创建地面:在场景中创建一个Cube,重命名为“Ground”。将其Scale的Y值设为0.5,X和Z值设为10,让它变成一个厚实的地板。
- 创建小球:创建一个Sphere,重命名为“BouncyBall”。将其位置提高到Ground上方,比如(0, 5, 0)。
- 添加物理组件:
- 选中“BouncyBall”,点击
Add Component,搜索并添加Rigidbody。 - 确保Sphere自带了一个
Sphere Collider。如果没有,手动添加一个。
- 选中“BouncyBall”,点击
- 运行测试:点击Play。你会看到小球自由落体,砸到地面后轻微弹起一下,然后很快停止。这是默认物理材质(
None)的效果,弹力很低。
3.2 创建并配置弹跳物理材质
- 创建物理材质资产:在Project窗口右键 -> Create -> Physics Material。命名为“PM_Bouncy”。
- 配置参数:选中新建的“PM_Bouncy”,在Inspector面板中调整:
- Bounciness(弹力):设置为
0.8。这是一个高弹力值,适合橡胶球。 - Bounce Combine(弹力合并模式):保持为
Average。 - Dynamic Friction & Static Friction(动/静摩擦):暂时都设为
0.6。给一点摩擦力,让球在滚动中能自然停下。
- Bounciness(弹力):设置为
- 应用材质:将“PM_Bouncy”从Project窗口拖拽到场景中“BouncyBall”物体上
Sphere Collider组件的Material属性槽中。或者,选中“BouncyBall”,在Sphere Collider组件里点Material右边的小圆点,选择“PM_Bouncy”。 - 再次运行测试:点击Play。现在小球弹跳得更高、次数更多了。但你会发现它可能横向乱滚,最后歪着停下来,弹跳衰减也不够“干净”。
3.3 精细化调整:结合刚体阻力
仅靠物理材质的弹力,模拟的是碰撞瞬间的能量损失。而物体在空中的运动衰减(主要是空气阻力)则需要通过刚体的Drag参数来控制。
- 调整刚体阻力:选中“BouncyBall”,找到
Rigidbody组件。- 将Drag(阻力)从默认的0稍微提高,比如设为
0.2。这个阻力会持续作用于小球,无论是在空中飞行还是地面滚动,使其速度逐渐减慢。 - 将Angular Drag(角阻力)也从默认的0.05提高到
0.5。这会更快地减缓小球的旋转,避免它一直打转。
- 将Drag(阻力)从默认的0稍微提高,比如设为
- 微调物理材质(可选):如果你觉得球弹跳后滚动太久,可以回到“PM_Bouncy”,将两个摩擦力值从0.6提高到
0.8或1.0,增加地面制动效果。 - 最终测试与对比:
- 运行游戏,观察小球的下落、弹跳、滚动直至停止的全过程。
- 你可以复制一个小球,给它一个默认物理材质(None)或者弹力更低的材质,将两个球从同一高度放下,对比它们的运动差异。这种A/B测试是调整物理手感最有效的方法。
实操心得:弹跳的“感觉”是弹力(Bounciness)、摩擦力(Friction)和空气阻力(Drag)共同作用的结果。想要一个“Q弹”的球,就提高弹力,同时保持较低的摩擦和阻力。想要一个“沉重”的弹跳物(比如铅球落在硬地上),就使用中等弹力(如0.3),配合较高的质量和高阻力。永远不要只调一个参数。
4. 实战二:模拟冰面滑动与低摩擦力环境
接下来,我们创造一个冰面环境。核心思路是将接触面的摩擦力降到极低,同时利用很小的初始力让物体滑行很长距离。
4.1 创建冰面与滑动物体
- 创建冰面:复制之前的“Ground”,重命名为“IceGround”。你可以改变它的材质颜色为浅蓝色以示区分。
- 创建滑动方块:创建一个Cube,重命名为“Slider”。将其放在“IceGround”上方,如(0, 1, 0)。
- 为方块添加物理组件:为“Slider”添加
Rigidbody组件。确保它有Box Collider。
4.2 创建极低摩擦力的冰面物理材质
- 创建物理材质:右键创建新的Physics Material,命名为“PM_Ice”。
- 配置冰面参数:
- Dynamic Friction & Static Friction:两者都设为
0.05甚至0.02。这是模拟冰面的关键,极低的摩擦力意味着物体很难停下来。 - Bounciness:设为
0.1或0。冰面通常没什么弹性。 - Friction Combine(摩擦力合并模式):保持为
Average。
- Dynamic Friction & Static Friction:两者都设为
- 应用材质:将“PM_Ice”拖拽到“IceGround”的
Box Collider的Material槽中。注意:这里是应用到地面上,而不是方块上。因为冰面的特性是由地面决定的。
4.3 赋予初始力并观察滑动
如果现在运行,方块只会垂直下落,停在冰面上。我们需要一个横向的力来启动它。
- 创建启动脚本:在“Slider”物体上创建一个新的C#脚本,命名为
IceSlider。 - 编写脚本:
using UnityEngine; public class IceSlider : MonoBehaviour { public float pushForce = 5.0f; // 初始推力大小 private Rigidbody rb; void Start() { // 获取刚体组件 rb = GetComponent<Rigidbody>(); if (rb == null) { Debug.LogError("Rigidbody component not found!"); return; } // 在游戏开始时,给物体一个向前的力 // ForceMode.Impulse表示施加一个瞬间的冲量,更符合“推一下”的感觉 rb.AddForce(Vector3.forward * pushForce, ForceMode.Impulse); } void Update() { // 可选:按空格键再次施加力,方便测试 if (Input.GetKeyDown(KeyCode.Space)) { rb.AddForce(Vector3.forward * pushForce, ForceMode.Impulse); } } } - 运行与观察:运行游戏。方块落下后,会受到一个向前的力,然后在冰面上滑行非常长的距离才缓缓停下。你可以调整脚本中的
pushForce变量,或者调整冰面材质“PM_Ice”的摩擦力值,感受不同的滑动效果。
4.4 进阶:对比实验与组合效果
为了加深理解,我们可以做一组对比实验:
- 创建不同材质的地面:再复制两个地面,分别命名为“RoughGround”和“NormalGround”。
- 创建对应物理材质:
- “PM_Rough”:摩擦力设为
1.0,弹力0.1。模拟粗糙水泥地。 - “PM_Normal”:摩擦力设为
0.4,弹力0.3。模拟普通木地板或土地。
- “PM_Rough”:摩擦力设为
- 并排摆放:将“IceGround”、“NormalGround”、“RoughGround”在X轴上并排摆放。
- 创建多个滑块:复制出三个“Slider”,分别放在三个地面的起始位置。
- 统一启动:修改
IceSlider脚本,让三个方块在Start时收到相同的力。 - 观察结果:运行后,你会清晰地看到:冰面上的滑块一骑绝尘,普通地面上的滑行一段后停止,粗糙地面上的滑块几乎瞬间停止。这个直观的实验能让你牢牢记住摩擦力的作用。
技巧分享:在实际游戏中,“冰面”效果不一定只用于冰。低摩擦力材质还可以用来模拟:
- 水面漂浮物(配合浮力脚本)。
- 科幻游戏里的磁悬浮跑道。
- 角色踩到香蕉皮后的打滑状态(临时将角色脚底的碰撞体材质切换为低摩擦材质)。
5. 物理材质与刚体参数的深度协同与陷阱排查
单独调整物理材质或刚体参数往往得不到理想效果,必须理解它们的协同工作原理。这里有几个高阶技巧和常见坑点。
5.1 阻力(Drag) vs 摩擦力(Friction):作用域辨析
这是最核心的区分,必须搞清楚:
| 特性 | 阻力 (Drag / Angular Drag) | 摩擦力 (Friction via Physics Material) |
|---|---|---|
| 作用对象 | 单个物体的属性,属于Rigidbody组件。 | 两个碰撞体接触面的属性,属于Physics Material资产。 |
| 作用条件 | 只要物体有速度/角速度,无论是否接触其他物体,持续生效。 | 仅在两个带有碰撞体的物体接触时生效。 |
| 模拟对象 | 物体在介质(如空气、水)中运动受到的阻碍。 | 物体在另一个物体表面滑动或滚动时,接触面产生的阻碍。 |
| 典型应用 | 模拟空气阻力使抛射体减速;模拟水中阻力;快速停止物体的旋转。 | 模拟地板粗糙度(地毯vs冰面);模拟轮胎抓地力;模拟墙面是否可攀爬。 |
举例:一个球在真空中(无Drag)滚过冰面(低Friction),它会永远匀速滚下去。一个球在空气中(有Drag)滚过粗糙地毯(高Friction),它会很快停下。Drag和Friction共同决定了物体从运动到静止的过程。
5.2 常见问题与排查清单
在调试物理效果时,如果你发现“怎么调都没反应”,请按以下清单逐一排查:
物理材质应用错误:
- 症状:调整了物理材质的参数,但物体碰撞行为毫无变化。
- 检查:物理材质是否正确拖拽到了碰撞体(Collider)的
Material属性槽中?而不是渲染器(Renderer)的材质槽。在场景中选择物体,查看其Collider组件确认。
碰撞体缺失或未激活:
- 症状:物体直接穿过另一个物体,没有碰撞。
- 检查:两个需要发生碰撞的物体是否都拥有碰撞体(Collider)组件?并且组件前面的复选框是勾选(激活)状态?至少其中一个物体需要有刚体(Rigidbody)。
刚体属性被脚本覆盖:
- 症状:设置了阻力或角阻力,但物体速度不减。
- 检查:是否有脚本在
Update或FixedUpdate中持续修改物体的速度(rb.velocity)或角速度(rb.angularVelocity)?这会将物理引擎计算出的阻力效果覆盖掉。正确的做法是通过AddForce或AddTorque来影响物体。
质量(Mass)比例失调:
- 症状:一个小方块撞不动一个大方块,或者碰撞后飞行轨迹怪异。
- 检查:碰撞双方的质量是否在一个合理的数量级内?一个质量0.1的乒乓球去撞质量1000的墙,乒乓球会以近乎原速弹回,而墙几乎不动。确保你的游戏世界有一个统一的质量尺度。
弹力(Bounciness)合并模式:
- 症状:球和地板都设置了弹力0.8,但碰撞后弹跳高度达不到预期。
- 检查:球和地板的物理材质,其
Bounce Combine模式是什么?如果是Minimum(取最小值),那么最终弹力是 min(0.8, 0.8) = 0.8。如果是Average,则是 (0.8+0.8)/2 = 0.8。但如果是Multiply,则是 0.8*0.8 = 0.64,弹力会降低。根据你的设计意图选择合适的合并模式。
时间步长(Fixed Timestep)影响:
- 症状:高速运动的物体(如子弹)穿过了薄碰撞体。
- 检查与分析:这不是材质问题,而是物理模拟的离散检测问题。在
Edit -> Project Settings -> Time中,可以调小Fixed Timestep(如从0.02调到0.01),但这会增加CPU负担。更好的做法是为高速物体启用Rigidbody的Collision Detection模式为Continuous或Continuous Dynamic。
5.3 性能优化小贴士
物理计算是性能消耗大户,尤其是当场景中有大量动态刚体时。
- 合理使用睡眠(Sleep):Unity的刚体在静止一段时间后会进入“睡眠”状态,停止物理计算。确保不要频繁用脚本去“唤醒”(修改位置、施加力)本应静止的物体。
- 简化碰撞体:对于复杂的模型,不要直接使用
Mesh Collider(尤其是凹面体),尽量使用组合的简单碰撞体(Box, Sphere, Capsule)来近似形状。 - 分层管理(Layer Collision Matrix):通过
Edit -> Project Settings -> Physics中的层碰撞矩阵,禁用不可能发生碰撞的物体层之间的检测(比如天空的云层和地面的小石子),可以显著减少物理引擎的计算量。 - 谨慎使用连续碰撞检测:
Continuous碰撞检测模式非常消耗性能,只对少数高速且重要的物体(如玩家发射的炮弹、玩家角色本身)使用。
6. 创意扩展:用简单参数模拟复杂物理感觉
掌握了基础,我们就可以玩一些花样了。游戏中的物理不一定要100%真实,但一定要“感觉”对。这里分享两个用今天学到的知识模拟复杂感觉的技巧。
技巧一:模拟“湿滑”或“粘稠”的地面(如泥沼)冰面是低摩擦,那高摩擦就是粗糙地面吗?不完全是。泥沼的特点是“动起来难,停下来快”。我们可以这样模拟:
- 设置一个较高的静态摩擦力(Static Friction),比如
0.9。这让物体很难开始滑动。 - 设置一个中等的动态摩擦力(Dynamic Friction),比如
0.4。一旦物体动起来了,阻力反而没那么大。 - 同时,增加刚体的阻力(Drag)和角阻力(Angular Drag),比如都设为
2.0。这模拟了泥浆介质带来的巨大粘滞阻力,让物体运动很快衰减。 这样组合起来,物体陷入泥沼时难以起步,一旦被推动,又很快失去速度停下来,感觉就很像了。
技巧二:制作“蹦床”或“弹簧踏板”效果我们想要一个平台,角色踩上去会被高高弹起。
- 为蹦床物体创建一个物理材质“PM_Trampoline”。
- 将弹力(Bounciness)设置为一个很高的值,例如
0.95。 - 关键步骤:在蹦床物体的刚体上,取消勾选
Use Gravity,并将Is Kinematic勾选上。这样蹦床本身不受物理影响,不会因为被撞击而移动,但它上面的碰撞体依然能产生弹力效果。 - 当角色(一个带有刚体的物体)落在上面时,就会获得一个巨大的向上的反弹速度。你可以通过调整角色刚体的质量、蹦床材质的弹力合并模式来微调弹跳高度。
通过这些组合,你会发现,仅仅依靠物理材质和刚体的几个参数,就能创造出丰富多样的物理交互体验。关键在于理解每个参数背后的物理意义,并敢于进行组合实验。多观察现实世界中的物理现象,然后在Unity里用这些简单的工具去尝试复现,这是提升游戏手感设计能力最快的方法。