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.5X和Z值设为10让它变成一个厚实的地板。创建小球创建一个Sphere重命名为“BouncyBall”。将其位置提高到Ground上方比如(0, 5, 0)。添加物理组件选中“BouncyBall”点击Add Component搜索并添加Rigidbody。确保Sphere自带了一个Sphere Collider。如果没有手动添加一个。运行测试点击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。给一点摩擦力让球在滚动中能自然停下。应用材质将“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。这会更快地减缓小球的旋转避免它一直打转。微调物理材质可选如果你觉得球弹跳后滚动太久可以回到“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。应用材质将“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 GetComponentRigidbody(); 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。模拟普通木地板或土地。并排摆放将“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.80.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 性能优化小贴士物理计算是性能消耗大户尤其是当场景中有大量动态刚体时。合理使用睡眠SleepUnity的刚体在静止一段时间后会进入“睡眠”状态停止物理计算。确保不要频繁用脚本去“唤醒”修改位置、施加力本应静止的物体。简化碰撞体对于复杂的模型不要直接使用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里用这些简单的工具去尝试复现这是提升游戏手感设计能力最快的方法。