对于大多数类型的资源,Unity 需要将资源的源文件中的数据转换为可用于游戏或实时应用程序的格式。这些转换后的文件及其关联的数据会存储在资源数据库 (Asset Database) 中。
由于大多数文件格式都经过优化来节省存储空间,所以需要执行转换过程,而在游戏或实时应用程序中,资源数据需要采用可用于硬件(例如 CPU、显卡或音频硬件)的格式才能立即使用。例如,Unity 将 .png 图像文件导入为纹理时,在运行时不会使用原始的 .png 格式数据。而在导入纹理时,Unity 将以另一种格式创建图像的新表示形式,并将其存储在项目的 Library 文件夹中。Unity 引擎中的 Texture 类会使用此导入版本,然后 Unity 将其上传到 GPU 以进行实时显示。
如果随后修改资源已导入的源文件(或更改其任何依赖项),Unity 会重新导入该文件并更新导入版本的数据。请参阅刷新资源数据库以了解关于此过程的更多信息。
资源数据库还提供了 AssetDatabase API 来访问资源以及控制或自定义导入过程。
资源数据库可以跟踪每个资源的所有依赖项,并保留导入版本的所有资源的缓存。
资源的导入依赖项包括可能影响所导入数据的全部数据。例如,一个资源的源文件是一个依赖项以及资源的导入设置(例如纹理的压缩类型)或项目的目标平台(例如,PS4 硬件要求的数据格式与 Android 硬件不同)。如果修改其中任意一个依赖项,则缓存版本的已导入资源都将变为无效状态,并且 Unity 必须将其重新导入才能反映所做的更改。
资源缓存是 Unity 存储导入版本的资源的位置。由于 Unity 始终可以从源资源文件及其依赖项重新创建这些导入的版本,所以这些导入的版本被视为预先计算的数据的缓存。在使用 Unity 时,此缓存可节省时间。因此,应该从版本控制系统中排除资源缓存中的文件。
默认情况下,Unity 使用本地缓存,这意味着导入版本的资源将缓存在本地计算机上项目文件夹的 Library 文件夹中。应该使用 ignore file 从版本控制中排除此文件夹。
但是,如果您是团队成员并且使用版本控制系统,最好也使用 Unity Accelerator,它可以跨 LAN 共享资源缓存。
由于缓存的资源不适合存储在版本控制系统中,所以您的团队共同处理项目并使用本地缓存时,如果资源或依赖项发生改变,则每个团队成员的 Unity 副本都将执行导入过程,这可能会很耗时。
Unity 为此提供的解决方案称为 Unity Accelerator。Accelerator 的功能之一是软件代理,它存储缓存版本的资源并将其提供给同一本地网络上共同从事同一项目的每个人。这意味着只有一个团队成员需要导入任何给定资源。随后,导入版本的资源将存储在 Accelerator 中,其他团队成员可以下载缓存的版本,而不必在本地等待导入过程。
Unity 在 Library 文件夹中保留两个数据库文件,它们统称为资源数据库。这两个数据库可以跟踪有关源资源文件和 Artifact(这是有关导入结果的信息)的信息。
源资源数据库包含有关源资源文件的元数据信息,Unity 将这些信息用来确定文件是否被修改,从而决定是否应该重新导入文件。这些信息中包括诸如上次修改日期、文件内容哈希、GUID 和其他元数据信息之类的信息。
Artifact 是导入过程的结果。Artifact 数据库包含有关每个源资源的导入结果的信息。每个 Artifact 都包含导入依赖项信息、Artifact 元数据信息和 Artifact 文件列表。
注意:数据库文件位于项目的 Library 文件夹中,因此应从版本控制系统中将这些文件排除。可以在以下位置找到它们:
Library\SourceAssetDB
Library\ArtifactDB
Unity 通常会在资源被拖入项目时自动导入资源,但也可以在脚本控制下导入资源。为此,可以使用 AssetDatabase.ImportAsset 方法,如以下示例所示。
using UnityEngine;
using UnityEditor;
public class ImportAsset {
[MenuItem ("AssetDatabase/ImportExample")]
static void ImportExample ()
{
AssetDatabase.ImportAsset("Assets/Textures/texture.jpg", ImportAssetOptions.Default);
}
}
还可以将 AssetDatabase.ImportAssetOptions 类型的额外参数传递给 AssetDatabase.ImportAsset 调用。脚本参考页面介绍了不同的选项及其对函数行为的影响。
编辑器仅在需要时加载资源,例如,是否将资源添加到场景或从 Inspector 面板中进行编辑。但是,可以使用 AssetDatabase.LoadAssetAtPath、AssetDatabase.LoadMainAssetAtPath、AssetDatabase.LoadAllAssetRepresentationsAtPath 和 AssetDatabase.LoadAllAssetsAtPath 从脚本加载和访问资源。有关更多详细信息,请参阅脚本文档。
using UnityEngine;
using UnityEditor;
public class ImportAsset {
[MenuItem ("AssetDatabase/LoadAssetExample")]
static void ImportExample ()
{
Texture2D t = AssetDatabase.LoadAssetAtPath("Assets/Textures/texture.jpg", typeof(Texture2D)) as Texture2D;
}
}
由于 Unity 保留有关资源文件的元数据,因此不应使用文件系统创建、移动或删除这些文件。相反,可以使用 AssetDatabase.Contains、AssetDatabase.CreateAsset、AssetDatabase.CreateFolder、AssetDatabase.RenameAsset、AssetDatabase.CopyAsset、AssetDatabase.MoveAsset、AssetDatabase.MoveAssetToTrash 和 AssetDatabase.DeleteAsset。
public class AssetDatabaseIOExample {
[MenuItem ("AssetDatabase/FileOperationsExample")]
static void Example ()
{
string ret;
// 创建
Material material = new Material (Shader.Find("Specular"));
AssetDatabase.CreateAsset(material, "Assets/MyMaterial.mat");
if(AssetDatabase.Contains(material))
Debug.Log("Material asset created");
// 重命名
ret = AssetDatabase.RenameAsset("Assets/MyMaterial.mat", "MyMaterialNew");
if(ret == "")
Debug.Log("Material asset renamed to MyMaterialNew");
else
Debug.Log(ret);
// 创建文件夹
ret = AssetDatabase.CreateFolder("Assets", "NewFolder");
if(AssetDatabase.GUIDToAssetPath(ret) != "")
Debug.Log("Folder asset created");
else
Debug.Log("Couldn't find the GUID for the path");
// 移动
ret = AssetDatabase.MoveAsset(AssetDatabase.GetAssetPath(material), "Assets/NewFolder/MyMaterialNew.mat");
if(ret == "")
Debug.Log("Material asset moved to NewFolder/MyMaterialNew.mat");
else
Debug.Log(ret);
// 复制
if(AssetDatabase.CopyAsset(AssetDatabase.GetAssetPath(material), "Assets/MyMaterialNew.mat"))
Debug.Log("Material asset copied as Assets/MyMaterialNew.mat");
else
Debug.Log("Couldn't copy the material");
// 手动刷新数据库以通知更改
AssetDatabase.Refresh();
Material MaterialCopy = AssetDatabase.LoadAssetAtPath("Assets/MyMaterialNew.mat", typeof(Material)) as Material;
// 移到垃圾箱
if(AssetDatabase.MoveAssetToTrash(AssetDatabase.GetAssetPath(MaterialCopy)))
Debug.Log("MaterialCopy asset moved to trash");
// 删除
if(AssetDatabase.DeleteAsset(AssetDatabase.GetAssetPath(material)))
Debug.Log("Material asset deleted");
if(AssetDatabase.DeleteAsset("Assets/NewFolder"))
Debug.Log("NewFolder deleted");
// 进行所有更改后刷新 AssetDatabase
AssetDatabase.Refresh();
}
}
在平台之间切换可能会导致 Unity 重新导入您的资源。在资源导入方式因平台而异时,通常会发生这种情况。例如,不同的平台有不同的纹理格式,因此每个平台的纹理导入有所不同。
使用资源数据库 V2 时,该平台是资源数据库用于存储 Unity 内置导入器的导入结果的哈希集的一部分。这意味着在不同平台上导入资源的结果将存储为单独的缓存数据。
此功能的结果是,当您第一次切换平台时,如果在项目中使用了尚未导入该平台的新资源,它们会被重新导入。这意味着您必须等待该过程完成。但是,重新导入的新数据不会覆盖为先前平台缓存导入的旧数据。
这意味着,无论您随后何时切换回已为该平台导入资源的平台,这些资源导入结果都已缓存并可供使用,从而使切换速度更快。
本文档引用的是资源数据库版本 2,是使用 Unity 2019.3 或更高版本来创建新项目时包含的默认版本。旧版本(版本 1)是 Unity 早期版本中的默认版本,其运行方式有所不同。旧版本不能在 Unity 2020+ 中使用。