找回密码
 立即注册
查看: 334|回复: 0

[笔记] [原创]UE基础—资源浅析

[复制链接]
发表于 2022-6-28 18:02 | 显示全部楼层 |阅读模式
资源系统是个很大的话题,本文只对资源做个简单概述,权当抛砖引玉。大概分以下几个话题:Asset,AssetRegistry,资源加载,资源管理; 当前引擎版本: UnrealEngine 4.27
Asset

要了解UE4的资源系统,首先要理解 Asset 到底是个啥。它是一种 "既可以被序列化成文件(.uasset、.umap) 保存在硬盘" , 又可以 "从硬盘加载然后反序列化到内存中(UObject)" 的对象 ,主要用来存贮游戏资源(比如:蓝图,贴图,骨骼,声音,特效等)
从硬盘加载资产文件以后,在内存中就可以把它当作UObject对象使用了;比如:UBlueprint、UTexture2D、USkeletalMesh、 USoundWave 等。你在"Content Browser"中看到的每个资产,都有对应的UObject类
资产既然可以被序列化成文件保存在硬盘,那它是以怎样的格式存储对象呢?打开 Edit Preferences ,  General->Experimental->Core->Text Asset Format Support (勾选) 。然后随便选中一个蓝图对象,右键 Asset Actions->Export to text format;在当前文件的同目录下,就有个同名的.utxt文件



.utxt就是资源存储的内容

用文本编辑器打开,就可以看到它的一些信息,这些信息是被简化过的,不过也能基本了解当前资源包含的内容。从Exports就可以看出,PlayerCharacter.uasset 包含很多内容,比如:PlayerCharacter(对象),PlayerCharacter_C(CDO),Default__PlayerCharacter_C (蓝图) 等,而这些内容反序列化到内存中也是以UPackage的方式放在一起
Asset总结
Asset就是UE4的资产,有两种形态:平常会以 .uasset、.umap文件的形式趴在硬盘种,而在被需要的时候,就能幻化成内存中的UPackage(描述了资产的全部细节,包括:资产简介,资产包含的对象,资产依赖的其他资产等)
Asset Registry

通过上文,我们对Asset应该有个大概的了解。平常它趴在项目目录下的硬盘中,那我们打开编辑器为啥在Content Browser 能看到所有资源呢?



content browser

难道是打开编辑器,就把所有.uasset加载到了编辑器内?肯定不可能,那它是怎么显示这些资源的简介信息呢,这就是 AssetRegistry 最直观的应用。官方的解释:
TheAsset Registryis an editor subsystem which gathers information about unloaded assets asynchronously as the editor loads. This information is stored in memory so the editor can create lists of assets without loading them. The information is authoritative and is kept up to date automatically as assets are changed in memory or files are changed on disk. TheContent Browseris the primary consumer for this system, but it may be used anywhere in editor code.
Asset Registry 是一个编辑器子系统,用于收集项目目录下那些没有被加载到内存中的资产的基本信息(主要工作原理就是扫描指定的目录,然后加载资产的 Summary 信息),它会把这些信息存储在内存中,它还会自动监听资产变动(改名,移动到其他目录,删除等操作)从而保持信息准确。因此 Content Browser 可以根据 Asset Registry 的内容,从而把资产显示出来(并未真的加载,只是利用了它的基本信息)
Asset Registry 对我们来说直接用到的地方不多,但是如果你经常做一些编辑器功能开发你可能对它不陌生
void FToolbarModule::StartupModule()
{
        //监听资源保存
        UPackage::PackageSavedEvent.AddRaw(this, &FToolbarModule::AssetSaved);
        //监听资源刷新
        IAssetRegistry::Get()->OnAssetUpdated().AddRaw(this, &FToolbarModule::AssetUpdate);
}
AssetRegistry 扫描资产生成的缓存会保在本地:C:\lingze\TestProject\Intermediate\AssetRegistryCache;打包后也会生成 AssetRegistry.bin文件。在移动设备运行游戏的时候,AssetRegistry 模块启动就会把 AssetRegistry.bin 加载到内存
UE4的技能插件(GAS)默认的 Cue 加载方式,就是通过 AssetRegistry 获取你在 ini 配置的 Cue 路径下的所有资产的 AssetData 然后加载。然而大部分情况下,游戏运行过程中不需要 AssetRegistry(GAS可以重载 Cue 的加载方式),因此如果为了节省运行时内存,可以通过ini中的配置关闭使用
DefaultEngine.ini
[AssetRegistry]
bSerializeAssetRegistry=false
bSerializeDependencies=false
bSerializeNameDependencies=false
bSerializeManageDependencies=false
bSerializePackageData=false Asset Registry总结
Asset Registry是一个通过扫描收集资产简单信息的系统;主要用途是在编辑器环境下,在 content browser下显示所有资产列表,同时还有下列用处:

  • 通过它能获取某一个路径下所有资产的基本信息
  • 能查询资产之间的依赖
  • 可用于加载资产
  • 在编辑器功能开发中经常被使用
资源加载

UE4加载资源的顺序是 SerializeSummary->CreateUObject->SerializeUObject->PostLoadUObject,大致过程如下:

  • 序列化文件头,获取资源的基础信息
  • 根据头讯息创建对应的C++层面的 UObject
  • 根据资产数据序列化填充 UObject
  • 调用PostLoad函数,标志在 UObject 层面的加载已经完毕
而加载方式有哪些呢?
引用加载(同步)
最常用的加载方式,分为硬引用(同步)和软引用(半同步:之所叫半同步是指当前资产不会自动加载,但使用时加载的方式依然是同步)
硬引用就是通过UPROPERTY宏的方式将变量暴露给蓝图,然后蓝图中直接将资产拖入。在当前蓝图被加载到内存的时候,变量对应的资产也会自动加载到内存中
UPROPERTY(EditDefaultsOnly)
AActor* TestObject;
软引用也是通过UPROPERTY宏的方式将变量暴露给蓝图,但是包装了一下,那具体有哪些类型呢?FSoftObjectPath,FSoftClassPath,FSoftObjectPtr,TSoftObjectPtr,TSoftClassPtr,别装了这些内容你肯定迷糊了
Object和Class有啥区别,为啥要整2套API?

  • Object是指对象本身,就是你拿到这个对象就可以直接用 (挂在玩家身上,让它在场景中移动等)
  • Class是指对象的类,一般用它生成新的对象(注意和对象本身做区分)
在MyActor对象内定义如下变量:
//直接引用,相当于蓝图上的 ObjectReference
UPROPERTY(BlueprintReadWrite,EditAnywhere)
AActor* TestObject;
//直接引用,相当于蓝图上的 ClassReference
UPROPERTY(BlueprintReadWrite,EditAnywhere)
UClass* TestClass;
//直接引用,相当于蓝图上的 ClassReference,但是限定了类型只能是Actor
UPROPERTY(BlueprintReadWrite,EditAnywhere)
TSubclassOf<AActor> TestSubClass;

//间接引用
UPROPERTY(BlueprintReadWrite,EditAnywhere)
FSoftObjectPath TestSoftObjectPath;
//间接引用
UPROPERTY(BlueprintReadWrite,EditAnywhere)
FSoftClassPath TestSoftClassPath;
//间接引用,效果相当于蓝图上的 SoftObjectReference
UPROPERTY(BlueprintReadWrite,EditAnywhere)
TSoftObjectPtr<AActor> TestSoftObjectPtr;
//直接引用,效果相当于蓝图上的 SoftClassReference
UPROPERTY(BlueprintReadWrite,EditAnywhere)
TSoftClassPtr<AActor> TestSoftClassPtr;
打开蓝图,能看到变量出现在属性列表内,我们逐一解释:

  • TestObject,在编辑器内不能赋值(不能直接选择对象);一般用来保存某个新生成或者已加载对象,MyActor生命周期内,TestObject引用的对象不会被GC
  • TestClass,可在编辑器直接赋值;可以是任意资产类型,一般用来Spawn对象,或者传递给函数使用
  • TestSubClass,和TestClass功能一样,但是限制了引用的资产类型必须是Actor
  • TestSoftObjectPath,可在编辑器直接赋值;保存了引用的对象的路径,不会自动加载对象。优点是可以做到用时再加载(TestSoftObjectPath.TryLoad()),蓝图内基本不会用到,因为它没有提供蓝图方法
  • TestSoftClassPath,同上;用来加载类(TestSoftClassPath.TryLoadClass<UObject>())
  • TestSoftObjectPtr,在编辑器内不能赋值(不能直接选择对象);一般用来当作临时变量保存某个对象,TestSoftObjectPtr 引用的对象是否会被GC与MyActor生命周期无关(TestSoftObjectPtr 其实就是对 FSoftObjectPath 和 FWeakObjectPtr 的包装 )
  • TestSoftClassPtr,可以在编辑器直接赋值;软引用某个对象类,与TestSoftObjectPtr功能类似,返回的是UClass(TestSoftClassPtr.Get() 直接返回UClass*)
构造函数加载(同步)
C++代码内调用,一般不建议使用,因为路径是写死的,不够灵活(只能在构造函数内使用)

  • ConstructorHelpers::FObjectFinder<T> 一般用来加载非蓝图资产
  • ConstructorHelpers::FClassFinder<T>    一般用来加载蓝图并获取蓝图Class
示例如下(static关键字一定要带上):
ATestActor::ATestActor(const FObjectInitializer& ObjectInitializer)
{
    static ConstructorHelpers::FClassFinder<AActor> TestClass(TEXT("/Game/BluePrint/TestObj"));  
    static ConstructorHelpers::FObjectFinder<UStaticMesh> TestMesh(TEXT("/Game/BluePrint/TestMesh"));
}
FStreamableManager加载(异步)
本质上是调用 LoadPackageAsync(),提供资产加载接口 LoadSynchronous(本质上是锁主线程然后调用异步接口), RequestAsyncLoad , RequestSyncLoad, 都是通过 FSoftObjectPath 去加载对象;卸载资产接口 Unload,ReleaseHandle
这也是最常用的资产管理接口,因为提供了异步接口因此可以错位加载,让游戏更平滑。很多类用它做内部加载方式,比如:AssetRegistry , UObjectLibrary
StaticLoadObject加载(同步)
本质上是调用 LoadPackage(), 目前用到的地方不多,属于比较老的API。这也是LoadObject,LoadClass这两个API的底层实现
资源管理

UE4内貌似没有资源管理框架的概念,想怎么用都可以,不过提供了 DataAsset 、AssetManager 这两种组织资产的方式
DataAsset(注意与AssetData的区别)
不知道DataAsset算不算一种资源管理,但它确实也是一种将资源集合在一起的方式。比如:某个英雄会用到的所有资源,可以集合在一个DataAsset内,从而选择不同的英雄的时候,只加载对应的英雄的资源,这样也算实现了简单的资源管理,有如下特点:

  • 需要手动定义DataAsset的数据结构,并且手动添加引用的数据
  • 针对不同资产可定义多个DataAsset
  • 可以被到处使用,类似一个DataTable
  • DataAsset只存储引用,并不同步加载所有数据
AssetManager
AssetManager 可以说是DataAsset的威力加强版,它也是目前官方推荐的资源管理的方式。会根据资产类型依靠 AssetRegistry 来加载对应资产,有如下特点:

  • 可用作UObjectLibrary的替代品
  • 可做到精确的资产加载和释放
  • 配置方式比较灵活(支持蓝图和C++配置)
  • AssetsRegistry的存在也使得登记、获取、过滤、监听资产更为便捷
但是它强依赖 AssetRegistry ,如果在运行时关闭了它或者cook的时候选择不被注册,那么可能导致加载不到资产的情况
总结

本文只是对UE4的资源系统做个简单概述,很多前辈对文章中的内容进行了更深入的讲解,以下就是一些文中使用到的链接,想了解更深入的内容可点击查看
AssetRegistry

  • 官方解释 Asset Registry
  • what is asset registry used for
  • UE 性能分析:内存优化
AssetManager

  • 官方视频讲解
  • UE4资产管理基础1 | Epic 大钊
  • 官方解释 AssetManager
  • 使用DataAsset引用资产然后加载
资源加载

  • quabqi:UE4的资源管理
  • 加载资源的方式 各种加载方式特点总结和选择

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

×
懒得打字嘛,点击右侧快捷回复 【右侧内容,后台自定义】
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Unity开发者联盟 ( 粤ICP备20003399号 )

GMT+8, 2024-5-3 19:03 , Processed in 0.116930 second(s), 27 queries .

Powered by Discuz! X3.5 Licensed

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表