【UE4】加載資源的方式(九)各種加載方式特點總結和選擇
參考文章&參考資料&原文鏈接
前面幾篇文章介紹了各種各樣資源的加載方式,現在就來對它們進行一個總結。以后就當工具查了,忘了就回來看一眼。
參考了很多大佬的博客,也自己手動寫代碼感受也一下他們的異同(所有的文章參考了哪部分都有注明),確實資源加載要做到很好的管理不是一件容易的事。這是前面的文章:
【UE4】加載資源的方式(二)使用StaticLoadClass和StaticLoadObject來加載
【UE4】加載資源的方式(三)使用ConstructorHelpers來加載
【UE4】加載資源的方式(四)使用DataAsset引用然后加載
【UE4】加載資源的方式(五)使用ObjectLibrary引用然后加載
【UE4】加載資源的方式(六)使用StreamableManager進行加載
【UE4】加載資源的方式(七)使用AssetManager進行加載
【UE4】08_加載資源的方式(八)關於資產引用的各種Path和Ptr介紹
有關概念
需要了解的概念是:
-
路徑索引的意義。例如:
-
引用的概念、作用及其分類,它們的優缺點及適用場景。
-
資源加載的大致步驟。
-
同步加載、異步加載、回調函數、靜態加載和動態加載的概念,加載的總入口函數是什么。
-
常用的資源加載與卸載函數及它們的參數。
-
主資源、次資源、主資源標簽、資產注冊的概念。
簡單引用
分為軟性引用、硬性引用、構造時引用、強引用和弱引用。
基本方式
在UE4 4.18
版本之前:
FStringAssetReference
、FStringClassReference
、FAssetPtr
、TAssetPtr
、TAssetSubclassOf
。
UE4. 4.18
版本之后:
FSoftObjectPath
、FSoftClassPath
、FSoftObjectPtr
、TSoftObjectPtr
、TSoftClassPtr
。
推薦使用最新的引用方式。
特點
- 對美術師或設計師來說十分友好,他們可以在藍圖中直接使用,可以直接實時預覽效果。
- 可以考慮使用
DataAsset
來存儲引用,統一管理。 - 可以用
UPROPERTY()
宏的meta = (AllowedClasses ="Material,StaticMesh")
篩選UE原生的資源類型,用meta = (MetaClass = "MyActor")
則可以篩選自定義繼承UObject
的類型。
注意
-
需要熟悉它們定義和區別,以及它們之間的聯系和區別,例如4.18之前是用的哪幾個,在4.18及之后又改成了什么。
-
硬性引用資產過大時要注意性能問題。可以考慮用弱引用,然后再在合適的地方異步加載。
-
有些引用有模板類,十分方便。例如:
TSoftObjectPtr
、TSubclassOf
。 -
對於
FSoftObjectPath
來說:可以使用UPROPERTY(meta=(AllowedClasses="Material,StaticMesh"))
來篩選原生的UE4特定的類型。 -
對於
FSoftClassPath
來說:要篩選我們自定義繼承UObject
的類型可以使用UPROPERTY(meta = (MetaClass = "MyActor"))
來篩選。 -
在使用之前用
IsPending
或IsValid
檢查是否設置了引用以及引用的資源是否已經准備好是一個好習慣。 -
如果引用是以字符串的形式直接寫在代碼里面的話,例如:
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中,粉色的線為弱引用,白色的線為強引用:
Load
是同步加載資源的一種方式。其中的LoadPackageAsync
是整個UE資源加載的大入口。
特點
- 不論加載的是UObject還是UClass,其本質都是使用路徑加載,即必須知道完整路徑。
- 支持加載的UObject的類型很多。例如Texture、Material、SoundWave、SoundCue、ParticlesSystem、AnimMontage、BlendSpace(1D,2D,3D)、AnimSequence、AnimBlueprint、SkeletalMesh等等。
注意
LoadClass
與StaticLoadClass
、LoadObject
與StaticLoadObject
這幾個函數的聯系與區別。- 同步加載注意大資源可能會引起的卡頓和掉幀。
- 需要路徑不能出錯,藍圖則需要加上
_C
。
ConstructorHelpers
特點
- 同樣是需要完整路徑的一種加載方式。
- 只能在構造函數里面使用,非構造函數中使用會引起Error。這適用於某些情況,例如要使用這個資源的時候必須加載另一種資源,這個時候就可以考慮在構造函數中使用ConstructorHelpers。
注意
ConstructorHelpers
只能在構造函數中使用。如果在非構造函數中使用的話,則會引起Crash(原因不明),在其代碼內部檢查了是否在構造函數中調用:CheckIfIsInConstructor(ObjectToFind);
。ConstructorHelpers
前面必須加上static
。- 同樣的,代碼里面的
AMyCharacter
都可以換成AActor
,只是個人更推薦寫AMyCharacter
,因為AMyCharacter
是BP_MyCharacter
的最直接的父類。 - FObjectFinder()是對LoadObject()的封裝。但是FClassFinder()不是對LoadClass()的封裝,FClassFinder()內部調用的是LoadObject()。
DataAsset
UDataAsset
包含一個簡單資源數據的基類。如果您繼承了這個類,編輯器將在content browser中列出它。這個相當於Unity Asset文件,可以用來存儲數據。
特點
-
不過手動定義數據結構的話靈活性極大,並且可以定義多種不同的數據。
-
這種方式似乎類似於用DataTable數據驅動開發,就像一個配置表一樣。DataTable也需要自定義數據類型。
-
有了這個不是寫在代碼里的顯示引用,UE就能自動幫我們處理,比如在重定向的時候就會自動處理。
-
一個DataAsset可以給很多個藍圖使用,只需要使用UPROPOERTY宏。
-
由於能直觀的的看到引用的數據,因此同樣對設計師或美術師十分友好。例如:
注意
- 需要繼承自
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
來掃描路徑列表,讀取指定類型的所有主資產的資產數據。
用 LoadPrimaryAssets
、LoadPrimaryAsset
和 LoadPrimaryAssetsWithType
可用於在適當的時間開始加載主資源。
用 UnloadPrimaryAssets
、UnloadPrimaryAsset
和 UnloadPrimaryAssetsWithType
進行卸載。
資源需要注冊,注冊資源有兩種方式,一種是在引擎里面注冊,一種是在代碼里面注冊。這里需要注意的是數組元素里有一項是PrimaryAssetType,這項的值必須與注冊的資源返回的Id參數AssetType的TEXT值一致。
特點
- 被認為是UObjectLibrary的替代品,從上面的實踐來說確實很不錯。
- 確實可以很精確的控制資源的加載和釋放的時機。
- 配置非常給力精確。
- AssetsRegistry的存在也使得登記、獲取、過濾、監聽資產更為便捷。
注意
- 需要覆蓋方法,返回一個ID。使次資源變為主資源。
- 加載和卸載的函數及參數。
- 資源注冊的兩種方式以及配置參數。
本文標簽
游戲開發
、游戲開發基礎
、Unreal Engine
、UE資源加載
。