Unity文件、文件引用、Meta詳解

本文詳細講解了Unity引擎各種類型文件的信息內容、用法和使用場景,幫助研發團隊對於引擎文件進行更好的理解和掌握。

一、Unity項目中Assets目錄下常見的文件類型

在Unity3d中一般存在這麼幾種文件:

  • 資源文件
  • 代碼文件
  • 序列化文件
  • 文本文檔
  • 非序列化文件
  • Meta文件

1、資源文件
資源文件指一些創建好並且不再修改的文件。這樣的文件一般是美術設計師和音頻視頻設計師創造的文件,比如FBX文件、貼圖文件、音頻文件、視頻文件和動畫文件(雖然動畫文件可以被認爲是配置文件,不過在由於一般不會去做修改,所以也認爲是資源文件)。像這類文件,Unity中都會在導入時進行轉化。每一個類型都對應一個AssetImporter,比如AudioImporter、TextureImporter、ModelImport等等。在Unity中點擊這樣的資源,在Inspector面板會出現設置界面,如下圖所示是一個FBX的設置界面:

請輸入圖片描述

 

2、代碼文件
代碼文件包括所有的代碼文件、代碼庫文件、Shader文件等。在導入時,Unity會進行一次編譯。

3、序列化文件(數據文件)
序列化文件通常是指Unity能夠序列化的文件,一般是Unity自身的一些類型,比如Prefab(預製體)、Unity3d(場景)文件、Asset(ScriptableObject)文件、Mat文件(材質球),這些文件能夠在運行時直接反序列化爲對應類的一個實例。

4、文本文檔
文本文檔比較特殊,它不是序列化文件,但是Unity可以識別爲TextAsset。很像資源文件,但是又不需要資源文件那樣進行設置和轉化,比如txt、xml文件等等。

5、非序列化文件
非序列文件是Unity無法識別的文件,比如一個文件夾也會被認爲是一個文件,但是無法識別。

請輸入圖片描述

 

6、Meta文件
Meta文件在Unity中的作用非常關鍵,它有2個作用:

  • 定義在它同目錄下,同名的非Meta文件的唯一ID:GUID。而對於Unity的序列化文件來說,引用的對象用的就是這個GUID。所以一旦Meta中的GUID變更了,就要注意,它很可能引起一場引用丟失的災難。

  • 存儲資源文件的ImportSetting數據。在上文中資源文件是有ImportSetting數據的,這個數據正數存儲在Meta文件中。ImportSetting中專門有存儲Assetbundle相關的數據。這些數據幫助編輯器去搜集所有需要打包的文件並分門別類。所以每一次修改配置都會修改meta文件。


二、Meta文件詳解——Unity GUID/LocalID系統

由於Meta文件的重要性,這裏先說說Meta文件的數據結構。Meta文件實質上是一個文本文檔,只是採用的是一種叫做YAML的格式來寫的(見Description of the Format)。Unity中的序列化文件都是用這個格式類寫的,比如Prefab、場景等(後文會繼續)。

我們使用Nodepad++打開一個Meta文件,然後在菜單中將語言設置爲YAML,如下圖所示:

請輸入圖片描述
這是一個Asset文件(ScriptableObject)的meta文件

 

1、GUID
Guid是Meta中最最最重要的數據。這個Guid代表了這個文件,無論這個文件是什麼類型(甚至是文件夾)。換句話說,通過GUID就可以找到工程中的這個文件,無論它在項目的什麼位置。在編輯器中使用AssetDatabase.GUIDToAssetPath和AssetDatabase.AssetPathToGUID進行互轉。

所以在每次svn提交時如果發現有Meta文件變更,一定要打開看一下。看看這個Guid是否被更改。理論上是不需要更改的。

2、ImportSetting數據

後面比較重要的數據是ImportSetting數據。根據不同的文件類型,它的數據是不同的ImportSetting數據,比如上面的NativeFormatImporter、ModelImporter、AudioImporter等等。只要對照Inspector面板中的條目,都可以看懂每一行的意義。

所以知道這個之後,我們可以發現,假如我們把一個文件和這個文件的Meta文件從一個Unity工程複製到另一個Unity工程中,它的配置是不會變的(以前在2個工程手動裁剪同一個模型的20個動畫真是傻到家了,直接將這個Fbx和它的Meta文件拷貝過去就行!)。

3、FileID(LocalID)

有一個問題是,如果是一個圖集,下面有若干個圖片,那麼,這個GUID怎麼對應一個文件呢?是的,對於一個文件下有多個文件的情況,就需要另外一個ID來表示,這就是LocalID。更習慣用Meta文件中的名字FileID。FileID存儲方式有2種:

對於資源文件,非序列化文件,由於一般不會去更改源文件,所以FileID存儲在meta文件中。以下是一個Fbx文件的Meta文件:

 

請輸入圖片描述
請輸入圖片描述

 

對於序列化文件,自身數據裏面會存儲自身的FileID,也會記錄所有子文件的FileID(更多關於序列化文件的數據,見下文)。比如對於這樣的AnimatorController。它本身的數據如下,除了本身的FileID爲9100000外,記錄了4個AnimatorClip的FileID。而meta文件中只有自身的FileID。

 

請輸入圖片描述
請輸入圖片描述請輸入圖片描述

 

回到本節一開始的問題,如果是圖集,因爲是圖片本身是資源文件,所以會有FileID存儲在對應的Meta文件中。打開任意一個圖集,比如以下這個圖集對應的Meta文件:

 

請輸入圖片描述
 

 

至此就是整個Unity的GUID/LocalID系統的基礎了。通過GUID找到任何一個文件,通過FileID找到其中的某個子文件。


三、序列化文件詳解——Unity文件引用系統

上文已經提到,對於所有的序列化文件,Unity採用的是YAML來書寫。所以對於一個Unity3d(場景)文件、prefab文件、材質、控制器等都可以用文本文檔軟件打開。這裏還是用Notepad++打開。

爲了能夠簡潔地說明問題,我們在Unity中創建一個新的場景,然後創建2個Cube,一個做成Prefab。如圖所示:

 

請輸入圖片描述

 

保存之後,用Notepad++打開這個1.Unity3d。然後在菜單中設置語言爲YAML。

 

請輸入圖片描述

 

可以看到大概的數據:

  • OcclusionCullingSettings裁剪數據(菜單Window->Occlusion面板中的數據)
  • RenderSettings(菜單Window->Lighting->Settings面板中的部分數據)
  • LightmapSettings(菜單Window->Lighting->Settings面板中的其他部分數據)
  • NavMeshSettings(菜單Window->Navigation面板中的數據)
  • 之後就是場景中的物件的數據

1、GameObject數據
展開第一個GameObject數據,可以看到這個的Name就是Main Camera(如果你的第一個GameObject數據不是Main Camera也沒關係,下面肯定某一個是Main Camera,展開那個數據也是一樣的結構)。

這個物體上有4個組件,一一對應下面的數據。這就是物體內的引用關係。每一個Unity對象都會有一個FileID,然後在需要引用時,使用這些FileID即可。所以在實例化一個這樣的GameObject時,只要依照次序,依次創建物體,組件,初始化數據並進行引用綁定即可在場景中生成一個實例。

請輸入圖片描述

 

我們在Inspector面板中的右上角點擊,然後選擇Debug轉成Debug模式下的Inspector面板:

請輸入圖片描述

 

在Hierarchy面板中選中Main Camera可以看到如圖所示,所有的組件的LocalIdentfierInFile的值就是剛剛在Notepad++中看到的數據:

請輸入圖片描述

 

這裏有一點,我們看到有一個叫做InstanceID的數據。這個是Unity中一個實例的ID。每一個Unity實例都會有一個InstanceID。在運行時,可以使用UnityEngine.Object的GetInstanceID獲取。但是要注意的是,每一次運行,相當於重新生成了新的實例,所以這個值是可變的。

2、組件數據

在GameObject之後就是這個GameObject的組件數據(不知道次序會不會亂,理論上不影響)。每一個組件的數據基本上就是這個組件的一堆參數了。可以結合Unity中這個組件的面板來了解每一個數據的意義。

這裏有一個問題,比如這裏有一個組件是FlareLayer,但是在YAML裏面只是一個Behaviour(所有Behaviour組件都看不到類型名字),怎麼樣才能知道他是一個FlareLayer?

請輸入圖片描述

 

可以看到在這個數據上方,在FileID左邊我們看到一個124。對,這個就是FlareLayer。請參考YAML Class ID Reference,每一個Unity類型都有一個對應的數字。

那麼自定義腳本類呢?

我們創建一個Test腳本,繼承MonoBehaviour。裏面什麼都不寫。添加到Main Camera物體上。保存場景然後回到Notepad++。

 

請輸入圖片描述

 

可以看到多了一個MonoBehaviour,並且這個裏面有一個M_Script數據,指向對應的GUID及其FileID。上文我們已經說了,任何一個文件都可以通過GUID找到,然後通過FileID找到它內部的子文件。所以這樣就能識別出這個具體是什麼類了。

我們往Test中寫2個字段

  • Public int A;
  • Public Test RefTest;

在Main Camera中,設置Test腳本的A值爲111,RefTest設置爲自身。保存後回到Notepad++;
請輸入圖片描述

看到數據想必都明白了。

可以往Test中寫一些其他類型的數據,看看這些序列化數據放在YAML的哪個位置!這裏不再展開(這些數據和編輯器的SerializedProperty息息相關)。

3、Prefab數據

在YAML的最下面有一個數據是Prefab數據:

請輸入圖片描述

 

看起來很複雜,但是實際上,它就保存了最重要的幾個數據:

  • Modification:每個組件的修改數據列表,但凡修改的數據,都會在這裏體現。
  • ParentPrefab:表示是哪一個Prefab。

所以上面的數據就是GUID爲27f1445c35c923741a22e4948c4da980的Prefab,修改後的FileID爲4126423848245890的一堆數據和FileID爲1854796474342856的Name數據。

通過打開我們製作的Cube的Prefab文件及其meta文件,我們可以看到,Meta文件中的GUID就是那個,而Prefab中存在4126423848245890(Transform)和1854796474342856(GameObject)

請輸入圖片描述
請輸入圖片描述

 

OK,至此,序列化文件的數據和引用的原理都已完畢。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章