> 文章列表 > UE资源加载

UE资源加载

UE资源加载

UE中资源文件和内存里对象的关系

UE4的资源,就是在工程文件夹下的哪些非代码资源,比如Content下面的网格,材质,蓝图这些文件,大部分是以uasset作为后缀的UE资源文件

UE资源加载

对于UE4来说,这个过程有下面这几个步骤

  1. 读取资源文件到内存
  2. 根据内存的二进制数据,把空壳对象反序列化成实际的对象
  3. Eugene这个对象有依赖其他的对象,就递归的去做1和2的操作,直到这个对象完整可用
  4. 调用对象的初始化函数,并将对象加入到引擎的对象管理中

加载对象和创建对象的区别?

  1. 加载对象实际上是在做反序列化,从而在内存中构造出对象
  2. 创建对象就是在调用类的构造函数从而在内存中构造出对象

资源的硬引用

硬性引用,即对象 A 引用对象 B,并导致对象 B 在对象 A 加载时加载。通俗点说,硬引用所表示的资源在引用初始化时就加载进内存,因此硬引用的资源几乎不需要加载方法。例如静态网格体组件对静态网格体的引用

资源的软引用

软性引用,即对象 A 通过间接机制(例如字符串形式的对象路径)来引用对象 B。
硬引用的问题是在容易一开始就加载全部硬引用表示的资源,这可能导致资源载入时间过长。而软引用则是可随时灵活加载资源的一种引用,而不用硬性地一开始就加载。UE中主要涉及到 FSoftObjectPath、FSoftClassPath、TSoftObjectPtrr< T >,TSoftClassPtr< T >,使用这些方式时,需要手动加载资源(同步/异步加载:LoadObject, StaticLoadObject,FStreamingManager)
引用资源最简单的方式就是创建指针UProperty并为他指定一个类别,这种称为硬指针

硬引用指针

在UE4中,如果有一个硬UObject指针属性引用了一个资源(往往在蓝图上设置引用),则加载包含这个属性的对象(放在贴图中,或者从gameinfo等引用)时,就会加载这个资源。

UPROPERTY(EditDefaultsOnly, Category=Building)
USoundCue* ConstructionStartStinger;

常用API

查找资源

  • FindObject
  • FindObjectFast
  • FindObjectChecked
  • FindObjectSafe
  • FSoftObjectPath::ResolveObject

同步加载资源

  • LoadObject
  • LoadClass
  • LoadPackage
  • FSoftObjectPath::TryLoad
  • FStreamableManager::RequestSyncLoad
  • FStreamableManager::LoadSynchronous
  • FlushAsyncLoading(异步转同步)

异步加载资源

  • LoadPackageAsync
  • FStreamableManager::RequestAsyncLoad

判断加载状态

  • GIsSavingPackage
  • IsGarbageCollectingOnGameThread
  • IsLoading
  • GetNumAsyncPackages
  • GetAsyncLoadPercentage
  • FStreamableManager::IsAsyncLoadComplete

查找资源

FObjectFinder / FClassFinder

若需要用C++代码而非蓝图来设置引用,则往往需要FObjectFinder、FClassFinder。
在UE4源码里面,FObjectFinder构造函数里通过调用LoadObject()来加载资源,而FClassFinder构造函数里调用的也是LoadObject()。

  1. 只能在类的构造函数中使用,如果在普通的逻辑代码中嵌套这份代码,会引起整个编译器的crash。(实际上里面代码就有检查是否在构造函数里,否则crash)
  2. 其次,FObjectFinder/FClassFinder变量必须是static的,从而保证只有一份资源实例。
    FObjectFinder:一般用来加载非蓝图资源,比如StaticMesh、Material、SoundWave、ParticlesSystem、AnimSequence、SkeletalMesh等资源:
static ConstructorHelpers::FObjectFinder<UTexture2D> ObjectFinder(TEXT("Texture2D'/Game/Textures/tex1.tex1'"));
UTexture2D* Texture2D = ObjectFinder.Object;

FClassFinder:一般用来加载蓝图资源并获取蓝图Class。这是因为如果C++要用蓝图创建对象,必须先获取蓝图的Class,然后再通过Class生成蓝图对象:

static ConstructorHelpers::FClassFinder<AActor> BPClassFinder(TEXT("/Game/Blueprints/MyBP"));
TSubclassOf<AActor> BPClass = BPClassFinder.Class;
...//利用Class生成蓝图对象
  • FClassFinder的模版名不能直接写UBlueprint,例如:FClassFinder是错误的。创建蓝图时选择的是什么父类,则写对应的父类名,假如是Actor,那么要写成:FClassFinder,否则无法加载成功。
  • FClassFinder的模版名必须和TSubclassOf变量的模版名一致,当然也可使用UClass代替TSubclassOf。实际上TSubclassOf也是UClass,只是更加强调这个Class是从T派生出来的。
    • 在启动游戏时若报错提示找不到文件而崩溃(例如:Default property warnings and errors:Error: COD Constructor (MyGameMode): Failed to find /Game/MyProject/MyBP.MyBP)
    • 这是因为UE4资源路径的一个规范问题,解决办法为:
      在copy reference出来的文件路径后面加_C,例如:“Blueprint’/Game/Blueprints/MyBP.MyBP_C’”(_C可以理解为获取Class的意思)。

FSoftObjectPaths、FStringAssetReference

  1. FSoftObjectPath:是一个简单的结构体,其中包含了资源的完整名称(一个字符串)。它实质就是用一个字符串来表示对应的资源,从而可以随时通过字符串找到硬盘上的目标资源,将其载入进内存。

FSoftObjectPath.SolveObject() 可以检查其引用的资源是否已经载入在内存中,若载入则返还资源对象指针,否则返还空。

FSoftObjectPath.IsPending() 可检查资源是否已准备好可供访问。而如何利用FSoftObjectPath加载资源进内存

TSoftObjectPtr

TSoftObjectPtr是包含了FSoftObjectPath的TWeakObjectPtr,可通过模板参数来设置特定资源类型,这样就可以限制编辑器UI仅允许选择特定的资源种类。

TSoftObjectPtr.Get() 可以检查其引用的资源是否已经载入在内存中,若已载入则返还资源对象指针,否则返还空。想要资源加载进内存,则可以调用ToSoftObjectPath()来得到FSoftObjectPaths用于加载。

同步加载资源

LoadObject/LoadClass

LoadObject():加载UObject,一般用来加载非蓝图资源。

UTexture2D* Texture2D  = LoadObject<UTexture2D>(nullptr,TEXT("Texture2D'/Game/Textures/tex1.tex1'"));

LoadClass():加载UClass,一般用来加载蓝图资源并获取蓝图Class。实际上源码里LoadClass的实现是调用LoadObject并获取类型。

TSubclassOf<AActor> BPClass = LoadClass<AActor>(nullptr, TEXT("/Game/Blueprints/MyBP_C"));

异步加载资源

首先,需要创建FStreamableManager,官方建议将它放在某类全局游戏单例对象中,例如使用GameSingletonClassName在DefaultEngine.ini中指定的对象。

  • FStreamableManager.RequestAsyncLoad():将异步加载一组资源并在完成后调用委托。
void UGameCheatManager::GrantItems()
{      //获取 FStreamableManager的单例对象引用FStreamableManager& Streamable = ...;//得到一组软引用TArray<FSoftObjectPath> ItemsToStream;for(int32 i = 0; i < ItemList.Num(); ++i)ItemsToStream.AddUnique(ItemList[i].ToStringReference());//根据一组软引用来异步加载一组资源,加载完后调用委托Streamable.RequestAsyncLoad(ItemsToStream, FStreamableDelegate::CreateUObject(this, &UGameCheatManager::GrantItemsDeferred));
}void UGameCheatManager::GrantItemsDeferred()
{//do something....
}

字体转换器