![6948c4a4374ffc8e646b0a6c36938ba3.png](https://i-blog.csdnimg.cn/blog_migrate/20b14b19bf0b8f8a292bbe1fad2e06ce.jpeg)
写在前面
该系列文章主要介绍UE4 的关卡加载和流送机制。
适合的读者:
- 熟悉C++;
- 了解UE4 的LevelStreamingVolume 和WorldComposition;
- 想搞清楚其中的细节;
源码之下,了无秘密。——侯捷
目录结构
- 先从场景加载机制开始;
- 然后是LevelStreamingVolume 和WorldComposition;
场景加载机制
![8cacdc0cd00dfbce5c67ede2db059bd2.png](https://i-blog.csdnimg.cn/blog_migrate/fd1c5008797fee0eb2f3c5a48a7a8acd.jpeg)
异步Package加载:
这里统一的Package 加载逻辑。不展开讲,因为不是本文的研究重点。感兴趣的同学可以自行查阅AsyncLoading.cpp相关代码。
下面的LevelStreaming::RequestLevel将会用这个。
/**
* Asynchronously load a package and all contained objects that match context flags. Non-blocking.
* This version is useful when loading multiple copies of the same package.
*
* @param InName Name of package to load
* @param InGuid GUID of the package to load, or nullptr for "don't care"
* @param InPackageToLoadFrom If non-null, this is another package name. We load from this package name, into a (probably new) package named InName
* @param InCompletionDelegate Delegate to be invoked when the packages has finished streaming
* @param InPackageFlags Package flags used to construct loaded package in memory
* @param InPIEInstanceID Play in Editor instance ID
* @param InPackagePriority Loading priority
* @return Unique ID associated with this load request (the same package can be associated with multiple IDs).
*/
COREUOBJECT_API int32 LoadPackageAsync(const FString& InName, const FGuid* InGuid = nullptr, const TCHAR* InPackageToLoadFrom = nullptr, FLoadPackageAsyncDelegate InCompletionDelegate = FLoadPackageAsyncDelegate(), EPackageFlags InPackageFlags = PKG_None, int32 InPIEInstanceID = INDEX_NONE, TAsyncLoadPriority InPackagePriority = 0);
UWorld::UpdateLevelStreaming
场景加载的主要入口。
其中会遍历StreamingLevelsToConsider
,通过FStreamingLevelPrivateAccessor::UpdateStreamingState
,调用对应StreamingLevel 的ULevelStreaming::UpdateStreamingState
,根据StreamingLevel 的状态机,处理它的加/卸载、可见性。
// World.cpp
void UWorld::UpdateLevelStreaming()
{
// ...
StreamingLevelsToConsider.BeginConsideration();
TArray<FLevelStreamingWrapper> StreamingLevelsBeingConsidered = MoveTemp(StreamingLevelsToConsider.StreamingLevels);
for (int32 Index = StreamingLevelsBeingConsidered.Num() - 1; Index >= 0; --Index)
{
if (ULevelStreaming* StreamingLevel = StreamingLevelsBeingConsidered[Index].Get())
{
bool bUpdateAgain = true;
bool bShouldContinueToConsider = true;
while (bUpdateAgain && bShouldContinueToConsider)
{
bool bRedetermineTarget = false;
FStreamingLevelPrivateAccessor::UpdateStreamingState(StreamingLevel, bUpdateAgain, bRedetermineTarget);
if (bRedetermineTarget)
{
bS