這篇部落格介紹了UE4中的Asset Manager相關的内容,大部分參考的是Fortnite的公開資料。
背景(題外話)
如果不出意外的話,未來的一段時間将要回歸UE4的全職開發了。用了将近9個月的unity,或多或少能感受到這兩款商業引擎的設計理念的差異,也開闊了不少思路。在使用Unity 5的過程中發現它的Asset Management做的很不錯,回想起來當初用UE4做Console的時候也沒有遇到過這種需求 —— 不過這個功能在移動端應該是很常用的需求,是以也做個記錄吧……
涉及到的類
- Assest
指的是在Asset
中看到的那些物件。貼圖,BP,音頻和地圖等都屬于Asset.Content Browser
- Asset Registry
是資源系統資料庫,其中存儲了每個特定的asset的有用的資訊。這些資訊會在asset被儲存的時候進行更新。Asset Registry
- Streamable Managers
負責進行讀取物件并将其放在記憶體中。Streamable Managers
- Primary Assets
指的是在遊戲中可以進行手動載入/釋放的東西。包括地圖檔案以及一些遊戲相關的物件,例如character classs或者inventory items.Primary Assets
- Secondary Assets
指的是其他的那些Assets了,例如貼圖和聲音等。這一類型的assets是根據Secondary Assets
來自動進行載入的。Primary Assets
- Asset Bundle
是一個Asset的清單,用于将一堆Asset在runtime的時候載入。Asset Bundle
- Asset Manager
是一個可選的全局單例類,用于管理Asset Manager
和primary assets
,這些東西在runtime的時候很有用。asset bundles
Primary Assets
Primary Asset
指的是可以針對于
UObject::GetPrimaryAssetId()
傳回一個有效的值的
UObject
。
對于預設的工程,所有在
/Game/Maps
路徑下的Maps會被設為Primary Assets,而所有其他的assets如果需要設定為Primary Assets,都需要手動指定。
所有的
Primary Assets
是通過
FPrimaryAssetId
來進行引用的,
FPrimaryAssetId
擁有如下的屬性:
-
:這指的是一個用于描述物件的邏輯類型的名字,通常是基類的名字。例如,我們有兩個繼承自同一個本地類PrimaryAssetType
的BPAWeapon
和AWeaponRangedGrenade_C
,那麼它們會有同樣的AWeaponMeleeHammer_C
——PrimaryAssetType
"Weapon"
-
:這指的是用于描述這個asset的名字。通常來說,這就是這個object的名字(short name),但是對于例如說maps來說,這個值就是對應的asset path。PrimaryAssetName
-
可以組成整個遊戲執行個體中的asset的唯一的描述。當用戶端在和服務端通信的時候,就可以通過這個字元串來确認某個物件。例如,PrimaryAssetType:PrimaryAssetName
本質上和"Weapon:BattleAxe_Tier2"
是一樣的。"/Game/Items/Weapons/Axes/BattleAxe_Tier2.BattleAxe_Tier2_C"
- 在
中分别有兩個FPrimaryAssetId
的Tag,分别是FName
和PrimaryAssetTypeTag
。是以,當一個PrimaryAssetNameTag
被儲存了之後,就可以直接在Primary Asset
中通過這兩個Tag來找到這個Asset。Asset Registry
Streamable Manager
FStreamableManager
可以用來處理assets的讀取,并且将其在被需要的時候儲存在記憶體中。針對不同的操作,可以有不同的
Streamable Manager
。FStreamableManager可以與
FStreamableHandle
一起工作,來更好的處理物件在記憶體中的生命周期。
-
是一個用于處理assets讀取的結構體。通常來講,在streaming operation會傳回一個shared pointer,這個shared pointer就是用于追蹤這個結構體的。當一個handle是active的時候,它就可以確定它引用的那些assets是在記憶體中的了。FStreamableHandle
-
從Loading開始就被激活了,當這個handle被顯式cancel或者release的時候,将被disactive。FStreamableHandle
-
可以用來被顯示調用。但是當所有的指向這個handle的隻能指針被銷毀的時候被隐式調用。FStreamableHandle::ReleaseHandle()
-
是用來中斷Loading過程的接口。這個函數被調用後,Loading将會被中斷,并且将取消Loading完成過後的所有回調函數。FStreamableHandle::CancelHandle()
-
将阻斷線程,知道所需的asset被成功載入為止。這個函數被調用時,所需的asset的載入優先級将被設為最高(通過将其移到優先級隊列的top來實作),并且不會影響其他的異步載入操作,是以通常比FStreamableHandle::WaitUntilComplete()
函數更快。LoadObject
-
是基本的stream操作。可以傳入一個RequestAsyncLoad
或者一個FStringAssetReference
的清單。調用了這個操作之後,引擎會試圖去Load這些Assets,并且在Loading完畢之後調用回調函數。同時,這個函數會傳回一個FStringAssetReference
的Streamable Handle
來供後期調用。shared pointer
-
是RequestSyncLoad
的同步版本。這個函數要麼會進行異步載入并且調用RequestAsyncLoad
函數,要麼直接調用WaitUntilComplete
函數 —— 哪個更快就調哪個。LoadObject
-
是另一種Loading的方式,這個函數會傳回一個asset,并且這個函數可以有模版安全的版本。LoadSynchronous
- 這些函數都有
的參數,預設為false —— 如果設定為true的話,會導緻bManageActiveHandle
本身就帶有一個這個handle的reference。這樣一來的話就需要手動管理以及release這個handle了。streamable manager
Asset Manager
AssetManager
是一個單例的UObject,它提供了在runtime的時候進行查詢以及讀取Primary Assets的操作。這個東西是原本用于取代
ObjectLibraries
目前提供的操作的,并且可以對
FStreamableManager
進行一層封裝來處理Async Loading的操作。引擎内置的asset manager隻能提供基本的管理操作,但是一些更加複雜的東西,例如caching需要自己實作。Asset Manager的基本操作如下:
-
:單例的Get操作。Get()
-
:這個函數可以查詢特定目錄下的某類特定的ScanPathsForPrimaryAssets(Type, Paths, BaseClass)
,如果在Editor下則直接讀取磁盤上的資訊,如果在cooked工程中會從asset registry cache中讀取asset資訊。primary asset
-
: 獲得PrimaryAssetId對應的asset的object path。GetPrimaryAssetPath(PrimaryAssetId)
-
: 獲得object path對應的asset的primary asset id資訊,以Type:Name的形式。GetPrimaryAssetIdForPath(StringReference)
-
:通過GetPrimaryAssetIdFromData(FAssetData)
來獲得對應的Type:Name形式的FAssetData
。Primary Asset Id
-
:同理GetPrimaryAssetData(PrimaryAssetId)
-
:傳回一個所有對應類型的asset清單。GetPrimaryAssetDataList(Type)
-
:查詢這個對應的UObject是否在記憶體中。如果這個UObject不再記憶體中,則傳回nullptr。GetPrimaryAssetObject(PrimaryAssetId)
-
:異步載入這些primary assets和BundleState所引用的所有其他assets。傳回一個LoadPrimaryAssets(AssetList, BundleState, Callback, Priority)
的FStreamableHandle
用于追蹤,并且在Loading完成後調用回調函數。shared_pointer
-
:這個函數會調用這些primary assets的GC。UnloadPrimaryAssets(AssetList)
-
:這個函數可以用一種更複雜的方式去處理bundle state。ChangeBundleStateForPrimaryAssets(AssetList, Add, Remove)
Asset Bundles
Asset Bundle在Unity中很常見了——總體來說就是顯式的primary assets相關的assets清單。
- 從底層來看,一個Bundle本質上其實就是一個
到FName
的map。每一個bundle都與一個TArray<FStringAssetReferences>
相關。但是……這個東西也可以是一個動态的asset。Primary Asset Id
- 如果需要對普通的Primary Asset生成對應的Asset Bundle,我們需要在自己的Object中加入一個
的FAssetBundleData
,并且在進行save操作的時候将這個UStruct
進行填充。然後,這些資料就會被寫在asset registry tag中,并且在這些asset資料被讀取的時候,這個UStruct
會被識别并處理。UStruct
- AssetBundle meta tag可以被設定為确定的
或者AssetPtr
。StringAssetReference
- 可以通過調用
函數來在runtime的時候處理一些特定的asest bundle.AddDynamicAsset
- 在Asset Bundle中的任何東西,都會被認為是該primary asset的一部分。這在進行Chunking的時候會非常有用。
其他
整個的AssetManager是一個很大的系統,如果有個例子就更好了。
如果有時間就把Fortnite的例子翻譯過來吧……
<全文完>