【虚幻引擎】UE4 同步和异步资源加载(软引用)
迪丽瓦拉
2025-05-31 02:52:05
0

一、引用介绍

虚幻引擎给我们提供了两种引用,一个是硬引用。软引用通常是仅储存资源对象的资源路径没有与资源产生耦合关系的引用(软引用加载到内存中,引用对象不会被加载到内存中,只有在需要的时候才会被加载进内存中)。硬引用则是拥有资源对象实际成员变量,直接与资源对象产生耦合(硬引用被加载到内存中,则被引用的对象资源也会被加载到内存中)。

在UE4开发中经常性需要获取一些资源(StaticMesh,Material,Particle,Datatable, Actor蓝图,各种继承UObject的蓝图等等)的路径,然后利用这些路径进行资源的加载。

蓝图类资源,也就是BlueprintClass,继承于UObject并且蓝图化的资源。

 非蓝图类资源:UTexture,UStaticMesh,UParticleSystem,UMaterialInterface这些资源:如纹理,粒子,静态网格,材质等等。

 二、软引用

在UE4中,我们常用的软引用有以下四种 FSoftObjectPath、FSoftClassPath、FSoftObjectPtr、TSubclassOf 这四个。

FSoftObjectPath:翻译成“软对象路径”,也就是在一个(UObject,UStruct,Actor,ActorCompoennt)对象中配置一个具体资源(非蓝图资源和蓝图资源都可以)的路径,当这个对象被加载的时候,FSoftObjectPath指向的资源未被加载,仅仅是提供了一个路径。

蓝图中的应用:

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ftr")FSoftObjectPath AssetObjectPath;

如果我们需要某些特定的资源路径,可以使用元数据,meta = (AllowedClasses ="Material,StaticMesh"),他就只会选择你设置的类型 ,

注意1:FSoftObjectPath用AllowedClasses 只能筛选"Material,StaticMesh,Particle等资源

注意2:Material,StaticMesh类型之间不能有空格

 FSoftClassPath:对蓝图资源的一种弱引用,类似FSoftObjectPath,继承自FSoftObjectPath,可以说是FSoftObjectPath的进一步封装,不过这里是蓝图资源,指向了蓝图资源的路径,通过路径我们可以手动加载。

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ftr")FSoftClassPath AssetClassPath;

本质是FSoftClassPath指向的资源的路径为FSoftObjectPath的指向资源路径的子集 

TSoftObjectPtr:软对象指针用于在异步加载并且资源加载完成触发回调函数的时候获取资源对应的对象指针用的,毕竟异步加载是无法直接获取对象指针的。

//软引用获得资源对象的指针,仅储存资源对象的资源路径没有与资源产生耦合关系的引用//(软引用加载到内存中,引用对象不会被加载到内存中,只有在需要的时候才会被加载进内存中)UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ptr")TSoftObjectPtr softActorobj;

 TSoftClassPtr:检测蓝图资源加载,获取蓝图资源对应的指针

UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Ptr")TSoftClassPtr softActorClass;

同样的可以直接用TSoftObjectPtr来获取UClass的指针,因为UClass本身就是UObject的子类。

三、同步加载

在UE4中使用同步加载RequestSyncLoad和异步加载RequestASyncLoad,就要提到一个类FStreamableManager,用于管理流资产并将其保存在内存中的本机类。

第一种同步加载的方式RequestSyncLoad

源码分析:

TSharedPtr FStreamableManager::RequestSyncLoad(const FSoftObjectPath& TargetToStream, bool bManageActiveHandle, FString DebugName)
{return RequestSyncLoad(TArray{TargetToStream}, bManageActiveHandle, MoveTemp(DebugName));
}

参数解释:

  • TargetsToStream要加载的资产磁盘。
  • bManageActiveHandle如果为true,管理器将保持流句柄活动,直到显式释放。
  • DebugName此句柄的名称,将在调试工具中报告。

测试案例介绍:

FSoftObjectPath Path2 = FString(TEXT("Texture2D'/Game/StarterContent/Textures/T_Brick_Clay_Beveled_M.T_Brick_Clay_Beveled_M'"));//注意:在资源未完成加载之前代码会在这一行暂停运行以等待资源加载完成。TSharedPtr SyncStreamableHandle2 = UAssetManager::GetStreamableManager().RequestSyncLoad(Path2);if (SyncStreamableHandle2){//使用RequestSyncLoad(方法加载单个资源的时候要用GetLoadedAsset来获得FStreamableHandle中返回的资源。UTexture2D* Image2 = Cast(SyncStreamableHandle2->GetLoadedAsset());if (Image2){UE_LOG(LogTemp, Warning, TEXT("Image2 is %s"), *Image2->GetName());}}

注意:资源的引用在Content Browser中右键该资产,再选择Copye Reference即可复制路径

结果:

 

同步加载资源组:

源码分析:

/** * Synchronously load a set of assets, and return a handle. This can be very slow and may stall the game thread for several seconds.* * @param TargetsToStream		Assets to load off disk* @param bManageActiveHandle	If true, the manager will keep the streamable handle active until explicitly released* @param DebugName				Name of this handle, will be reported in debug tools*/
TSharedPtr RequestSyncLoad(TArray TargetsToStream, bool bManageActiveHandle = false, FString DebugName = TEXT("RequestSyncLoad Array"));

参数解释:

  • TargetsToStream要加载的资产磁盘。
  • bManageActiveHandle如果为true,管理器将保持流句柄活动,直到显式释放。
  • DebugName此句柄的名称,将在调试工具中报告。

案例测试: 

//同步加载资源组TArray Paths;Paths.AddUnique(FString(TEXT("Texture2D'/Game/StarterContent/Textures/T_Brick_Clay_Beveled_N.T_Brick_Clay_Beveled_N'")));Paths.AddUnique(FString(TEXT("Texture2D'/Game/StarterContent/Textures/T_Brick_Clay_New_D.T_Brick_Clay_New_D'")));//注意:在资源未完成加载之前代码会在这一行暂停运行以等待资源加载完成。TSharedPtr SyncStreamableHandle3 = UAssetManager::GetStreamableManager().RequestSyncLoad(Paths);if (SyncStreamableHandle3){TArrayLoadedAssets;SyncStreamableHandle3->GetLoadedAssets(LoadedAssets);if (LoadedAssets.Num() > 0){for (int32 i = 0; i < LoadedAssets.Num(); i++){UTexture2D* Image3 = Cast(LoadedAssets[i]);if (Image3){UE_LOG(LogTemp, Warning, TEXT("Image3 is %s"), *Image3->GetName());}}}}

注意,使用这个方法加载单个资源的时候要用GetLoadedAsset来获得FStreamableHandle中返回的资源。 

结果:

同步加载单个资源LoadSynchronous ,实际上是对RequestSyncLoad的一层封装

源码分析:

UObject* LoadSynchronous(const FSoftObjectPath& Target, bool bManageActiveHandle = false, TSharedPtr* RequestHandlePointer = nullptr);/** Typed wrappers */template< typename T >T* LoadSynchronous(const FSoftObjectPath& Target, bool bManageActiveHandle = false, TSharedPtr* RequestHandlePointer = nullptr){return Cast(LoadSynchronous(Target, bManageActiveHandle, RequestHandlePointer) );}template< typename T >T* LoadSynchronous(const TSoftObjectPtr& Target, bool bManageActiveHandle = false, TSharedPtr* RequestHandlePointer = nullptr){return Cast(LoadSynchronous(Target.ToSoftObjectPath(), bManageActiveHandle, RequestHandlePointer));}

案例测试:

//同步加载单个资源LoadSynchronousFSoftObjectPath Path =FString(TEXT("Texture2D'/Game/StarterContent/Textures/T_Brick_Clay_Beveled_D.T_Brick_Clay_Beveled_D'"));UTexture2D* Image = UAssetManager::GetStreamableManager().LoadSynchronous(Path,false,nullptr);if (Image){UE_LOG(LogTemp,Warning,TEXT("Image is %s"),*Image->GetName());}

结果:

注意:该方法或许适用于较小对象,但可能会导致主线程长时间停滞。在这种情况下,您将需要使用RequestAsyncLoad,它将异步加载一组资源并在完成后调用委托。 

四、异步加载 

UE4异步加载RequestAsyncLoad

源码分析:

/** * This is the primary streamable operation. Requests streaming of one or more target objects. When complete, a delegate function is called. Returns a Streamable Handle.** @param TargetsToStream		Assets to load off disk* @param DelegateToCall		Delegate to call when load finishes. Will be called on the next tick if asset is already loaded, or many seconds later* @param Priority				Priority to pass to the streaming system, higher priority will be loaded first* @param bManageActiveHandle	If true, the manager will keep the streamable handle active until explicitly released* @param bStartStalled			If true, the handle will start in a stalled state and will not attempt to actually async load until StartStalledHandle is called on it* @param DebugName				Name of this handle, will be reported in debug tools*/TSharedPtr RequestAsyncLoad(TArray TargetsToStream, FStreamableDelegate DelegateToCall = FStreamableDelegate(), TAsyncLoadPriority Priority = DefaultAsyncLoadPriority, bool bManageActiveHandle = false, bool bStartStalled = false, FString DebugName = TEXT("RequestAsyncLoad ArrayDelegate"));TSharedPtr RequestAsyncLoad(const FSoftObjectPath& TargetToStream, FStreamableDelegate DelegateToCall = FStreamableDelegate(), TAsyncLoadPriority Priority = DefaultAsyncLoadPriority, bool bManageActiveHandle = false, bool bStartStalled = false, FString DebugName = TEXT("RequestAsyncLoad SingleDelegate"));

参数解释:

  • TargetsToStream要加载的资产磁盘。

DelegateToCall委托在加载完成时调用。将被调用在下一个Tick,如果资产已加载,或许多秒后。

  • Priority优先级传递给流系统,优先级高的将首先加载。
  • bManageActiveHandle如果为true,管理器将保持流句柄活动,直到显式释放。
  • bStartStalled如果为true,句柄将以停滞状态启动,并且在调用StartStalledHandle之前不会尝试实际异步加载。
  • DebugName此句柄的名称,将在调试工具中报告。

案例测试

	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Test")TArray> ObjectPtrs;TSharedPtr ASyncStreamableHandle2;void AsyncLoadCompleted();

蓝图资源配置

 

//异步加载单个资源FSoftObjectPath Path4 = TEXT("Texture2D'/Game/StarterContent/Textures/T_Ceramic_Tile_M.T_Ceramic_Tile_M'");TSharedPtr ASyncStreamableHandle = UAssetManager::GetStreamableManager().RequestAsyncLoad(Path4);if (ASyncStreamableHandle){UTexture2D* Image4 = Cast(ASyncStreamableHandle->GetLoadedAsset());if (Image4){UE_LOG(LogTemp, Warning, TEXT("Image4 is %s"), *Image4->GetName());}}//异步加载资源组TArrayPaths2;for (auto item:ObjectPtrs){Paths2.AddUnique(item.ToSoftObjectPath());//ToSoftObjectPath()返回的是一个智能指针}ASyncStreamableHandle2 = UAssetManager::GetStreamableManager().RequestAsyncLoad(Paths2, FStreamableDelegate::CreateUObject(this, &AMyActor::AsyncLoadCompleted));
}void AMyActor::AsyncLoadCompleted()
{if (ASyncStreamableHandle2){TArrayObjectArray;ASyncStreamableHandle2->GetLoadedAssets(ObjectArray);if (ObjectArray.Num()>0){for (int i = 0; i < ObjectArray.Num(); i++){UTexture2D* Image5 = Cast(ObjectArray[i]);UE_LOG(LogTemp, Warning, TEXT("Image5 is %s"), *Image5->GetName());}}}
}

结果:

异步加载单个资源

异步加载资源组

 

 

相关内容

热门资讯

linux入门---制作进度条 了解缓冲区 我们首先来看看下面的操作: 我们首先创建了一个文件并在这个文件里面添加了...
C++ 机房预约系统(六):学... 8、 学生模块 8.1 学生子菜单、登录和注销 实现步骤: 在Student.cpp的...
A.机器学习入门算法(三):基... 机器学习算法(三):K近邻(k-nearest neigh...
数字温湿度传感器DHT11模块... 模块实例https://blog.csdn.net/qq_38393591/article/deta...
有限元三角形单元的等效节点力 文章目录前言一、重新复习一下有限元三角形单元的理论1、三角形单元的形函数(Nÿ...
Redis 所有支持的数据结构... Redis 是一种开源的基于键值对存储的 NoSQL 数据库,支持多种数据结构。以下是...
win下pytorch安装—c... 安装目录一、cuda安装1.1、cuda版本选择1.2、下载安装二、cudnn安装三、pytorch...
MySQL基础-多表查询 文章目录MySQL基础-多表查询一、案例及引入1、基础概念2、笛卡尔积的理解二、多表查询的分类1、等...
keil调试专题篇 调试的前提是需要连接调试器比如STLINK。 然后点击菜单或者快捷图标均可进入调试模式。 如果前面...
MATLAB | 全网最详细网... 一篇超超超长,超超超全面网络图绘制教程,本篇基本能讲清楚所有绘制要点&#...
IHome主页 - 让你的浏览... 随着互联网的发展,人们越来越离不开浏览器了。每天上班、学习、娱乐,浏览器...
TCP 协议 一、TCP 协议概念 TCP即传输控制协议(Transmission Control ...
营业执照的经营范围有哪些 营业执照的经营范围有哪些 经营范围是指企业可以从事的生产经营与服务项目,是进行公司注册...
C++ 可变体(variant... 一、可变体(variant) 基础用法 Union的问题: 无法知道当前使用的类型是什...
血压计语音芯片,电子医疗设备声... 语音电子血压计是带有语音提示功能的电子血压计,测量前至测量结果全程语音播报࿰...
MySQL OCP888题解0... 文章目录1、原题1.1、英文原题1.2、答案2、题目解析2.1、题干解析2.2、选项解析3、知识点3...
【2023-Pytorch-检... (肆十二想说的一些话)Yolo这个系列我们已经更新了大概一年的时间,现在基本的流程也走走通了,包含数...
实战项目:保险行业用户分类 这里写目录标题1、项目介绍1.1 行业背景1.2 数据介绍2、代码实现导入数据探索数据处理列标签名异...
记录--我在前端干工地(thr... 这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前段时间接触了Th...
43 openEuler搭建A... 文章目录43 openEuler搭建Apache服务器-配置文件说明和管理模块43.1 配置文件说明...