UE踩坑记 日志

UE5.5后world partition下level instance的加载机制

playerzhou 无回复

在5.5之前,对于level instance的加载机制见https://dev.epicgames.com/documentation/en-us/unreal-engine/level-instancing-in-unreal-engine ,当level instance使用了ofpa机制时,cook时会把level里的actor打散进cell中,表现与场景中普通actor一致,若未使用ofpa机制,则是以一整个完整的level为单位进行加载

但在5.5之后,对于未使用ofpa的level,在保存前,使用

void UWorld::GetExtendedAssetRegistryTagsForSave(const ITargetPlatform* TargetPlatform, TArray<FAssetRegistryTag>& OutTags) const
{
    Super::GetExtendedAssetRegistryTagsForSave(TargetPlatform, OutTags);

    if (!PersistentLevel->IsUsingExternalActors())
    {
        TArray<FString> ActorsMetaData;
        for (AActor* Actor : PersistentLevel->Actors)
        {
            if (IsValid(Actor) && Actor->SupportsExternalPackaging())
            {
                FWorldPartitionActorDescUtils::FActorDescInitParams ActorDescInitParams(Actor);
                ActorsMetaData.Add(ActorDescInitParams.ToString());
            }
        }

        if (ActorsMetaData.Num())
        {
            static FName NAME_ActorsMetaData(TEXT("ActorsMetaData"));
            const FString ActorsMetaDataStr = FString::Join(ActorsMetaData, TEXT(";"));
            OutTags.Add(UObject::FAssetRegistryTag(NAME_ActorsMetaData, ActorsMetaDataStr, UObject::FAssetRegistryTag::TT_Hidden));
        }
    }
}

为level的package增加ActorsMetaData数据,将actor的信息存在package内,world partition持有的actordesccontainer初始化时

void UActorDescContainer::Initialize(const FInitializeParams& InitParams)
{
    // 省略上文

        // Gather external actors
        {
            TRACE_CPUPROFILER_EVENT_SCOPE(GetExternalAssets);

            FARFilter Filter;
            Filter.bRecursivePaths = true;
            Filter.bIncludeOnlyOnDiskAssets = true;
            Filter.PackagePaths.Add(*ContainerExternalActorsPath);

            FExternalPackageHelper::GetSortedAssets(Filter, ExternalAssets);
        }

        // Gather non-external actors
        {
            TRACE_CPUPROFILER_EVENT_SCOPE(GetInternalAssets);

            FARFilter Filter;
            Filter.bIncludeOnlyOnDiskAssets = true;
            Filter.PackageNames.Add(ContainerPackageName);

            TArray<FAssetData> WorldAssetData;
            AssetRegistry.GetAssets(Filter, WorldAssetData);

            // Transform world assets
            static FName NAME_ActorsMetaData(TEXT("ActorsMetaData"));
            for (const FAssetData& AssetData : WorldAssetData)
            {
                FString ActorsMetaDataStr;
                if (AssetData.GetTagValue(NAME_ActorsMetaData, ActorsMetaDataStr))
                {
                    TArray<FString> ActorsMetaData;
                    if (ActorsMetaDataStr.ParseIntoArray(ActorsMetaData, TEXT(";")))
                    {
                        InternalAssets.Append(ActorsMetaData);
                    }
                }
            }
        }
    }

    // 省略下文
}

ActorsMetaData中提取actor数据,用于生成actor desc,之后cook时即可通过actor desc将level里的actor打散至cell中

至此,对于5.5之后版本创建的level来说,无论是否开启ofpa,当其作为level instance导入world partition场景中时,它都将使用Embedded Mode,将level拆散。

但对于5.5之前创建的level,由于缺少ActorsMetaData,仍然使用Level Streaming Mode,以完整的level为单位进行加载,并且只需重新保存即可为level生成ActorsMetaData,从而使用Embedded Mode

来一发吐槽

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据