现代游戏引擎 - 游戏引擎中物理系统的高级应用(十一)
角色控制器(Character Controller)
角色控制器(character controller)是玩家操作角色和游戏世界进行交互的接口。和很多人直观的认识不同,
角色控制器在很多情况下实际上是一个非物理的。最常见的例子是玩家控制角色停止移动时角色会立即停住,
而不是严格按照刚体仿真那样通过摩擦力来逐渐停止运动。某种意义上讲,角色控制器虽然是反物理的但却更符合人对物理世界的认知。
构建一个控制器(Build a Controller in Physics System)
在构建角色控制器时一般会使用简化后的形状来包裹角色,这样便于处理各种场景之间的互动。
与环境碰撞(Collide with Environment)
在角色和场景进行互动时最常见的情况是玩家控制的角色撞到了墙壁上。如果严格按照物理引擎进行模拟,此时角色会一直停在碰撞的位置;
而现代游戏中更常见的处理方式是修改角色的运动方向,使得角色可以沿墙壁方向进行滑动。
自动步进及其问题(Auto Stepping)
上下楼梯同样也是角色在场景中的一种常见行为。如果严格按照物理仿真进行处理,胶囊的上下楼梯会非常地困难。
因此在游戏引擎中需要单独考虑这种情况,当角色上下楼梯时自动修正角色的位置。
对于斜坡这种情况,如果按照刚体运动学进行处理会导致角色下坡时直接从斜坡上滑下来,
或是在上坡时由于具有过大的速度角色直接冲上它不应该到达的位置。
为了避免这些问题需要单独考虑角色停在斜坡或是限制角色的位置。
控制器卷更新(Controller Volume Update)
角色控制器还需要考虑角色体积发生变化的情况。当玩家控制角色进行下蹲等动作时需要自动更新角色控制体的体积,
否则容易出现角色卡在门口无法进入的问题。
控制器推送对象(Controller Push Objects)
当玩家控制角色和场景中的物体互动时需要对动态对象的运动状态加以更新。
比较常见的处理方式是发生碰撞时对动态对象施加一个相应的冲量来控制它们的运动。
站在移动平台上(Standing on Moving Platform)
除此之外,角色控制器还需要考虑动态场景的情况。当角色位于运动的平台时需要根据平台的运动来调整角色的运动状态,
否则会出现平台发生运动时角色的运动没有同步或是滞后的问题。
布娃娃系统(Ragdoll)
布娃娃(Ragdoll)系统是游戏角色动画的一个重要组成部分,它最常见的例子是角色的处决动画:
当玩家控制的角色处决了某个游戏对象时,根据处决场景的不同被处决对象会发生相应场景互动的动作。
将骨架映射到刚体(Map Skeleton to Rigid Bodies)
实际上ragdoll与前面介绍过的骨骼动画密切相关。在模拟ragdoll的运动时,
我们同样会在角色身上设置相应的节点并把不同节点之间的骨骼按照刚体进行模拟。
不过出于实时计算上的考虑,ragdoll一般只会使用非常少量的节点和骨骼来进行模拟。
人体关节约束(Human Joint Constraints)
同样地,在ragdoll中需要考虑角色身上不同节点的运动是带有一定约束的。如果忽略了人体骨骼关节的约束则会导致非常扭曲的模拟效果。
一般来说ragdoll关节的约束会由TA进行设置,如果设置的不好会出现一些反直觉的动画效果。
布娃娃的骨架动画(Animating Skeleton by Ragdoll)
需要注意的是尽管我们可以使用ragdoll来模拟角色的动画,在实际游戏中仍然是需要通过骨骼关节系统来驱动整个角色的运动。
由于ragdoll中的骨骼关节数量一般会少于实际角色的骨骼关节,
我们需要使用动画重定向技术来将ragdoll计算出的运动映射到实际的角色骨骼上。
混合动画和布娃娃(Blending between Animation and Ragdoll)
在使用时还需要注意角色动画切换到ragdoll的过程。还是以角色处决动画为例,在一开始被处决对象是使用预先录制的角色动画,
然后在某一时刻会切换成ragdoll使用物理系统来实时计算角色的行为。
更进一步,在现代3A游戏中还会将角色动画和ragdoll实时计算出的动画进行混合来提升玩家的代入感和游戏体验。
衣料模拟(Cloth)
布料系统是游戏物理仿真中的重要一环。早期的布料模拟是使用预先录制的动画来实现的,
我们可以在角色身上设置一些额外的骨骼来控制衣物的运动,
这样就可以实现角色执行不同动作时衣物随之飘动的效果。
另一种处理衣物的方法是使用刚体运动的方法来模拟衣物和角色以及场景的互动。
这样的处理方法虽然需要更多的计算资源,但可以实现相对真实衣物运动的效果。
基于网格的布料模拟(Mesh-Based Cloth Simulation)
而在现代游戏引擎中衣物运动更多地是使用网格来进行模拟。这里首先要说明的是布料仿真中使用的网格是不同于渲染中所使用的网格,
出于计算效率上的考虑布料仿真中使用的网格要比渲染中的网格要稀疏很多。
同时在布料仿真中往往还会为网格上的每个顶点赋予一定位移的约束,从而获得更符合人直觉的仿真结果。
质量弹簧系统(Mass-Spring System)
使用网格进行布料仿真的基本处理方法是使用质点弹簧系统进行模拟。我们为网格的顶点赋予一定的质量,然后将相邻顶点使用弹簧连接起来就形成了布料仿真的物理系统。
这里需要注意的是除了弹簧弹力之外一般还需要为质点施加一定的阻尼来保证质点的运动最终能够停住。
在放置弹簧时除了横竖方向外一般还需要在对角方向上也设置一些弹簧,这样可以保证布料具有抵抗对角方向的刚度。
最后把外力施加在质点弹簧系统上就可以进行布料的运动仿真了。这里需要注意的是在进行仿真时不要忘记质点除了弹簧施加的弹力和阻尼外自身还会收到重力以及空气阻力的作用。
韦尔莱积分(Verlet Integration)
对质点弹簧系统进行仿真时不可避免地会使用到一些数值积分的方法,这里我们着重介绍一些Verlet积分算法。Verlet积分本质仍然是半隐式欧拉积分,
不过在实际积分时可以将速度项约掉只保留位移和加速度项就能进行计算。因此Verlet积分不需要保存每一时刻的速度,
我们只需要位移和力(加速度)就可以进行计算,从而提高布料仿真的效率。
自相交(Self Collision)
布料仿真的一大难点在于如何处理自相交(self collision)问题。由于我们使用了没有体积的网格来表示布料,在进行仿真时很容易出现网格直接相互的穿插。
目前布料自相交的问题还没有一个十分完善的解决方法。在工业界会使用一些trick来缓解自相交的问题,
比如说对布料进行加厚、减少仿真时的时间步长、限制顶点的速度以及使用SDF进行控制等。
破坏模拟(Destruction)
玩家对场景的破坏是通过破坏系统来进行实现。一个好的破坏系统可以极大地提升玩家的游戏体验,有些游戏甚至是以破坏系统为核心玩法进行设计的。
区块层次结构(Chunk Hierarchy)
我们可以使用一棵树来描述同一物体不同碎片之间的层次关系:树的根节点表示完整的物体,而它下面的每一层表示物体经受一定程度的冲击后所产生的碎片。
连通性图(Connectivity Graph)
当确定了物体承受的冲击后就可以使用一张图来表示不同碎片之间的连接关系:图的节点表示碎片,
而图的边则表示相互连接的碎片能够承受的荷载,当冲击大于边上的值时就会发生物体的破碎。
损坏计算(Damage Calculation)
需要说明的是虽然我们使用了冲击和荷载这样的字眼,实际上在游戏引擎中却不会去计算这些物理量。
它们只是一些人工设置的数值,并不具备真实的物理意义。在游戏开发中一般会使用一些经验公式来对冲击以及物体的承载力进行计算。
沃罗诺伊图压裂(Fracturing with Voronoi Diagram)
那么如何去生成这样的一张图呢?在物理引擎中一般会使用沃罗诺伊图(Voronoi diagram)这样的技术来对原始的物体区域进行划分,
划分后的每一个区域即为所需的碎片。
对于三维的情况则要更加复杂一些,除了需要使用Voronoi图对空间进行划分还需要使用Delaunay三角化来重新生成碎片的三维网格。
同时当物体破碎后还需要为碎片的网格赋予内部材质的纹理,这一般需要使用一些程序化的纹理生成算法。
在设置Voronoi图的种子时还可以根据需要设置不同模式的种子,这样可以实现相应的破碎效果。
物理系统中的破坏(Destruction in Physics System)
从物理系统的计算流程上来看,破碎系统一般是仿真碰撞检测后实际解算之前。这主要是因为很多破碎的事件是由碰撞所导致的,
同时在物体破碎后往往还会产生新的物体(碎片)需要计算相应的运动。
破坏的问题(Issues with Destruction)
除了物理系统的计算外在处理场景破坏时还需要添加相应的声音和粒子效果,这样可以得到更加真实的游戏体验。
此外破坏系统的计算是相当昂贵的:当一个物体出现破碎后往往会带来成百上千个碎片需要进行物理仿真,
这会极大地增加物理系统的计算负载,因此在使用时需要慎重考虑。
流行的破坏实现(Popular Destruction Implementations)
目前很多商业引擎都有现成的破坏系统。
载具模拟(Vehicle)
载具系统是现代游戏中重要的组成部分。要对载具进行模拟需要推导相应的动力学模型,
以汽车为例整个汽车可以看做通过悬挂系统与地面接触的刚体。
整个汽车的驱动力来自于引擎产生的扭矩,而扭矩的大小则需要查询引擎的相关曲线来计算。
在竖直方向上由于地面的起伏车身会产生悬挂系统所导致的振动。
在平面上汽车的轮胎会产生平行于前进方向的径向力,同时还会产生的切向力控制车辆的转动。
根据车身重量的分布我们还需要计算汽车的重心。实际上重心的位置不仅会控制汽车的振动,还会汽车的转向性能有重要的影响。
同时需要注意的是当车辆进行加速或是刹车时重心的位置也会发生一些变化。
为了更好地实现转向,现代汽车在设计时会让两个转向轮的转动有微小的差异。在进行模拟时也需要考虑这个微小的角度变化。
最后需要说明的是在计算地面和车轮求交时需要把轮子看做是球,这样才能模拟出车辆在凹凸不平的地面上行驶的效果。
高级:PBD与XPBD
PBD
本节课最后讨论了PBD和XPBD两种更高级的物理仿真技术。和前面介绍过的仿真技术相比,
PBD和XPBD是建立在拉格朗日力学(Lagrangian mechanics)基础上的仿真方法。
在拉格朗日力学的框架中不再考虑力等物理概念,而是把物理定律视为系统的某种约束来描述运动。
以匀速圆周运动为例,在拉格朗日力学中我们不会去计算各种改变质点运动状态的力,
而是考虑质点运动的位置约束以及速度约束。其中位置约束的导数也称为Jacobian矩阵。
类似地,弹簧质点系统也可以表示为由约束定义的系统。
PBD在求解时,PBD会把整个物理系统描述为关于位置的约束。然后通过不断迭代来计算满足约束的解。
整个PBD的求解流程如下:
PBD是目前游戏行业非常热门的物理仿真技术,和传统仿真技术相比PBD往往会得到更稳定的解。
XPBD
XPBD可以看做是对PBD的一种推广,它在PBD的基础上引入了刚度(stiffness)的概念来描述不同约束的强弱。
引用
- 本文作者:樱白 - Cherry White
- 本文链接:https://cherry-white.github.io/posts/be812c00.html
- 版权声明:本博客所有文章均采用 BY-NC-SA 许可协议,转载请注明出处!