Unreal

UE5 World Partition流程分析

本质是WorldSubSystem中的一个:UWorldPartitionSubsystem

主要关注这个函数:

UWorldPartitionSubsystem::UpdateStreamingState

WorldPartitionSubsystem::Tick

主要是Editor下的部分Tick更新逻辑

WorldPartitionSubSystem::UpdateSteamingState

更新Streaming状态的单位是UWorldPartitionRuntimeCell

Cell的内部拥有一个UWorldPartitionLevelStreamingDynamic 继承自ULevelStreamingDynamic

所以某种程度上走了原来的Streaming的逻辑

储存这些Cell的容器是UWorldPartitionRuntimeHash 目前的实现是UWorldPartitionRuntimeSpatialHash 结构层次:

TArray<FSpatialHashStreamingGrid> UWorldPartitionRuntimeSpatialHash::StreamingGrids

TArray<FSpatialHashStreamingGridLevel> FSpatialHashStreamingGrid::GridLevels

TArray<FSpatialHashStreamingGridLayerCell> FSpatialHashStreamingGridLevel::LayerCells

TArray<TObjectPtr<UWorldPartitionRuntimeSpatialHashCell>> FPatialHashStreamingGridLayerCell::GridCells

然后会根据DataLayer又进行区分加载。

  • 入口:UWorld::InternalUpdateStreamingState()
    • UWorldPartitionSubsystem::UpdateStreamingState 获取当前世界WorldPartition并且Update StreamingPolicy->UpdateStreamingState(); 有一层StreamingPolicy的抽象 实际上目前只有一种实现:
      • UWorldPartitionStreamingPolicy::UpdateStreamingState 确定是否是BlockTillLevelStreamingComplete设置flag
        • 更新StreamingSourceUWorldPartitionStreamingPolicy::UpdateStreamingSources 获取PlayerController的位置创建FWorldPartitionStreamingSource 加入到StreamingSources 获得所有WorldPartition的StreamingSourceProviders 加入到StreamingSources 记录所有有效Source的更新速度,移除无效的Source
        更新所有需要激活、加载、卸载的单元
        • 如果是客户端
          • UWorldPartitionRuntimeHash::GetStreamingCells 如果Source还是空的: 从DataLayerSubSystem里面取出所有AlwaysLoadedCells 否则 从DataLayerSubsystem里面取出所有需要激活的Cell以及需要加载的Cell
        • 如果是服务端
          • 激活所有的CellUWorldPartitionRuntimeHash::GetAllStreamingCells 遍历所有Cell全部返回(会筛选传入的DataLayer所属的Cell)
        确定每个cell的状态之后,开始设置状态?
        • UWorldPartitionStreamingPolicy::SetTargetStateForCells
          • EWorldPartitionRuntimeCellState::Unloaded:
            • UWorldPartitionRuntimeCell::UnLoad 遍历调用
              • UWorldPartitionLevelStreamingDynamic::UnLoad 走传统Streaming的流程
          • EWorldPartitionRuntimeCellState::Loaded: 先进行优先级排序UWorldPartitionRuntimeHash::SortStreamingCellsByImportance 如果当前状态是Activated,则
            • UWorldPartitionRuntimeCell::Deactive
              • LevelStreaming->Deactivate 走传统Streaming的流程
            否则则加入LoadedCelles
            • UWorldPartitionRuntimeCell::Load
              • LevelStreaming->Load 走传统Streaming的流程
          • EWorldPartitionRuntimeCellState::Activated: 先进行优先级排序UWorldPartitionRuntimeHash::SortStreamingCellsByImportance 如果LoadedCell中有该Cell则 UWorldPartitionRuntimeCell::Activate 否则,如果不是AlwaysLoaded就加入ActivatedCelles中调用 UWorldPartitionRuntimeCell::Activate
            • LevelStreaming->Activate 走传统Streaming的流程
        设置所有Cell的更新重要度
        • UWorldPartitionRuntimeHas::``SortStreamingCellsByImportance 根据Cell内缓存的距离进行排序
        筛选出所有需要加入到world的cell并且设置优先级
        • UWorldPartitionRuntimeCell::SetStreamingPriority
          • ULevelStreaming::SetPriority
            • UWorld::UpdateStreamingLevelPriority FStreamingLevelsToConsider::Reevaluate
        计算Streaming性能进行限制
        • UWorldPartitionStreamingPolicy::UpdateStreamingPerformance 如果当前是BlockTillLevelStreaming则return
          • UWorldPartitionRuntimeHash::GetStreamingPerformance 遍历需要Activate的Cell,获取Cell的Performance,获取最严重等级的性能Level
            • UWorldPartitionRuntimeCell::GetStreamingPerformanceForCell 靠 现在好像全部返回的Good 😓

总结

综上所述WorldPartition本质上是一个WorldSubSystem,

并且通过Grid分层的方式动态管理了大量的子关卡(StreamingLevelDynamic)

然后最后还是走到StreamingLevel的逻辑里面。另一种方面说就是StreamingLevel的更上层包装

发表评论

邮箱地址不会被公开。 必填项已用*标注