物理系统:高级运用
物理系统:高级运用
角色控制 Character Controller

Character Controller 是个反物理系统,物理交互是被控制的,
Character Controller和普通的Dynamic Actor\是不同的,主要的三个特点是:
- 它和刚体之间的交互是可控的
- 角色的摩擦力被假设为无穷大,且没有弹性
- 加速、减速、转向都是瞬时的,甚至可以传送
物理系统中角色控制器的构建

采用双层结构
- 一般使用胶囊体,内层是实际的碰撞体,外层主要是防止对象与其他物体过近。
从而避免高速运动下直接发生重叠的情况以及其他对象过近时相机视角出错的问题)

贴墙移动需要往前滑
- 当我们控制的角色与墙发生碰撞时,不该停下来。更符合我们认知的是该沿着墙进行滑动

自动步进以及它的问题
- 游戏世界避免不了高低起伏,比较经典的是爬楼梯。
一个解决方案是角色移动角色时,角色会上抬一小段距离计算
另一个经典实现就是楼梯看着是高低起伏,其实是直线斜坡。 - 问题:由于角色移动时会自动往上抬,所以如果一个障碍物高度和碰撞体差不多高可能会被卡住,所以像门这种一般都会比设计得大一些。

斜坡限制和向下滑动
- 设计最大可爬角度,当大于这个角度时,角色会滑下来。
以及如果想更加精细的话,上斜坡的动作应该有一种攀岩的感觉,往下滑时应该有奋力刹车的动作等.

Controller 体积更新
- 简单讲就是游戏中角色随状态会改变它的体积(比如站蹲趴、变形等),所以会需要实时更新计算它的size,
而在处理过程中,应该在更新之前进行重叠测试,防止因为物理系统处理的比较快等原因导致在实际上还不能改变到目标尺寸的时候就进行了更新。
这样会导致卡住,比如卡到管道里。

Controller 推动物体
- 角色可以对其他动态物体施加力互动,往往以当时角色控制器的冲量进行计算

角色站在移动的平台上
- 在这种情况下,一般在逻辑上把角色控制器和平台物体绑定在一起(除非要进行更高标准精细计算的情况),
来防止平台移走角色下落的情况以及因为帧率问题导致的角色处在上下移动平台上时不断弹动的情况。 - 可以用raycast来检测角色站到哪个物体上
Info
总的来说,角色控制器本身并不是多复杂的对象,但其拥有很多小细节和设计来模拟各种不同情况下的真实处理。
而作为引擎设计者,应在设计角色控制器时留有较多的处理空间给开发者进行不同的细节设计。
布娃娃系统 Ragdoll
布娃娃系统就是利用了人物的joint和骨骼,一般设置的较粗略,最多也就十几个joint,然后设计彼此之间的限制和关系,从而形成合理的转变动作.

- 如上图,当角色从后面将敌人杀死,然后一脚踹了下去。我们可以用动画把这个动作做出来,但是它不可能适用所有情况。
所以我们采用布娃娃系统,刚开始用动画,后面将动画作为物理的输入,让物理引擎去模拟。
布娃娃系统实现

将关键的Joint用大的Rigid Bodies连起来
一般选取十多个重要的关节即可,需要控制好这些关节的约束,不然会产生很奇怪的结果。

将joint分为三类:
- Active joints — 这些joint上布娃娃系统和原本骨骼重叠,所以只需要直接用原骨骼系统去进行变化即可
- Leaf joints — 在布娃娃系统joint尽头未被覆盖的joint,使其保持动画设定的变化即可,跟着布娃娃系统尽头的joint变化延伸
- Intermediate joints — 在两个布娃娃系统joint之间的原生骨骼节点,一般使用插值均匀分到这些joint上进行限制性变化

在动画整个过程中完成动画到刚体的混合
比如上述刺杀过程,在动画进行到一定情况时(比如快倒下时)转到布娃娃系统由物理系统去计算

现代游戏将物理与动画融合完成更好的艺术表现
比如抱着一个小女孩跑步的过程,一方面小女孩自身拥有一定的晃动动画,另一方面随着整体位置的移动,
动画带来的角色物理信息会一起输入到物理系统去更新最终呈现出来的融合效果,使得避免动画单纯重复(只动画)和小女孩乱晃(只物理/布娃娃)。
衣料模拟 Clothing

基于动画的衣料模拟
- 把衣服当身体一样进行动画处理,在衣服上设置joint和骨骼,并进行相应的插值处理。
优点在于便宜和可控(移动端),缺点在于不够真实、和环境没有交互以及设计上受限.

基于动力学骨骼的衣料模拟
- 像布娃娃系统一样设置一些骨骼joint,利用物理系统去进行计算处理。
优点在于便宜和可交互,缺点在于质量不可控、动画师的工作量大、不鲁棒以及需要高质量物理系统参与.
基于网格的衣料模拟 Mesh-based Cloth Simulation
简单讲就是获得物体的mesh,并对每一个顶点进行计算处理。
而由于物理系统计算的昂贵,所以一般不会像渲染时一样对每个顶点计算,而是相对稀疏。(如下图, 少几倍到十倍)

具体做法上细节如下(以人物身上的衣料为例(披风)):

首先,对每一个顶点要设置最大的移动半径。
一般来说,对离人物越近的顶点,最大移动半径越小(比如脖子处基本不动),一方面更符合物理实际,另一方面可以减少穿模概率
在游戏开发者角度来说,需要提供衣料的物理属性进行设置。以UE4为例,有如下属性:

结合上渲染系统,可以表现出不同材质和物理情况的衣料。
而在引擎开发者角度,衣料的实现是基于一个Mass-Spring系统。
我们只能把衣料处理成许多弹簧质点。
针对每一个质点,它会收到两个力,一是弹簧弹力,与弹簧系数和位移大小有关;
另一个是所谓damping force,是一个衰减力,与damping系数和速度有关。如下图:

这个衰减力主要是为了处理空气阻力(每一个质点代表的是实际的衣料上的一个小面,所以空气阻力并不小)和能量爆炸问题(随着迭代产生)
根据不同的需求和衣料特点,实际中如何设置弹簧质点各有不同,以最标准的每个顶点之间一个弹簧为例进行详细力的分析。取其中某个顶点为例进行受力分析:


其中,空气阻力是受速度影响的,简单计算就是速度乘以一个常量系数(虽然实际上应该是速度平方)。
获得加速度之后,可以直接利用Verlet公式进行计算下一帧的位置。
Verlet公式由上一课所提的半隐式欧拉法为基础进行转换得到,只需要利用上一帧位置和当前帧算出的加速度即可,成本低速度快。其另外一个值得注意的优点是避免了速度的计算,从而避免了速度突变导致的位移不稳定。

基于位置的动力学模拟(PBD)

现在最常用的是处理弹簧算法的方法是:Position Based Dynamics(PBD),
其简单思想是用拉格朗日力学替代传统力学, 放弃“约束 - 力 - 速度 - 位置”的逻辑而把所有的力学关系描述成一套约束,并直接解出最后的位置,而不关心速度。
PBD在后面会详细介绍。
自穿插问题

同一件衣服之间、不同件衣服之间的碰撞十分复杂,解决方案:

- 单纯把衣服变厚即可,这样即使有一定穿模也不影响
- 使用很多substep去精细的处理物料间的碰撞

- 设置一个最大速度阈值,防止衣料之间穿模的过深,还能弹回来
- 楼上方法的进阶,在衣料内部设置一个反向的力场,当有其他衣料穿进来时对其施加反方向的力将其弹出。
破坏模拟 Destruction

破坏系统的制作大概分为如下步骤:

设计架构 Chunk Hierarchy。将完整未被破坏的物体自然分割成不同大小的块并生成树状结构进行描述它们的关系。

建立不同块之间的联系,此时是指同一层的不同块之间的关系。设置它们联系的紧密程度。实时更新。

对每一个联系设置一个value值,表示当多大的力打到该部分时会打断其间的联系。其实也就是“硬度”。
每次打击后更新其值(比如不断变小)。变成0时即断开。

计算从冲量产生的伤害值 D = I / H 。I是指撞击给的冲量,H是指刚体的材料硬度。

计算球体撞击的伤害值 D。
对结果分段,在比较小的范围内物体收到相同的完全的伤害,在最大伤害范围外物体不受到伤害,在中间从内到外插值不断减小。

另外,当撞击发生时,有没有support graph也会影响结果(应该是指比如物体附着在其他物体上时,发生撞击只会影响对应部分)

通过Voronoi Cell生成Chunk.
就像细胞生长一样,在一个区域内生成随机撒一些种子,然后这些种子以相同的速度(半径不断增大的圆)向外扩张,当遇到其他点的圆时就停止,最终占满空间。

如果是一个2D的mesh,先生成包围盒,然后在包围盒内随机撒种子进行分割。


3维物体的切割也是类似。只是最后要用一个分割四面体的方法。
难点是处理切割处的纹理问题,一般有两种方式:
- 直接制作对应的三维纹理,切割时直接用(麻烦、贵)
- 离线计算好这些纹理,一旦破碎则切换到对应的纹理,(要瞬时处理)。
- 简而言之都很复杂。

破碎的方式也可以设计的不一样,均匀的、随机的、中心往外碎等等。

物体碎裂生成的刚体碎片的交互开销巨大,需要谨慎使用

为使得看起来更加真实,破碎应当搭配上合适的音效,以及粒子系统。

破坏系统容易出现的问题


一些物理破坏模拟引擎
载具模拟 Vehicle

载具模型由一个刚体构成,还有一些弹簧等组件。
各种作用力

驱动力 Traction Force
- 由引擎的扭矩经过一系列操作获得轮胎扭矩,再从而获得静摩擦力F(未和地面失去连接)。

悬挂力 Suspension Force
- 轮胎是悬挂在车上的(利用弹簧),所以有一个随着轮胎离车体距离形成的弹簧弹力

轮胎力 Tire Forces
- 分两个:一是向前的纵向力,由向前的拉力(如上述)和反向的拉力和转动阻力组成;
二是横向力(用于转弯),是由滑动摩擦力和角度构成。最终方向由两个力的合力构成。
重心对车子的影响



重心本身的计算就是两轮之间重量的中心点;在跳跃、转弯时重心靠前和靠后会发生不一样的接过。
- 平稳性:重心靠后更稳定
- 转向:重心越靠前,越难转弯

加减速对车身影响:
在实际驾驶中,汽车的重心是会发生变化的,主要是由驱动力产生(加速时靠后,减速时前移等)。


转向角校正:
当前面两个导向轮转动一样角度时,靠外的轮胎会发生空转。
所以实际驾驶中两个轮胎的转动角度是不一样的,具体是由轮胎到转动圆的圆心的连线(半径)的垂线(其实就是切线)决定。

比如在过减速带时,如果简单的进行raycast(当前轮胎被减速带穿模过了就往上抬,否则下降),会出现穿模。
实际处理中要用spherecast,将轮胎整体以圆的形式去判断。
高级:PBD/XPBD
拉格朗日力学:将把求解力学的运算变成求解约束的问题。而借助约束又可以求出量。
圆的约束:

其中雅克比矩阵 J( x 为 向量),就像牛顿迭代法一样,该方法是逐渐逼近目标解的(约束为0),而雅克比矩阵就是最快收敛到解的方向。
弹簧质点模型约束:

PBD
PBD 简单理解就是对于某个点来说,根据雅克比矩阵可以求出改点移动的倾向,
然后再根据步长 λ 与 向着雅克比矩阵方向来不断逼近约束为0的点。(IK也是一样,利用雅克比矩阵得到关节扰动的趋势,再不断逼近)
弹幕有提到该方法是梯度下降发、超级牛顿迭代法

解:用泰勒公式将C展开成多项式,然后去掉高阶项(因为△X很小),同时假设△X是沿着雅克比矩阵的方向去走的,并确定步长。

伪代码:

PBD的优势

XPBD
在 PBD 的基础上增加了刚度( stiffness) 用于描述约束的强弱,例如硬币的刚度就比较大,布的刚度就比较小。
