【三思Unity】深入淺出資源管理之:Asset Import Pipeline v2(上)


每個游戲都是由種類繁多的資源構成,例如:網格、材質、紋理、着色器、動畫、音頻等。導入並管理這些資源文件,是游戲引擎必備的能力。資源管理包含兩部分:離線管理和運行時管理。

在 Unity 2019 LTS 中,對應的解決方案分別是 Asset Import Pipeline v2(下文簡稱 AIP v2) 和 Addressable Asset System。本文主要講解 AIP v2 部分, 包含 v2 相對於 v1 的改進之處,和完整的資源導入流程。

關鍵詞:Asset Import Pipeline v2,Unity Accelerator,Asset Revisions,Asset Database

1. Asset Import Pipeline v2

資源導入是 Unity 中最耗時的工作流程之一,是 AIP v1 的遺留問題。針對其中最耗時的兩個階段——新資源的導入和平台切換,AIP v2 分別提供了對應的解決方案。

1.1 新資源的導入

第一次拉取項目時,項目中沒有 Library 文件夾,這意味着 Assets 文件夾和 Packages 文件夾中的所有資源都需要經過 AIP 的導入處理,這步非常耗時。相較而言,直接拉取導入結果,耗時就要少幾個數量級。

Unity Accelerator

AIP v2 給出的方案是 Unity Accelerator,一種基於 Unity Collaborate 的局域網代理和緩存服務。原理是:團隊中有一人導入完資源,導入結果被自動緩存到 Accelerator,團隊里的其他成員在導入相同版本的資源時,Unity 首先檢測 Accelerator 上是否已經有對應的導入結果,如果有就下載。因為是本地網絡,帶寬不是問題,所以在資源較多的項目中,下載時間要遠少於導入時間。

在 Unity 給出的測試中,一個大小100MB、數量12000個的項目資源,Untiy 的導入時間為6分鍾,Accelerator 的導入時間為30秒,節省了90%以上的資源導入時間。然而實際項目中,12000個資源的空間占用一般要大於100MB,因此該測試僅供參考。

Unity Accelerator 基於 Unity Teams Advaned,按團隊人數收費。目前提供30天免費試用,25GB雲存儲,3人團隊的價格是60元/月,每增加一名團隊成員的價格是48元/月。

1.2 平台切換

在 AIP v1 中,Library 文件夾中緩存的導入結果以資源的GUID作為文件名。這天然的導致了一個資源只存在一個導入結果,因此每次切換平台都需要重新導入所有資源。這步非常耗時,在大型項目中甚至需要數個小時。

在 AIP v2 出現前,臨時的解決方案是每個平台分別對應一個項目。缺點是要占用多份項目的硬盤空間,以及每個項目需要單獨拉取更新。

Asset Revisions

AIP v2 給出的解決方案是:不使用資源的GUID作為導入結果的文件名,而是使用資源所有依賴的哈希值作為文件名,而平台正是資源的依賴之一(資源依賴的說明見下文4.3)。於是每個資源因為依賴的不同,而擁有多個版本的導入結果,它們被稱為資源的修訂版(Asset Revisions)。因此 Asset Database 中可以同時緩存多個平台的導入結果,當切換至已經有導入結果的平台時,就不需要再經歷耗時的導入處理。

AIP v2 同樣存在占用硬盤空間大的缺點,但是相較於每個平台分別對應一個項目,占用空間要小很多。對此 AIP v2 也做了優化處理:只保存每個資源僅平台依賴不同的修訂版,其他依賴導致的不同修訂版,在 Unity 每次重啟時會被刪除。

2. 源文件 Source File

Source File 是指由 Unity 之外的軟件創建並導出的資源文件。常見的有:圖片(png、jpg、psd)、音頻(wav、ogg、mp3)、視頻(avi、wmv、mp4)、模型(fbx、obj、c4d、blend)、字體(ttf、otf、ttc)、着色器(cg、hlsl)、文本文件(txt、xml、json、csv)、代碼文件(dll、jar、cpp、c、mm、dylib)等。

僅僅將 Source File 放入項目文件夾中,並不代表它成為了項目的一部分。只有經過 AIP 的導入處理,Soure File 轉變成 Asset, 才能為項目所用。

導入處理將 Source File 轉換成 Unity 能夠處理的格式。這些格式往往硬件友好,能夠讓CPU、圖形、音頻等硬件立即處理。例如:Unity 在運行時不會直接使用 .png 格式的圖片,而是使用經過導入處理后的某種具體格式的 texture 文件。

Pipeline 確保了導入結果的確定性,即:相同依賴的 Sourece File 經過導入處理,在任意時刻、任意設備得到的 Asset 是相同的。

3. 資源數據庫 Asset Database

Asset Database 包含了兩層含義。一層指 Source Files 經過 AIP 導入處理后的數據文件集合,即項目 Library 文件夾中的內容,又稱為 Asset Cache。Unity 在項目運行和打包時,使用的正是這里面的數據文件。

另一層指 Unity 封裝的 AssetDatabase 類。該類提供了對於 AIP 最重要的一個方法 Refresh,以及一系列方便安全的項目文件操作方法,例如:Contains、CreateAsset、CreateFolder、RenameAsset、CopyAsset、MoveAsset、DeleteAsset、LoadAssetAtPath等。

4. 刷新 Asset Database

將 Source File 放入項目 Assets 文件夾中時,或通過 Package Manager 導入 Package 時,AIP 檢測到新資源,並執行導入處理。這一步的本質是觸發了 AssetDatabase 的 Refresh 方法。

以下三種情況會觸發 AssetDatabase 的 Refresh 方法:

  1. Unity Editor 重新獲得焦點(如果開啟了 Auto-Refresh)。
  2. 點擊 Assets > Refresh 菜單。
  3. 在 C# 代碼中直接調用 Refresh 方法;或通過調用 CreateAsset、ImportAsset 等方法,間接觸發 Refresh 方法。

AssetDatabase 的 Refresh 方法將按順序執行以下步驟:

  1. 尋找變更的 Assets,並更新 source Asset Database(Library 文件夾中)
  2. 導入並編譯代碼相關文件
  3. 重載腳本域
  4. 導入非代碼文件
  5. 熱重載
  6. 更新 Artifact Database(Library 文件夾中)

接下來將對上述步驟做較詳細介紹,其中某些步驟會被拆分為幾個小步驟。

4.1 尋找變更的 Assets

當觸發了 AssetDatabase.Refresh() 方法后,Unity 開始掃描項目中 Assets 文件夾和 Packages 文件夾中的每個資源。與上次掃描相比,如果資源出現了新增、變更或刪除,則將它添加到一個資源變更列表中。

4.2 更新 source Asset Database

計算資源變更列表中的每個資源的哈希值,並且根據它們的GUID,更新 source Asset Database,並從列表中刪除對應資源。

4.3 依賴追蹤(Dependency tracking)

資源的依賴(Dependencies)是指所有能夠影響導入結果的數據。資源的 Source File 是最原始的依賴,資源的導入設置、目標平台等也都是依賴。

資源變更的本質,是資源依賴的變更。AIP 追蹤了每個資源的所有依賴。資源的任意依賴發生變更,都將引起資源的重新導入,生成新的導入結果。

資源變更的結果,是不同版本的資源緩存。AIP 維護了項目所有資源的導入結果,這些導入結果緩存在 Library 文件夾中,又叫做資源緩存(Asset Cache)。同一個資源的不同導入結果,是不同版本的資源緩存,又稱為資源的修訂版(Asset Revisions)。

4.4 導入並編譯代碼相關文件

Unity 從資源變更列表中收集與代碼相關的文件,遞送給腳本編譯管線(script compilation pipeline)。然后編譯器根據腳本文件和 assembly definition 文件生成程序集(Assemblies)。

4.5 重載腳本域(Reload the domain)

域重載(Domain Reloading)處理會完全重置腳本的狀態,包括重置所有靜態字段和靜態事件句柄。任意腳本的變更,都會重載腳本域。為了確保自定義導入器(Scripted Importer)起作用,這步將重啟 AssetDatabase.Refresh() 方法。

4.6 導入非代碼資源

AIP 基於資源文件名的擴展名識別文件類型,再基於文件類型使用對應的導入器(Asset Importer)處理資源。例如:TextureImporter 負責導入 jpg、png 和 psd 等圖片資源。導入器分為兩種:原生導入器(Native Importers)和自定義導入器(Scripted Importers)。

4.6.1 原生導入器(Native Importers)

Unity 內置了很多原生導入器,支持大多數資源類型,例如:圖片、音頻、視頻、模型、材質、着色器、字體、文本文件、代碼文件等。

4.6.2 自定義導入器(Scripted Importers)

對於新的資源類型,我們可以編寫自己的導入器。對於 Unity 已經提供了導入器的資源類型,也可以使用自定義導入器覆蓋原生的導入處理。

部分 Unity 內置的導入器也屬於自定義導入器,因此這些導入器的處理,發生在自定義導入器的處理階段。例如:StyleSheetImporter(uss 文件)、UIElementsViewImporter(uxml 文件)。

4.7 預處理(Preprocess)和后處理(Postprocess)

在導入階段,有許多回調方法,可用於資源導入的預處理和后處理。

預處理方法有:

  • OnpreprocessAsset
  • OnpreprocessAnimation
  • OnpreprocessAudio
  • OnpreprocessModel
  • OnpreprocessSpeedTree
  • OnpreprocessTexture

后處理方法有:

  • OnAssignMaterialModel
  • OnPostprocessAnimation
  • OnPostprocessAssetbundleNameChanged
  • OnPostprocessAudio
  • OnPostprocessCubemap
  • OnPostprocessGameobjectWithAnimatedUserProties
  • OnPostprocessWithUserProperties
  • OnPostprocessMaterial
  • OnPostprocessMeshHierarchy
  • OnPostprocessModel
  • OnPostprocessSpeedTree
  • OnPostprocessSprites
  • OnPostprocessTexture
  • OnPostprocessAllAssets

4.8 重啟 AssetDatabase 的 Refresh 處理

在上文中提到,重載腳本域將重啟 AssetDatabase.Refresh() 方法。除此以外,還有其他情況會重啟 AssetData base 的 Refresh 處理。例如:

  • 如果某個資源導入失敗
  • 如果資源在 Refresh 中的導入階段被更改
  • 如果資源在導入時生成了其他資源
  • 如果在預處理/后處理回調方法中強制重新導入某個文件,例如:在 OnPostProcessAllAssets 方法中使用 AssetDatabase.ForceReserializeAssets 方法或 AssetImport.SaveAndReimport 方法。注意避免無限重導入。
  • 如果在編譯完腳本后,某個程序集需要重新加載。
  • 如果以“Text only”保存某個資源,但是該資源必須被序列化為二進制格式,就會觸發 Refresh 處理。例如:帶有地形的場景必須被序列化為二進制格式,因為文本格式太笨重。

4.9 熱重載 Hot reloading

熱重載是指在 Editor 不重啟的情況下,導入並應用腳本和資源的變更。熱重載在 Editor 的 Play Mode 和非 Play Mode 都有可能發生。

當你更改並保存一個腳本文件時,Unity 首先保存所有已加載腳本的序列化變量,等腳本加載完成再恢復這些數據。在熱重載完成后,所有非序列化的數據都將丟失。

4.10 更新 Artifact Database

這是 Refrech 的最后一步,Library 文件夾中的 Artifact Database 被更新,導入結果被保存在硬盤上。

引用參考

[1] The new Asset Import Pipeline: Solid foundation for speeding up asset imports
[2] The Asset Database
[3] Refreshing the Asset Database

【三思Unity】系列是一個野心頗大的坑,旨在用精煉而准確的文字,闡述Unity的最新技術。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM