02 - 物理系统的高级应用
本文将对游戏引擎中物理系统的高级应用做一些简单介绍,包括角色控制器,布娃娃系统,布料模拟,破坏模拟,载具模拟,PBD、XPBD等内容。
角色控制器
角色控制器是物理系统的高级应用,主要用于给玩家模拟物理效果。和动态刚体不同,它是反物理的。早期游戏还没有物理系统,开发者为了让玩家有良好游玩体验使用大量硬编码,例如几度坡可以走上去等。
控制器的构建
人们大多使用胶囊体来构建控制器,有内外两层,内层是真正的碰撞检测器,外层相当于缓冲区,防止高速移动出bug、相机出bug(近平面)等。
和环境的碰撞
墙体
此外,玩家和环境的碰撞也得是自然的。例如玩家和墙碰撞时,不会卡着不动,而是会沿一定方向慢慢滑走。
楼梯
当玩家在走楼梯时,它不希望被楼梯卡住,因此需要在每个阶梯处将玩家稍微升高一点,让它能顺畅走完下节楼梯。
斜坡
玩家还要面对斜坡,可以按坡度分为能上去的坡,能跳/冲上去一点然后滑下来的坡。
动态Actor
可以利用动态Actor的碰撞回调更新它的状态,决定玩家是否能推动它。
动态平台
角色还应该随着动态平台的移动而移动,好好实现需要细心。
控制器包围体的更新
随着玩家姿态的变化,控制器的包围体也要适时更新。
布娃娃系统
由于大多数动画都是角色在特定环境下做好的,因此在特定环境以外可能会出现异样。例如下图的死亡动画,在地上是正常的,在悬崖边就不正常了。因此要使用布娃娃系统,让死去的尸体掉落。
映射骨架和刚体
可以将一些关键的关节与刚体映射,最多十几个,让角色拥有布娃娃系统。
处理关节的约束
物理引擎不管人体关节的约束,还需要TA去调节关节的约束,让布娃娃系统看起来更合理。约束通常有自由、限制和锁定三种。
制作布娃娃动画
制作布娃娃动画的思想类似于动画重定向,当物理引擎计算完刚体骨架的模拟结果后,就可以通过动画重定向思想将结果应用到骨架上。从下图可以发现,主要应用的是活跃关节,对于末端的叶关节保持动画原本姿态,中间过渡性关节则用绑定姿态和刚体姿态插值。
动画和布娃娃的混合
以上面的刺杀场景为例,在播放刺杀动画时,尸体是反物理的。刺杀动画快播放结束时,让尸体变成动态的,给他一个向外的力,由布娃娃系统接管,实现平滑过渡。
在现代游戏中,有种叫做Powered Ragdoll
的布娃娃系统,它让动画一帧帧播放,物理系统一帧帧模拟,二者插值结合并为下一帧做准备。让动画有了物理感,同时没有那么失序/混乱。
布料模拟
人物的布料,毛发,小挂件等都有物理效果,离不开物理引擎的支持。
基于动画的布料模拟
可以在玩家播放行动动画的时候,让布料顺便”摆动“一下,以达到衣服随人物行动飘动的效果。这种方法不需要消耗过多计算量,非常适合移动端。但它毕竟不是真正的物理模拟,且不能和环境互动。
基于刚体的布料模拟
可以在布料上放几根刚体骨骼,让它进行物理模拟,需要高性能物理引擎的支持。
基于网格的布料模拟
这是现代游戏引擎使用的方法,通过网格来模拟布料,更具真实感。
渲染网格和物理网格
渲染网格和物理网格不同,可见物理网格比较少。
绘制网格的约束
例如披风,可以绘制出每个网格的约束,让它只能在指定范围内飘动。
设置物理材料参数
还可以调节布料的物理材料参数,获得各种各样类型的物理布料,当然也需要PBR的帮助。
质点弹簧系统
基本概念
使用质点弹簧系统来进行布料解算,即遵守胡克定律的弹力(Spring Force)和衰减力(Spring Damping Force),后者可以提高算法迭代的稳定性。
可以把衣料看成由均匀质点和弹簧组成的系统,进行布料模拟。如果想让布看起来更“硬”,可以跨节点布置弹簧。
对于布料里的一个质点,会受到重力,风力,空气阻力以及周围弹簧给它的拉力和衰减力。有了力后就能算出加速度,从而得到当前质点的位移。整块布的位移可以通过求积分得到,这里将使用Verlet积分。
Verlet积分
使用之前提到的半隐式欧拉积分方法,得到的式子如左下。将上下两式带入中间,整理得到最终的式子就是Verlet积分,它只用上一帧位移和这一阵的位移和加速度就能估算出下一帧的位移,没有考虑速度,计算较快且稳定。
基于位置的动力学PBD
此外,一种新的布料模拟方法是基于位置的动力学模拟(PBD,Position Based Dynamics)。相较于传统力学,PBD使用拉格朗日力学方法,通过数学方式计算各种约束,省去计算力和速度,从而得到快速稳定的结果。
自穿插现象
布料模拟还会发生自穿插现象,不好好处理的话结果会很丑。
解决方法
可以让布料变厚,看起来解决了自穿插问题;也可以在一次物理模拟中进行多次小模拟,防止出现自穿插现象,但计算量加大;还可以设置最大速度,防止自穿插;更可以直接在布料上设置一个立场,如果发生自穿插,立场会让布料复原。
破坏模拟
破坏系统对于现代游戏引擎很重要,它不仅是一种视效表现,还是许多游戏Gameplay的一环。
一般步骤
建立层次结构
可以用层次树状结构管理碎片,根据破坏的等级显示不同层次的碎片节点。
建立图结构
接下来需要给各个碎片间建立图结构,这是一个带权图,权值为所承受的最大伤害,如果受到的伤害超过这个值,就会断裂。
伤害计算
伤害可在击中点通过冲量相关运算得到:
会在击中点同心圆内进行相关运算,伤害会随着半径的增加而衰减:
支撑图
有时可破坏物体会与世界中不可破坏物体相连,直观表现在总会有些残留连接在不可破坏物体上。这需要在图结构上添加相关支撑节点。
程序化生成区块
不能总是拜托艺术家帮我们划分碎片区块,如果不考虑美感的话,可以用Voronoi图来程序化生成碰撞区块。
2D和3D网格
对于2D网格的碎片区块生成,可以在它包围矩形内随机选点,然后生成Voronoi图,并按此图来划分区块。
对于3D网格来说,和2D类似,但需要在切面处使用三角形剖分算法生成新的网格。
此外,还需要在切面处生成它的材质。可以使用程序化生成一个3D材质然后查表,也可以预计算切面的uv坐标,然后破碎的时候再使用。
区块的样式
对于碰撞区块的样式也可以选择,例如均匀、集群、辐射状。
在物理系统的位置
如图,对于破坏的更新发生在碰撞之后,求解之前。
回调事件
为了让破坏模拟更具真实感,可以在一些特定事件中添加回调函数,让它在生成碎片时、发生碰撞时执行相应内容,如播放声音、生成烟雾等。
存在的问题
主要是性能问题,对算力需求很大,需要对场景中的可破坏物体、碎片数量进行限制;也可以调整不同物体的模拟参数。
流行的实现
比较流行的破坏系统的实验有:
- 英伟达的APEX,Blast。
- Havok的破坏系统。
- UE5的Chaos系统。
载具模拟
载具的物理建模
载具由车身和车轮组成,用悬挂系统连接,悬挂系统可看成一个弹簧。
受力分析
牵引力
引擎驱动载具,给载具向前的牵引力。引擎、轴承和车轮之间的关系较为复杂,可以用包含发动机转速、油门和扭矩的曲线描述。
悬挂力
每个轮子均给车身提供悬挂,要单独计算,让车有种摇摆的效果。
轮胎力
轮胎还给载具提供轮胎力,对于导向轮只有摩擦力,而驱动轮额外提供了动力。
重心
载具的重心也很重要,影响载具的操纵、加速、在空中的稳定性等。重心靠前,载具在空中容易沉下来,转弯时的转向力也不足。
重量转移
在载具模拟中还需注意的细节就是重量转移,在载具加速的时候重心会往后翘一下。
转向角
此外,载具在转向时,两个专项轮的角度和转速都有差异,需要进行计算。
如果没有转向角纠正,载具的转向表现会异常,例如螺旋转向。
高级轮胎交互
轮胎与地面的障碍物也有交互,需要用到圆形的Sweeping算法来计算交互,只用简单的光线投射技术效果不佳。
PS:除去车类模拟外,还有飞行模拟,船类模拟等待我补充。。。
PBD/XPBD
约束
拉格朗日力学定义了一系列约束,可以通过约束来反向求解物体的运动。
圆周运动约束
对于圆周运动,它的位置约束就是物体只能在圆上走,因此C(x)是那样的。然后速度约束即用位置约束对时间t求导,然后用链式法则写成如下形式,左边是雅可比矩阵,右边是速度。
弹簧质点约束
而弹簧质点模型则需要满足这个约束:
PBD
原理
而PBD就是基于上面的约束求解思想,将速度等一切物理量全都变成基于位置的约束,通过在当前点求解雅可比矩阵,知道下一次迭代要往哪个方向收敛,直到得到最终解。
算法
PBD的算法如下,首先在(5)到(7)处进行半隐式的积分,然后在(8)添加碰撞的约束,防止自穿插现象,再然后在(9)到(11)处开始PBD求解,之后就是更新状态了。需要注意的是,速度一定要及时更新,否则结果不稳定。
优点
求解快,且稳定。
XPBD
是PBD的优化拓展,引入了一个叫做Stiffness的约束(下图的\(\alpha\)),让模拟看起来更真实。
参考资料
- GAMES104 (boomingtech.com)