Loading

【UE4】加载资源的方式(九)各种加载方式特点总结和选择

【UE4】加载资源的方式(九)各种加载方式特点总结和选择

参考文章&参考资料&原文链接

UE4中资源的引用

UE4的资源管理

前面几篇文章介绍了各种各样资源的加载方式,现在就来对它们进行一个总结。以后就当工具查了,忘了就回来看一眼。

参考了很多大佬的博客,也自己手动写代码感受也一下他们的异同(所有的文章参考了哪部分都有注明),确实资源加载要做到很好的管理不是一件容易的事。这是前面的文章:

【UE4】加载资源的方式(一)使用引用进行简单加载

【UE4】加载资源的方式(二)使用StaticLoadClass和StaticLoadObject来加载

【UE4】加载资源的方式(三)使用ConstructorHelpers来加载

【UE4】加载资源的方式(四)使用DataAsset引用然后加载

【UE4】加载资源的方式(五)使用ObjectLibrary引用然后加载

【UE4】加载资源的方式(六)使用StreamableManager进行加载

【UE4】加载资源的方式(七)使用AssetManager进行加载

【UE4】08_加载资源的方式(八)关于资产引用的各种Path和Ptr介绍

有关概念

需要了解的概念是:

  • 路径索引的意义。例如:

    v2-85372c13737c85fa7ade48123dddebcc_720w

  • 引用的概念、作用及其分类,它们的优缺点及适用场景。

  • 资源加载的大致步骤。

  • 同步加载、异步加载、回调函数、静态加载和动态加载的概念,加载的总入口函数是什么。

  • 常用的资源加载与卸载函数及它们的参数。

  • 主资源、次资源、主资源标签、资产注册的概念。

简单引用

分为软性引用、硬性引用、构造时引用、强引用和弱引用。

基本方式

UE4 4.18版本之前:

FStringAssetReferenceFStringClassReferenceFAssetPtrTAssetPtrTAssetSubclassOf

UE4. 4.18版本之后:

FSoftObjectPathFSoftClassPathFSoftObjectPtrTSoftObjectPtrTSoftClassPtr

推荐使用最新的引用方式。

特点

  • 对美术师或设计师来说十分友好,他们可以在蓝图中直接使用,可以直接实时预览效果。
  • 可以考虑使用DataAsset来存储引用,统一管理。
  • 可以用UPROPERTY()宏的meta = (AllowedClasses ="Material,StaticMesh")筛选UE原生的资源类型,用meta = (MetaClass = "MyActor")则可以筛选自定义继承UObject的类型。

注意

  • 需要熟悉它们定义和区别,以及它们之间的联系和区别,例如4.18之前是用的哪几个,在4.18及之后又改成了什么。

  • 硬性引用资产过大时要注意性能问题。可以考虑用弱引用,然后再在合适的地方异步加载。

  • 有些引用有模板类,十分方便。例如:TSoftObjectPtrTSubclassOf

  • 对于FSoftObjectPath来说:可以使用UPROPERTY(meta=(AllowedClasses="Material,StaticMesh"))来筛选原生的UE4特定的类型。

  • 对于FSoftClassPath来说:要筛选我们自定义继承UObject的类型可以使用UPROPERTY(meta = (MetaClass = "MyActor"))来筛选。

  • 在使用之前用IsPendingIsValid检查是否设置了引用以及引用的资源是否已经准备好是一个好习惯。

  • 如果引用是以字符串的形式直接写在代码里面的话,例如:

     static ConstructorHelpers::FClassFinder<APawn> PlayerPawnBPClass(TEXT("/Game/ThirdPersonCPP/Blueprints/ThirdPersonCharacter"));
    

    那么在构建版本时,并不会将该引用cook进包中,这是个巨坑,可以考虑使用DataAsset来统一处理。

    如果没有用DataAsset的话那么就需要手动指定,让该资源打进包中。在DefaultGame.ini的文件的/Script/UnrealEd.ProjectPackagingSettings标签的DirectoriesToAlwaysCook数组中配置包含该资源的目录。例如:

    [/Script/UnrealEd.ProjectPackagingSettings]
    +DirectoriesToAlwaysCook=(Path="/Game/ThirdPersonCPP/Blueprints")
    

    与指定字符串路径相比,当在编辑器中对被软引用到的资源进行移动、改名等操作时,ue4会进行自动调整。

  • 强引用是自动加载资源的,弱引用可能已经加载了可能没加载,如果没加载的话需要我们手动加载。强引用和弱引用的区别:

    UCLASS(config=Game)
    class AMyTest1Character : public ACharacter
    {
        GENERATED_BODY()
        
        // ... ...
        
    public:
        UPROPERTY(Category = MyTest1, EditAnywhere) TSoftObjectPtr<UTexture2D> SourceTexture1; // 软引用
        UPROPERTY(Category = MyTest1, EditAnywhere) UTexture2D* SourceTexture2; // 硬引用
    };
    

    在Referece Viewer中,粉色的线为弱引用,白色的线为强引用:

    img

Load

是同步加载资源的一种方式。其中的LoadPackageAsync是整个UE资源加载的大入口。

特点

  • 不论加载的是UObject还是UClass,其本质都是使用路径加载,即必须知道完整路径。
  • 支持加载的UObject的类型很多。例如Texture、Material、SoundWave、SoundCue、ParticlesSystem、AnimMontage、BlendSpace(1D,2D,3D)、AnimSequence、AnimBlueprint、SkeletalMesh等等。

注意

  • LoadClassStaticLoadClassLoadObjectStaticLoadObject这几个函数的联系与区别。
  • 同步加载注意大资源可能会引起的卡顿和掉帧。
  • 需要路径不能出错,蓝图则需要加上_C

ConstructorHelpers

特点

  • 同样是需要完整路径的一种加载方式。
  • 只能在构造函数里面使用,非构造函数中使用会引起Error。这适用于某些情况,例如要使用这个资源的时候必须加载另一种资源,这个时候就可以考虑在构造函数中使用ConstructorHelpers。

注意

  • ConstructorHelpers 只能在构造函数中使用。如果在非构造函数中使用的话,则会引起Crash(原因不明),在其代码内部检查了是否在构造函数中调用:CheckIfIsInConstructor(ObjectToFind);
  • ConstructorHelpers 前面必须加上static
  • 同样的,代码里面的AMyCharacter都可以换成AActor,只是个人更推荐写AMyCharacter,因为AMyCharacterBP_MyCharacter的最直接的父类。
  • FObjectFinder()是对LoadObject()的封装。但是FClassFinder()不是对LoadClass()的封装,FClassFinder()内部调用的是LoadObject()。

DataAsset

UDataAsset包含一个简单资源数据的基类。如果您继承了这个类,编辑器将在content browser中列出它。这个相当于Unity Asset文件,可以用来存储数据。

特点

  • 不过手动定义数据结构的话灵活性极大,并且可以定义多种不同的数据。

  • 这种方式似乎类似于用DataTable数据驱动开发,就像一个配置表一样。DataTable也需要自定义数据类型。

  • 有了这个不是写在代码里的显示引用,UE就能自动帮我们处理,比如在重定向的时候就会自动处理。

  • 一个DataAsset可以给很多个蓝图使用,只需要使用UPROPOERTY宏。

  • 由于能直观的的看到引用的数据,因此同样对设计师或美术师十分友好。例如:

    image-20211104215031211

注意

  • 需要继承自UDataAsset类,并手动定义DataAsset的数据结构,并且要手动添加需要的数据的引用,稍显麻烦。
  • DataAsset只是存储引用,并不是真正的加载数据,加载数据是用的其他方法。

ObjectLibrary

ObjectLibrary:是一个对象,包含了一系列继承共享基类的未加载对象或者未加载对象的FAssetData 。您可以通过提供一个搜索路径来加载一个对象库,它将加载那个路径中的所有资源。

其实里面就只是放了一个FAssetData

特点

  • 同样的,他也只是记录路径,加载是靠其他方法,当然你要是想用它自带的方法加载也可以- -。
  • 其内部只是一个DataAsset而已,只不过不一样的是我们不需要自定义数据结构来记录资产路径,而是需要给它一个扫描路径和扫描类型,那么它就会帮我们记录,就不用我们一个一个手动的添加了。

注意

  • 需要用CreateLibrary函数来扫描指定的资源类型和资源路径(注意添加到根节点放置GC)。
  • 再用GetAssetDataList来获取扫描的结果,传入一个TArray<FAssetData>的引用来获得所有的路径,这个路径就是传入扫描的路径。
  • 最后使用路径可以按需加载。

StreamableManager

用于管理流资产并将其保存在内存中的本机类。AssetManager是具有蓝图访问权的全局单例版本。

在UE中可以直接用的写法:UAssetManager::GetStreamableManager()

核心是一个共享内存指针得到句柄 TSharedPtr<FStreamableHandle>* RequestHandlePointer ,用它来控制资源的释放。

加载单个资源:LoadSynchronous

同步加载:RequestSyncLoad

异步加载:RequestAsyncLoad

资源卸载:Unload

特点

  • 可以加载单个资源,也可以加载一组资源。
  • 同时支持同步加载和异步加载两种方式,选择和控制灵活多变。
  • 使用返回的Handle以控制资源的释放。

注意

  • 注意同步加载代码会一直停在那一行等待范围Handle,而异步加载则有个回调函数以供执行后续操作。
  • 资源加载完毕了要用Get取,第二次调用Get则会取消引用。

AssetManager

需要弄清楚主资源、次资源和主资源标签的概念。

调用 GetPrimaryAssetId 即可获得此主资源ID。覆盖GetPrimaryAssetId函数以让次资源成为主资源。

ScanPathForPrimaryAssets来扫描路径列表,读取指定类型的所有主资产的资产数据。

LoadPrimaryAssetsLoadPrimaryAssetLoadPrimaryAssetsWithType 可用于在适当的时间开始加载主资源。

UnloadPrimaryAssetsUnloadPrimaryAssetUnloadPrimaryAssetsWithType 进行卸载。

资源需要注册,注册资源有两种方式,一种是在引擎里面注册,一种是在代码里面注册。这里需要注意的是数组元素里有一项是PrimaryAssetType,这项的值必须与注册的资源返回的Id参数AssetType的TEXT值一致。

特点

  • 被认为是UObjectLibrary的替代品,从上面的实践来说确实很不错。
  • 确实可以很精确的控制资源的加载和释放的时机。
  • 配置非常给力精确。
  • AssetsRegistry的存在也使得登记、获取、过滤、监听资产更为便捷。

注意

  • 需要覆盖方法,返回一个ID。使次资源变为主资源。
  • 加载和卸载的函数及参数。
  • 资源注册的两种方式以及配置参数。

本文标签

游戏开发游戏开发基础Unreal EngineUE资源加载

posted @ 2021-11-26 23:13  多思考多实践同等重要  阅读(6424)  评论(0编辑  收藏  举报