Unity 在以下情况下会刷新资源数据库:
其他一些 AssetDatabase API 会触发 Refresh(),但是仅针对您指定的资源。例如,CreateAsset() 和 ImportAsset()。
Unity 在资源数据库刷新期间执行以下步骤:
Unity 在资源数据库刷新期间执行以上部分中描述的步骤。本部分将进一步详细描述这一过程。这些步骤在一个循环中执行,某些步骤可能导致刷新过程重新启动(例如,导入资源时会创建其他资源,Unity 也需要导入这些资源)。
Unity 在以下情况下会重新启动资源数据库刷新循环:
Unity 查找磁盘中的更改时会扫描项目中的 Assets 和 Packages 文件夹,从而检查自上次扫描以来是否已添加、修改或删除任何文件。它将所有更改收集到列表中,以供下一步处理。
Unity 收集文件列表后,将为添加或修改的文件获取文件哈希。然后会使用这些文件的 GUID 来更新资源数据库,并会删除被检测到“已删除”的文件的条目。
资源数据库跟踪两类资源依赖项:静态依赖项和动态依赖项。如果资源的任何依赖项改变,Unity 都会触发该资源的重新导入。
静态依赖项是导入器所依赖的值、设置或属性。静态依赖项在导入资源之前为已知状态,并且在导入过程中不受导入器行为的影响。如果资源的静态依赖项改变,Unity 将重新导入该资源。
一些常见静态依赖项如下:
Unity 通常会在导入过程中发现资源的动态依赖项。这是因为这些依赖项是按源资源的内容定义的。例如,一个着色器可能引用另一个着色器,而一个预制件可能依赖于其他预制件。
导入器还可以根据源资源的内容,有条件地使用全局状态,在这种情况下也将成为动态依赖项。这种情况的示例包括目标平台、项目的颜色空间、图形 API、脚本运行时版本或纹理压缩状态。
Unity 将资源的这些动态依赖项存储在资源导入上下文 (Asset Import Context) 中。
在一系列已更改或已添加的文件中,Unity 收集与代码相关的文件,并将其发送到脚本编译管线。编译器从项目中的脚本文件和程序集定义文件生成程序集。有关此步骤的更多信息,请参阅脚本编译程序集定义文件的相关文档。
如果 Unity 检测到任何脚本更改,则会重新加载 C# 域。这样做的原因是可能已创建新的脚本化导入器 (Scripted Importer),它们的逻辑可能会影响“刷新”队列中的资源导入结果。此步骤会重新启动 Refresh() 以确保所有新的脚本化导入器生效。
Unity 导入所有与代码相关的资源并重新加载域后,将继续导入其余资源。每个资源的导入器都会处理该类型的资源,并根据文件扩展名来识别应导入的文件类型。例如,TextureImporter 负责导入 .jpg、.png 和 .psd 文件等。
有两种类型的导入器:原生导入器 (Native Importer) 和脚本化导入器 (Scripted Importer),分别在单独的阶段进行处理。原生导入器组首先被处理,并包括大部分 Unity 的内置导入器。接下来处理脚本化导入器,它们是 C# 编写的自定义导入器,可扩展 Unity 的导入功能。
导入器导入资源文件时,会生成 AssetImportContext。
AssetImportContext 用于报告资源的静态依赖项。
另外,在导入步骤中,会发生多次回调。
预处理资源导入器调用:
OnPreprocessAsset
OnPreprocessAnimation
OnPreprocessAudio
OnPreprocessModel
OnPreprocessSpeedTree
OnPreprocessTexture
后处理资源导入器调用:
OnAssignMaterialModel
OnPostprocessAnimation
OnPostprocessAssetbundleNameChanged
OnPostprocessAudio
OnPostprocessCubemap
OnPostprocessGameObjectWithAnimatedUserProperties
OnPostprocessGameObjectWithUserProperties
OnPostprocessMaterial
OnPostprocessMeshHierarchy
OnPostprocessModel
OnPostprocessSpeedTree
OnPostprocessSprites
OnPostprocessTexture
所有导入完成后触发的最后一个后处理回调是 OnPostprocessAllAssets
。
过程中可能会发生许多事件,这些事件将对 Asset 文件夹重新启动刷新过程,其中一些事件包括:
如果资源导入失败
如果在刷新的导入阶段修改了资源。例如,如果列表中的文件被修改,因此其修改日期与上次刷新的日期不符。如果在 Editor 获得焦点时开始从版本控制系统中提取文件,则会发生这种情况。
如果资源在导入期间创建了其他资源。例如:导入 FBX 时,可以从 FBX 中提取纹理并将其置于项目中,这意味着 Unity 必须导入这些纹理(及其生成的任何 Artifact)。
如果在某次预处理/或后处理回调期间或者在 OnPostProcessAllAssets 内强制重新导入某个文件,例如,使用 AssetDatabase.ForceReserializeAssets
或 AssetImport.SaveAndReimport
。注意,如果执行此操作,必须小心,不要引起无限的重新导入循环。
如果在编译脚本后发生程序集重新加载。如果在刷新过程中生成 C# 文件,必须先编译这个新文件,以便 Unity 重新启动刷新。
如果将资源另存为“仅文本”,但是必须将此资源序列化为二进制文件,这时会发生重新启动。(例如,必须将包含地形的场景序列化为二进制文件,因为如果在文本文件中将地形数据视为一系列字符,则此数据将很难处理。)
热重载是指在 Editor 开启的状态下由 Unity 导入脚本和资源并应用所有更改的过程。无论 Editor 是否处于运行模式 (Play Mode),都可能发生此情况。无需重新启动应用程序和 Editor 即可使更改生效。
更改并保存脚本时,Unity 会热重载项目的所有脚本数据。它首先将所有可序列化变量的值存储在所有加载的脚本中,重新加载脚本,然后恢复这些值。在热重载期间,存储在不可序列化变量中的所有数据都将丢失。
Note: 由(内置 DefaultImporter)[BuiltInImporters]导入的资源在脚本资源之前导入,因此不会为默认资源调用任何脚本定义的 PostProcessAllAssets 回调。
一旦完成所有这些步骤,就完成了 Refresh() 并使用相关信息更新了 Artifact 数据库,还会在磁盘中生成必要的导入结果文件。