UnrealEngine的Chaos引擎架构简要分析

1 Chaos的主要类

这部分架构和各类主要作用主要参考
原文

为了方便查阅先搬到这里

1.1 主要类图

1.2 物理世界

1.2.1 UWorld

UWorld是代表由Actor构成的整个游戏世界,它持有一个FPhysScene来代表物理世界,可以类比为渲染中的FScene,物理世界的步进(Advance)初始也由UWorld::Tick()发起。UWorld与物理相关的功能一般在PhysLevel.cpp中实现。

1.2.2 FPhysScene

FPhysScene等价于FPhysScene_Chaos,继承自FChaosScene,是Chaos的首要入口。碰撞事件的注册分发,物理网络同步相关的内容也由其处理(通过IPhysicsReplication) 物理模拟的步进也在该类开始(StartFrame)

1.2.3 FPhysicsInterface与FPhysicsCommand

这两个类都是FPhysicsInterface_Chaos的别名,该类提供了大量的辅助功能接口,如FlushScene,IsInScene,CreateShape以及对物理ActorHandle的有锁读写操作等。

1.2.4 FPhysicsSolver

FPhysicsSolver等价于FPBDRigidsSolver,继承自FPhysicsSolverBase,虽然以Sovler命名,但该类并不是真正进行解算操作的地方,而是物理结算器与操作数据的进一步封装。 它持有一个FPBDRigidsEvolution类,这才是实际负责物理解算的类;同时还持有FParticlesType(FPBDRigidsSOAs),该类为所有Particle最终的数据集合。

Particle一般翻译成粒子,但是质点可能更为合适,指物理模拟中具有形状和质量的最基本的单位。

1.2.5 FParticlesType

实际指向FPBDRigidsSOAs,SOA指Structure of Arrays,一种常见的组织数据的优化方式。该类持有物理场景中所有Particle的数据(Position、Mass、Geometry等)

1.2.6 FPBDRigidsEvolution

等价于FPBDRigidsEvolutionGBF,继承自FPBDRigidsEvolutionBase。这里是最终进行物理解算的地方,物理引擎中碰撞检测的Broad Phase、Narrow Phase以及上述的PBD过程中积分,构建约束,求解约束等过程都在这里发生。

GBF是Guendelman,Bridson,Fedkiw的缩写,为Nonconvex Rigid Bodies with Stacking这篇论文的作者,Chaos中使用了文章提出的Shock Propagation Algorithm。

1.2.7 FChaosMarshallingManager

Particle数据的管理器,控制从主线程到物理线程的数据同步。核心的数据在FPushPhysicsData与FPullPhysicsData中

1
2
3
4
5
6
7
8
9
class FChaosMarshallingManager 
{
...
//push
FPushPhysicsData* ProducerData;
...
//pull
FPullPhysicsData* CurPullData; //the current pull data sim is writing to ...
}

物理线程与游戏线程间的数据同步被分为Push与Pull两部分,UE5以游戏线程为主视角,Push为将游戏线程上的数据变化推送到物理线程。比如触发了角色的移动,移动组件会将输入转化为Pawn速度与位置的变化,其对应的碰撞体也应该进行更新。

1.2.8 FPushPhysicsData

需要从游戏线程的对象推送到物理线程的数据。

1.2.9 FPullPhysicsData

物理模拟结束后,需要从物理线程回写到游戏线程对象的数据。

需要注意的是,事实上并不存在一个独立的物理线程,物理任务会被分发到工作线程上处理,后续我们讨论所谓的物理线程时都是指非游戏线程的其他处理物理任务的工作线程。

1.3 物理Actor

1.3.1 UPrimitiveComponent

UPrimitiveComponent为所有持有几何物体的基类,会创建一个FBodyInstance作为其在物理世界中的代表。 无论是UStaticMeshComponent还是USkeletalMeshComponent又或者UCapsuleComponent实际最终都会通过FBodyInstance与物理世界进行交互。此外还有UGeometryCollectionComponent等用于特定物理功能相关的Component,它们会持有额外的物理代理。

1.3.2 FBodyInstance

继承自FBodyInstanceCore,物理相关的各项属性与设置都由该类持有,并暴露给编辑器进行设置,引擎代码注释中对FBodyInstance的定义如下:

Container for a physics representation of an object.

FBodyInstance拥有几个重要的属性:

  • TWeakObjectPtr BodySetup
    //持有全部碰撞相关的设置,用于初始化FBodyInstance
  • FBodyInstance* WeldParent
    //一个BodyInstance所连接的父Bod
  • FPhysicsActorHandle ActorHandle
    //事实上是FSingleParticlePhysicsProxy*,为物理引擎内部BodyInstance的呈现与代理。

1.3.3 FPhysicsActorHandle

等价于FSingleParticlePhysicsProxy*,一个需要进行物理解算的对象在物理引擎内被称之为一个Particle,该类作为其代理充当与物理引擎交互的接口。 物理引擎只关注一个物体的几何形状、位置、以及质量等属性,它们由TGeometryParticle持有,这是Game Thread上一个Particle的呈现。此外,Proxy还持有一个TGeometryParticleHandle,这是Particle在物理线程上的Handle。 所以场景中每一个Particle都是由Game Thread上的Geometry Particle和物理线程上的Handle共同代表的,物理线程上具体的数据由FPBDRigidsSOAs持有,Handle通过引用访问它。

除此之外还有描述破坏集合的FGeometryCollectionPhysicsProxy、描述关节约束的FJointConstraintPhysicsProxy等.

1.4 小结

这里我们需要明白Component、BodyInstance、PhysicsProxy、Particle、与ParticleHandle之间的关系:Component是完全的游戏逻辑层面的对象,BodyInstance则是其在物理场景中的代表,PhysicsProxy与Particle代表其持有的各种物理运算相关的数据,这些对象都存在于游戏线程上;ParticleHandle则是Particle在物理线程上的代表,ParticleHandle不再单独的持有一个Particle的各项属性(位置、速度等),而是多个ParticleHandle的数据通过SOA的方式被组织在一起。

Proxy的类型在EPhysicsProxyType枚举中定义,共有9中类型,下文中如无特殊说明,Proxy默认指FSingleParticlePhysicsProxy

2 初始化

Init
Init
物理对象初始化
物理对象初始化
FBodyInstance初始化
FBodyInstance初始化

这些东西都在BodyInstance.h的TInitBodiesHelperBase::InitBodies()中

TestInlineCode




本站由 Caint 使用 Stellar 1.33.1 主题创建。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处。