一个完整 Game Thread 帧的执行流

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
FEngineLoop::Tick()
├─ UpdateTimeAndHandleMaxTickRate() // 计算 DeltaTime / 帧率限制
├─ ENQUEUE_RENDER_COMMAND(BeginFrame) // 把"开始渲染帧"投递到 RT 队列
├─ GEngine->Tick(DeltaSeconds, ...) // 进入 UWorld::Tick
│ └─ UWorld::Tick()
│ ├─ SetupPhysicsTickFunctions() // 配置 StartPhysics/EndPhysics 这两个特殊 Tick
│ ├─ RunTickGroup(TG_PrePhysics) // ⭐ 角色逻辑、骨骼动画 TickPose 都在这里
│ ├─ RunTickGroup(TG_StartPhysics) // 给 Chaos Solver 投递 dispatch
│ ├─ RunTickGroup(TG_DuringPhysics) // 物理跑的同时可并行的 Tick
│ ├─ RunTickGroup(TG_EndPhysics) // ⭐ 同步物理结果回传给 Component
│ ├─ RunTickGroup(TG_PostPhysics) // ⭐ 布料、IK、SkeletalMesh 渲染数据更新
│ ├─ RunTickGroup(TG_PostUpdateWork)// 摄像机、HUD 之类
│ └─ StartAsyncSendAllEndOfFrameUpdates() // ⭐ 把组件状态(PrimitiveSceneProxy)同步给 RT
├─ RedrawViewports() // 触发渲染(实际是发命令给 RT)
└─ GFrameCounter++
  • ETickingGroup 的定义 :
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    enum ETickingGroup : int
    {
    TG_PrePhysics, // 物理仿真之前(角色逻辑、TickPose)
    TG_StartPhysics, // 启动物理(dispatch async)
    TG_DuringPhysics, // 与物理并行
    TG_EndPhysics, // 等物理结束、回写结果
    TG_PostPhysics, // 物理之后(布料、Slave 骨骼、SceneProxy 准备)
    TG_PostUpdateWork, // 摄像机更新等
    TG_LastDemotable,
    TG_NewlySpawned,
    TG_MAX,
    };