引言
笔者最近在对一个物理向玩法的游戏设计进行预研,需要高度拟真的游戏环境支撑玩法。笔者尝试使用Unity内置的PhysX物理引擎对游戏环境进行拟真向物理模拟。在预研中发现对内置物理引擎的配置有一定的学习门槛,故在此分享研究成果,帮助大家快速搭建真实准确的游戏物理环境。
PhysX
PhysX,读音与Physics相同,是一套由AGEIA(音译为“阿吉亚”或“奥加”)公司开发的物理运算引擎;也是世界三大物理运算引擎之一,另外两种是Havok和Bullet。
2008年,在Intel收购了物理引擎界的领军者Havok后,Nvidia也收购了排名第二的AGEIA。正式将PhysX技术划入旗下。NVIDIA PhysX承袭自AGEIA PhysX,但Nvidia在此基础上推出了NVIDIA PhysX物理加速,并将PhysX物理加速功能移植到NVIDIA GPU中,用户不必额外购买PhysX物理加速卡就能享受到PhysX物理加速功能。
目前NVIDIA已经开源了最新的PhysX 5.1 SDK,总计包含了66.2万行代码、文档和相关资产。PhysX物理引擎源码可以在以下github链接下载:https://github.com/NVIDIA-Omniverse/PhysX
开始前的几点说明
- 物理组件的使用:指南中不会对组件的使用和基础概念进行说明,请在掌握Unity物理组件的基础概念和使用方法后再参考此指南。Unity物理组件的使用网络上有大量教程可以学习,故不在此赘述。本文主要讨论3D场景中的物理引擎使用,2D物理引擎与3D物理引擎使用类似,可类比使用。
- 物理概念的简化:本文中的物理概念因为篇幅原因和方便理解的目的皆简化了表达,若需要更精准的描述可以参考相关物理资料来获得准确的描述。
- 物理拟真实验的背景:笔者选择了台球的运动模拟对物理引擎进行使用预研,本文中的实验皆在此环境中进行,现象的描述也皆为台球运动模拟环境中的表现。
引擎参数配置
Unity Editor开启引擎配置页面路径:
Edit -> Project Settings… -> Physics
文档链接:https://docs.unity3d.com/cn/current/Manual/class-PhysicsManager.html
笔者在台球物理模拟中配置的几个重要参数:
- Bounce Threshold:调低速度阈值使台球在很低的速度仍然进行碰撞。
- Default Contact Offset:若基于unity引擎长度单位:米,则在场景中台球直径为0.05715米,碰撞触发距离需要调小增加小型物体碰撞计算精确度。
- Default Max Angular Speed: 特别注意,Unity文档疏忽了对此条的说明,导致测试中球体滚动速度一直不拟真,最后排查才发现有最大角速度限制,需要调高最大角速度模拟出真实情况。
其他项也会影响物理拟真质量,但在台球实验中不具有明显影响,故不在此描述,读者可以根据项目实际需要进一步调整其他参数。
质量与体积
质量与体积是物理引擎中物体最基本的物理属性,如果要配置相对真实的物理环境,建议根据真实比例设置质量与体积参数,可以更好的模拟物体真实表现,未来加入的物体也可以以真实世界为基准进行配置,形成统一稳定的物理环境。
质量:
查询现实世界台球的质量为170g=0.17kg。物理引擎中质量单位为kg,则设置rigidbody组件中的Mass:0.17
体积:
Unity引擎中的默认长度单位是米(m),也就是说,在引擎中默认创建的球体,直径为1米。查询现实世界一颗台球的直径为57.15mm=0.05715m,在Unity中缩放球体scale为:X:0.05715,Y:0.05715,Z:0.05715 以使游戏世界与现实世界球体大小对应,球体collider组件会自动缩放成此大小。
以上,游戏中台球的质量和体积完成了与现实世界的对应关系。
摩擦力
PhysX使用库伦摩擦模型,分为静摩擦力和动摩擦力。
简单的说静摩擦力为两个相互接触的物体保持禁止的力,超过最大静摩擦力则会发生滑动;动摩擦力为两个相互滑动的物体之间的阻力。
现实世界中摩擦力的大小与压力成正比,其系数为摩擦系数。在物理学中我们通过摩擦系数描述两物体之间的光滑程度:
F=μ*N(N为垂直力,F为摩擦力,μ为摩擦系数)
在Unity引擎中我们通过physics material中的Dynamic Friction和Static Friction来描述物体的光滑程度。
那么问题就出现了,现实世界中都是两种材料在某种环境下的摩擦系数来表示光滑程度,Unity怎么能用每个材料的两个独立参数表达光滑程度呢?其实原因很简单,Unity引擎不可能把所有两个物质的摩擦系数记录下来,然后在两个物质发生摩擦时查询它们的摩擦系数来计算他们的摩擦力,所以只能使用抽象的方法定义物体的摩擦参数:动摩擦参数Dynamic Friction和静摩擦参数Static Friction,当两物体接触时引擎使用他们的参数计算出近似的摩擦系数进行物理模拟。
摩擦系数的计算可以通过physics material中的Friction Combine项进行定制,比如平均值(Average)、取较小值(Minimum)、取较大值(Maximun)、取相乘值(Multiply),这些模式为物理引擎对现实世界的一种模拟,计算中会产生误差,但是在物理引擎中模拟出的摩擦效果是可以接受的。若要达到极为精准的摩擦力,可以考虑用摩擦系数表的方式查询出两物体之间的真实摩擦系数进行模拟。
在台球模拟中我们知道台球之间摩擦力非常小近乎于0,则设置台球的Dynamic Friction和Static Friction都为0,Friction Combine设为平均值(Average),查询现实世界中球台的滑动摩擦系数约等于0.2,则设置球台的Dynamic Friction为0.4,因为 (台球摩擦参数+球台摩擦参数)/2 = (0+0.4)/2 = 0.2 ;球台的Static Friction没有查到具体值,可以设置为比滑动摩擦大一点的0.45,因为在台球中基本是滚动摩擦和动摩擦运动,此参数不太影响物理模拟。
弹性
物理学中我们通过弹性系数界定一个物体的弹性,引擎中使用bounciness设置物体的弹性,介于0-1之间,0为没有弹性,1为完全反弹。可以通过Bounce Combine项设置弹性模拟的模式。
在台球中一颗球击中另一颗球的物理运动是击中方向动量完全传递的过程,所以需要bounciness为1的动量完全传递效果(表现为分离角为90度)
(没有滚动的情况下台球击球总是以90度分离)
滚动摩擦力和空气阻力
滚动摩擦力在现实世界里表现为球在地上滚动然后因为滚动摩擦力的影响最终停止的现象,实际原因为球在地面凹陷后形成静摩擦力阻止了球无限滚动。
在物理引擎中的表现是:在有静摩擦力的情况下,给球体施加一个向前滚动的角速度,物体会无限滚动下去。这是因为物理引擎无法无法模拟物体滚动时的精确摩擦导致滚动衰减的情况,所以引擎中引入了角阻力Angular drag概念来通过一个参数模拟产生滚动摩擦的现象,因为是一个不精确但是可以接受的参数,所以只能对物体进行近似的滚动摩擦模拟。在台球模拟中我们把台球的angular drag设为3来近似模拟台球滚动后受到滚动摩擦力停止的效果。
物理引擎中还引入了drag参数来模拟空气阻力的效果。在台球模拟中我们忽略空气阻力所以设置为0。
施力
物理引擎可以通过对rigidbody中的函数进行施加力、施加旋转等操作,也可以通过Constant Froce组件施加持续力和旋转,网上有大量的资料,在此就不再赘述了。
现实世界中球杆击球是一个复杂的物理行为,它不仅仅是针对球的一个点体施加一个力,或者是一个平面对球体的碰撞,而是球杆头击中球后发生形变推动球前进的复杂物理运动,并且击球的位置还会大大影响球的运动(产生旋转、跳跃等情况)。
我们应该如何模拟这种力呢?笔者的方法是通过对球同时施加瞬时的力和瞬时的旋转来模拟击球的施力,并配合球杆动画达到一种仿真的效果。
模拟实验的结果也达到了令人满意的物理效果,球的运动可以表现出台球运动中的真实情况,包括高中低杆击球、侧旋球的拐弯、跳球等情况的复现。
总结
以上就是笔者通过台球模拟实验总结出的Unity物理引擎使用指南,因为研究的目的是项目预研,故对引擎的使用并不是充分全面的描述,疏漏之处请各位读者包涵和批评指正。
希望此简易使用指南能让各位开发者快速上手物理引擎的使用,实现出项目需要的物理模拟效果。
暂无关于此日志的评论。