Version: Unity 6.0 (6000.0)
语言 : 中文
升级到 Unity 2022 LTS
Unity Building Blocks

升级到 Unity 2021 LTS

本页面列出了从 2020 版本升级到 2021 LTS 时在 Unity 2021 LTS 版本中可能对现有项目造成影响的更改。

注意:2021 LTS 也称为 2021.3。

页面大纲

渲染管线

本升级指南介绍如何升级到 Unity 2021 版内置渲染管线。要升级到 2021 版的其他渲染管线,请参阅:

要升级其他包,请参阅所使用包的文档。

Device Simulator

Device Simulator 现在属于编辑器的一部分,可从游戏窗口访问。要设置 Device Simulator,请将 UnityEngine.Device 命名空间添加到 Screen、Application 和 SystemInfo 类:UnityEngine.Device.Screen; UnityEngine.Device.Application; UnityEngine.Device.SystemInfo;

要切换到 UnityEngine.Device,请将以下逻辑添加到要与模拟器一起使用的每个脚本: using Screen = UnityEngine.Device.Screen; using Application = UnityEngine.Device.Application; using SystemInfo = UnityEngine.Device.SystemInfo; 新的命名空间 UnityEngine.Device 通过运行时构建从模拟器(在编辑器中时)平滑过渡到实际设备 API。

Environment Lighting

现在,编辑器会自动烘焙默认的天空盒探针和环境探针,并保留该数据,直到手动烘焙场景。升级时,没有环境光贡献的场景在视觉上可能会发生变化。要恢复这些场景的原始外观,请将环境光照强度乘数设置为 0。或者,将天空盒设置为黑色,烘焙场景,然后将天空盒重置为偏好的天空颜色。

环境光照:现在会自动烘焙环境探针和天空盒反射探针

现在,Unity 的渐进式光照贴图默认为每个场景自动生成环境探针和天空盒反射探针。这意味着场景会根据光照设置面板中环境选项卡中的设置自动接收环境光照。每次环境光照发生变化时,编辑器都会更新环境探针和天空盒反射探针,直到生成光照。使用生成光照控件进行烘焙时,编辑器会停止更新探针,仅在下一次烘焙时再次更新探针。启用自动生成选项时,编辑器会在每次环境光照发生变化时继续更新探针。如果生成光照,然后通过从项目中移除光照数据资产来删除此光照数据,则编辑器会再次自动生成环境探针和天空盒反射探针。

在升级项目时,有一种情形需要采取行动。即当您不希望项目中有任何环境光照贡献时,项目存在以下情况:

  • 没有光照数据资产。
  • 未启用自动生成
  • 环境贡献设置为黑色以外的颜色。

在这种情况下,找到窗口 (Window) > 渲染 (Rendering) > 光照设置 (Lighting Settings) > 环境 (Environment),然后通过进行以下其中一项更改来禁用自动生成环境探针和天空盒反射探针的环境贡献:

  • 选项 1:将强度乘数设置为 0。
  • 选项 2:使用黑色天空盒材质
  • 选项 3:在颜色渐变模式中将黑色用于

启用代码覆盖率偏好

用于管理代码覆盖率的用户界面已从常规首选项移至代码覆盖率包中。

在 Unity 2021 中,启用代码覆盖率复选框已移至代码覆盖率窗口。
在 Unity 2021 中,启用代码覆盖率复选框已移至代码覆盖率窗口。

代码覆盖率包作为已发布包通过 Unity 2019.3 及更高版本的包管理器提供。最新版本为 1.0.0。

可以使用以下方法之一启用代码覆盖率:

// Create a new C# script called CodeCoverageMenuItem and place it
// under the Editor folder.
// This class creates a toggle menu item under Code Coverage > Enable
// Code Coverage. Use it to enable/disable Code Coverage.

using UnityEditor;
using UnityEngine.TestTools;

class CodeCoverageMenuItem
{
    const string EnableCodeCoverageItemName = "Code Coverage/Enable Code Coverage";

    [MenuItem(EnableCodeCoverageItemName, false)]
    static void EnableCodeCoverage()
    {
        Coverage.enabled = !Coverage.enabled;
    }

    [MenuItem(EnableCodeCoverageItemName, true)]
    static bool EnableCodeCoverageValidate()
    {
        Menu.SetChecked(EnableCodeCoverageItemName, Coverage.enabled);
        return true;
    }
}

粒子系统力场

以前,某些力场属性在不同的帧率下(或者使用时间管理器设置中的时间尺度时)表现有所不同

现在,粒子系统使用 30fps 的参考帧率作为模拟基础。如果你的应用程序以不同的帧率运行,则以下设置的行为可能与早期的 Unity 版本不同:

  • Gravity
  • Rotation
  • Vector Fields

如果这些设置受到影响,请调整受影响区域的强度以获得所需外观。

粒子系统启动延迟 + 单位距离发射率

以前,单位距离发射率会忽略启动延迟设置。现在,如果定义了启动延迟设置,则会延迟基于距离发射的启动。

如果以前设置了此字段,可能需要进行调整。

BuildReport - PackedAssets

PackedAssets.file 已标记为过时,没有直接替换方案。以前,它包含一个整数,表示 BuildReport.files 中的文件 ID 或索引。现在要查找 BuildReport 文件,请使用 PackedAssets.shortPath。

地形 API 已退出实验阶段 (WIP)

实验性地形 API 已移至非实验性命名空间。地形 API 还有一些其他小更改。如果您使用了实验性地形 API,请改用以下 API:

  • UnityEngine.TerrainTools;
  • UnityEditor.TerrainTools;
  • UnityEngine.TerrainUtils;

以下是 API 更改的完整列表:

  • 在大多数情况下,UnityEngine.Experimental.TerrainAPIUnityEditor.Experimental.TerrainAPI 现在分别为 UnityEngine.TerrainToolsUnityEditor.TerrainTools。某些运行时 API 已移至新的 UnityEngine.TerrainUtils 命名空间。
  • GetDesc() 类的 TerrainPaintTool<T> 已重命名为 GetDescription()
  • TerrainUtility 类已从 UnityEngine.Experimental.TerrainAPI 移至 UnityEngine.TerrainUtils
  • TerrainUtility.TerrainMap 类不再是内部类,属于 UnityEngine.TerrainUtils 命名空间。
  • TerrainMap.TileCoord 结构不再位于 TerrainMap 类中,已重命名为 TerrainTileCoord,现在也是 UnityEngine.TerrainUtils 命名空间的一部分。
  • UnityEditor.Experimental.TerrainAPI.BrushPreviewMode 枚举已重命名为 TerrainBrushPreviewMode 并移至 UnityEditor.TerrainTools 命名空间。
  • TerrainPaintUtilityEditor.BuiltinPaintMaterialPasses 枚举已从 TerrainPaintUtilityEditor 类移动到 UnityEditor.TerrainTools 命名空间中,同时重命名为 TerrainBuiltinPaintMaterialPasses
  • IOnInspectorGUI 中的三个 ShowBrushGUI 函数已合并为一个具有默认参数值的函数,而不是不同的重载函数。
  • TerrainFilter 已被删除。请改用 System.Predicate<Terrain>

Texture2D.Resize 已重命名为 Reinitialize

Texture2D.Resize 及其重载已重命名为 Texture2D.Reinitialize

API Updater 将自动重命名此项。如果没有,请将 Texture2D.Resize 的任何用法更改为 Texture2D.Reinitialize

Android 更改

现在,Android 构建管线的很大一部分为增量,Unity 删除了先前构建管线中的以下功能:

  • Unity 不再将位于 Assets/Plugins/Android/[res, assets] 中的__ Gradle__一套 Android 构建系统,可自动执行多种构建过程。这种自动化意味着能减少许多常见的构建错误。更多信息
    See in Glossary
    项目资源复制到 Gradle 项目。
    • 以前,您可以将 Gradle 资源放在此文件夹中,然后 Unity 将它们复制到 Gradle 项目中。现在应使用 AAR 或 androidlib 插件将额外的 Gradle 资源传递给应用程序。
    • 如果将项目资源放在此文件夹中,Unity 会显示构建错误消息。
  • Unity 不再忽略 GENEATED BY UNITY 中的文件。删除此注释以防止再次导出注释时发生重写。
    • 以前,如果删除此注释,Unity 不会重写文件。如果未删除注释,Unity 始终会重新生成 build.gradle、清单和 UnityPlayerActivity 文件。
    • 如果想要使用新的构建管线来保留更改,请使用模板。
  • 导出 Android 项目时,Unity 不再创建符号 zip 包。符号现在位于 unityLibrary\symbols 目录中,您可以将其压缩。此更改的原因是导出项目时并非所有符号文件都可用;Gradle 在构建应用程序时会生成 libil2cpp.so 符号。
  • 更改了 Unity 检查 obb 是否与__ apk__Unity 输出的 Android 包格式。选择文件 (File) > 构建并运行 (Build & Run) 时,APK 会被自动部署到设备。更多信息
    See in Glossary
    兼容的方式。现在,apk 和 obb 内部都有 unity_obb_guid 文件,如果两者之间的内容匹配,Unity 会将它们视为兼容。
  • 对于使用 PatchPackage 的自定义构建脚本,请注意,Patch/Patch & Run 现在适用于所有类型的资源,并且不需要 Script Only Build。

默认的 mainTemplate.gradle 文件已更改。如果使用自定义主模板,必须重新生成该模板并在顶部重新应用更改。否则,如果使用 Resources.Load,应用程序可能会出现性能下降。

UI 工具包 - 图像的默认 scaleMode 已更改

默认 Image.scaleMode 已从 ScaleAndCrop 更改为 ScaleToFit。

图像的预期行为是缩放到元素大小,因此我们将 Image.scaleMode 的默认值更改为 ScaleToFit。如果未覆盖图像缩放模式,某些裁剪图像可能会缩小以适应元素的大小。如果 ScaleAndCrop 是图像的预期模式,则可以通过在 UXML 文件内联样式中添加以下值来覆盖其样式:

-unity-background-scale-mode: scale-and-crop;

还可以使用覆盖创建一个样式类,并将其应用于需要 ScaleAndCrop 的图像。

Mono 升级行为更改

底层 C# 运行时 Mono 在最新版本中已升级。其中包括来自 Mono 上游版本的许多修复,以及一些显著的行为变化。

  • Directory.GetFiles 不再保证返回排序列表。
    • 以前会始终返回按字母排序的项列表。如果您的项目需要每次以相同的顺序返回项,请对返回的列表进行排序。例如:var 文件 = Directory.GetFiles(dir).OrderBy(f => f)
  • Object.GetHashCode 现在返回不同的值,不应被视为操作系统之间的确定性哈希算法。
    • 通常,不应在当前进程之外使用 GetHashCode 的结果,即不要序列化结果或期望下次在新进程中运行代码时结果相同。Unity 建议使用确定性哈希算法,例如 MD5。
  • 某些错误修复导致抛出新的异常。此外,一些异常消息的内容已更改。
    • 这种新行为在自动化测试场景中尤其明显,如果测试正在针对特定异常消息解析日志,可能需要更改预期行为。

Adaptive Performance

Adaptive Performance 包的 3.0 版现已推出。有关如何升级到 3.0 版的信息,请参阅 Adaptive Performance 升级指南

RenderTexture DepthStencilFormat

以前,如果将 RenderTexture.depth 属性设置为 32 位,则可以视平台获取 D24_S8。现在,如果将属性设置为 32 位,则对于深度组件,如果当前平台支持该格式,则会获取具有 32 位的 D32_S8。但是,这会使该深度缓冲区的内存使用量增加一倍。

新的 RenderTexture.depthStencilFormat 属性返回图形 API 用于在视频内存中创建资源的格式。还可以使用此属性请求特定格式。但是,并非所有平台都支持所有深度模板格式。将 DepthStencilFormat 属性设置为不受支持的格式时,Unity 会自动选择具有与深度和模板组件相同或更多位数的兼容格式。

升级

现在,RenderTexture 资源会序列化您选择的深度模板格式。如果您使用的 API 采用的是位数而不是格式,则这些位将映射到某种格式,并且该格式将被序列化。深度设置为超过 16 位的早期版本的 RenderTexture 资源会自动升级到使用 D24_S8。

在某些使用 DirectX 图形 API 的平台(例如 Windows)上,这会导致格式的深度位数较少,因为如果位数大于 16,图形后端会在内部选择 D32_S8 格式。为了确保在所有平台上保持一致的升级,自动升级程序在所有平台上均使用 D24_S8。但是,如果项目中有 RenderTexture 资源,这可能会在项目的渲染输出中引入视觉瑕疵。请查看这些资源,并根据需要将深度模板格式更改为 D32_S8。可能会出现以下问题:

  • 所使用的 RenderTextures 的内存大小可能会增加。但是,现在报告内存是正确的。
  • 将深度属性设置为 32 位会为您提供 32 位深度组件,因此内存使用量会增加。为了避免这种情况,请将位设置为 24 并使用 D24_S8(如果平台支持)。
  • 如果平台不支持 D24_S8,Unity 默认回退到兼容格式 D32_S8。为防止这种情况,请在检视面板 (Inspector) 窗口中禁用资源上的启用兼容格式 (Enable Compatible Format) 属性。如果 Unity 不支持 D32_S8 格式并且无法回退,则会显示错误消息:RenderTexture.Create 失败:不支持深度/模板格式。此平台上没有兼容格式,或者在导入检视面板中禁用了回退到兼容格式。在大多数情况下,要解决此问题,可以开启启用兼容格式 (Enable Compatible Format)

图形格式 DepthAuto、ShadowAuto 和 VideoAuto 已弃用

以下图形格式现已弃用:

  • DepthAuto
  • ShadowAuto
  • VideoAuto

对于这些 Auto 格式,使用的确切格式并不清楚,可能会因平台而异。

删除这些已弃用格式的步骤取决于格式和用例。

对于 VideoAuto

要获取当前平台的自动视频格式,请使用 SystemInfo.GetGraphicsFormat(DefaultFormat.Video)

对于用于指示仅深度渲染纹理的 DepthAuto/ShadowAuto。

GraphicsFormat API 通常使用 DepthAuto 或 ShadowAuto 来创建具有仅深度渲染而没有颜色缓冲区的渲染纹理。此用例的示例如下:

  • renderTextureDescriptor.graphicsFormat = GraphicsFormat.ShadowAuto
  • RenderTexture.GetTemporary(width, height, bits, GraphicsFormat.ShadowAuto)

要指示仅深度(非颜色)渲染,请将 GraphicsFormat.None 用作新颜色格式。renderTextureDescriptor.graphicsFormat = GraphicsFormat.None;

如果使用的是 ShadowAuto,请将 RenderTextureDescriptor 的 shadowSamplingMode 设置为 ShadowSamplingMode.CompareDepths 以在深度纹理上启用深度比较采样,并将代码更改为采用 RenderTextureDescriptor 的过载。renderTextureDescriptor.shadowSamplingMode = ShadowSamplingMode.CompareDepths;

对于其他情形中的 DepthAuto/ShadowAuto

在某些情况下,DepthAuto/ShadowAuto 格式表示自动选择的适用于当前平台的深度格式。要替换这种情形下的已弃用值,请使用 SystemInfo.GetGraphicsFormat(DefaultFormat.Depth/Shadow)

WebGL:更新 Emscripten 到 2.0.19

以前可供高级用户使用的 asm.js Linker 目标不再可用。

  • 在 Unity 2021.2 中,WebGL 平台使用的底层 Emscripten 编译器已更新到版本 2.0.19。升级了原生代码对象文件格式,因此需要重新编译项目中的所有原生代码插件(C/C++ 代码插件)。例如,如果您使用的是 Unity 资源商店中的闭源第三方插件,请记住向创作者索要 Unity 2021.2 的更新版本。
  • Emscripten 运行时 JavaScript 函数 Pointer_stringify() 现已弃用。应调用函数 UTF8ToString() 将 UTF8 编码的以空字符结尾的 C 字符串从 WebAssembly 堆封装到 JavaScript 字符串。

渐进式 GPU 光照贴图不再支持 CPU OpenCL 设备

渐进式 GPU 光照贴图不再支持 CPU OpenCL 设备。如果未找到受支持的 GPU,但检测到 CPU OpenCL 设备,则会显示一条警告消息,告知设备被跳过并回退到渐进式 CPU 光照贴图。渐进式 CPU 光照贴图为基于 CPU 的光照贴图计算提供更好的性能。此行为更改将自动发生,光照贴图应按预期计算。

OnPostprocessAllAssets 行为更改

当 Unity 在资源导入过程中调用 InitializeOnLoad 方法时,资源加载可能会失败。在资源导入期间,资源数据库处于更新状态,Unity 无法确定已导入哪些资源。InitializeOnLoad 方法无法加载尚未导入的资源。

为了改进资源导入过程,OnPostprocessAllAssets 回调得到了增强。具体而言,OnPostprocessAllAssets 回调情况如下:

  • 可在域重载后执行初始化,确保资源数据库处于就绪状态。
  • 包含 didDomainReload 参数,如果域已重载,则设置为 true。
  • 支持资源操作。其中包括资源加载,其行为与通过菜单项加载资源的方式相同。
  • 已移出资源数据库导入循环。回调处理将推迟到资源导入完成。

将任何需要资源操作的域相关初始化逻辑移动到 OnPostprocessAllAsset 回调;不要在 InitializeOnLoad 方法中执行资源操作。

以下行为更改代码示例显示了资源操作先前如何推迟。

示例 1:

public class AssetPostprocessorTester1 : AssetPostprocessor
{
    static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    {
        var assetPath = "Assets/hello.txt";

        if (File.Exists(assetPath))
        {
            var txtObj = AssetDatabase.LoadAssetAtPath<TextAsset>("Assets/hello.txt");
            AssetDatabase.DeleteAsset("Assets/hello.txt");

            if (txtObj == null)
                Debug.Log("New Behaviour: Asset object is unloaded");
            else
                Debug.Log("Old Behaviour: Asset is loaded for deleted asset!!");
        }
    }
}

示例 2:

 public class AssetPostprocessorTester2 : AssetPostprocessor
{
    static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
    {
        var assetPath = "Assets/SomeText.txt";
        if (!File.Exists(assetPath))
        {
            File.WriteAllText(assetPath, "hello world");

            AssetDatabase.ImportAsset(assetPath);
            var txtObj = AssetDatabase.LoadAssetAtPath<TextAsset>(assetPath);

            if (txtObj == null)
                Debug.Log("Old Behaviour: Asset hasn't been imported yet");
            else
                Debug.Log("New Behaviour: Asset is imported and loaded");
        }
    }
}

以下示例具有带有 didDomainReload 参数的新 OnPostprocessAllAssets 变体:

static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload)
{
    if (didDomainReload)
        Debug.Log("Domain has been reloaded");
    else
        Debug.Log("Domain did not reload during import");
}

现在,所有域重载都在资源数据库中进行处理。

现在 OnPostprocessAllAssets 更好地用于资源操作,但此回调中的任何处理都会增加资源数据库刷新和域重载时间。InitializeOnLoad 方法也会增加域重载时间。最佳做法是尽量减少这些回调中的处理,以改进编辑器在迭代之间的响应性。

没有阴影的混合点光源和聚光灯在 Subtractive 光照模式下烘焙直射光

现在混合模式点光源和聚光灯在使用 Subtractive 光照模式的场景中始终提供烘焙直射光,无论其阴影类型设置如何。因此,在受影响的场景中,静态__ GameObjects__Unity 场景中的基础对象,可以表示角色、道具、风景、摄像机、路径点等。GameObject 的功能由所附的组件决定。更多信息
See in Glossary
的镜面光照可能看起来缺失。要解决此问题,请将受影响的混合模式光源替换为实时模式光源。或者,将 Baked IndirectShadowmask 光照模式与混合光源一起使用。

着色器关键字系统改进

现在,着色器关键字系统允许每个着色器或计算着色器最多有 65534 个本地关键字,每个项目最多 232–2 个全局关键字。现在,在着色器或计算着色器中声明的所有关键字都是此着色器的本地关键字。在带有 _local 后缀的指令中声明的关键字不受全局关键字状态的影响。

示例:

着色器中的通道声明以下关键字:

  • #pragma shader_feature FOO BAR
  • #pragma shader_feature_local BOO BAZ

使用此通道时,如果全局或在材质上启用了关键字 FOO 和 BAR,则会启用它们。关键字 BOO 和 BAZ 仅在材质上启用时才启用。

Unity 支持 .NET Standard 2.1 API

现在,Unity 在 .NET 基类库中支持许多其他 API,包括 .NET Standard 2.1 API 中的所有 API。如果您的任何代码与新 API 发生冲突,则项目可能无法编译。

为避免升级在 Unity 之前版本中创建的项目时出现错误,请检查和更新代码,以确保与 .NET Standard 2.1 中现在可用的类型和方法没有冲突。

冲突来源如下:

  • 不明确的引用
  • 扩展方法
  • 预编译程序集

解决不明确的引用

如果代码实现类型或方法的名称与 .NET Standard 2.1 添加的类型或方法发生冲突,则代码无法编译。由于引用不明确,名称冲突可能导致 C# 编译器错误。

例如,如果将名为 MyCompany.MyCode.Range 的类型添加到项目的代码中,这可能与现有 System.Range 类型冲突。同时包含 using System;using MyCompany; 语句的代码无法编译。

为了防止错误,请在 C# 代码中为具有冲突名称的任何类型完全指定命名空间。

解决冲突的扩展方法

如果现有代码具有 .NET Standard 2.1 现在直接在类型上实现的扩展方法,可以选择重命名扩展方法或使用基类库实现的方法。

例如,项目中的代码可能会在 ArraySegment 类型上实现名为 CopyTo 的扩展方法。在 .NET Standard 2.1 中,ArraySegment 具有内置 CopyTo 方法。您可以选择重命名 CopyTo 扩展方法,也可以将其完全删除并使用内置方法。

解决冲突的程序集

如果项目使用预编译的程序集(即托管插件),这些程序集实现了现在属于基类库的类型和方法,请从项目中移除这些程序集并使用内置实现方案。

例如,在 Unity 的之前版本中,需要使用 NuGet 中的 System.Memory.dll 程序集来访问 System.Span 值类型。现在,.NET Standard 2.1 在基类库中提供了 System.Span。如果尝试在 Unity 2021.2 中使用 System.Memory.dll 托管插件,项目将无法构建。

Windows XR 插件已删除

Microsoft 已弃用 Windows__ XR__虚拟现实(VR)、增强现实(AR)和混合现实(MR)应用的泛指术语。支持这些形式的交互式应用程序的设备可被称为 XR 设备。更多信息
See in Glossary
插件,现在通过 OpenXR 插件支持 Windows 混合现实 (WMR) 功能和设备。

  • 从 Unity 2021.2 开始,已删除 Windows XR 插件。
  • 在 Unity 2021.2 中打开现有项目时,更新过程会删除 Windows XR 插件(如果有)。
  • 要继续在 Windows 混合现实中使用项目,必须启用 Unity OpenXR 插件。
  • 根据使用的功能,还必须安装 Microsoft 的 混合现实 OpenXR 支持插件,还可能要安装 Microsoft 混合现实工具包中的其他工具。

要升级到 Unity OpenXR 插件:

  1. 打开项目设置 (Project Settings) 窗口。
  2. XR 插件管理 (XR Plug-in Management) 部分中,在插件提供程序 (Plug-in Providers) 列表中启用 OpenXR。如果需要,Unity 会下载并安装 OpenXR 插件。

启用 OpenXR 插件后,您可以使用 Microsoft 提供的混合现实功能工具安装所需的支持包。

要安装或更新 WMR 功能、工具和示例,请执行以下操作:

  1. 下载并运行混合现实功能工具 (Mixed Reality Feature Tool)
  2. 选择要更新的 Unity 项目,然后单击发现功能 (Discover Features)。
  3. 在平台支持 (Platform Support) 下,选择混合现实 OpenXR 插件 (Mixed Reality OpenXR Plugin)。
  4. 选择要添加的任何其他功能。
  5. 单击获取功能 (Get features)。
  6. 单击导入 (Import),然后单击批准 (Approve) 以完成该过程。
  7. 返回到 Unity 项目设置的 XR 插件管理部分,然后启用并配置添加的功能。

有关设置新的和更新的 Unity 项目以使用 Windows 混合现实的更多信息,请参阅 Microsoft 文档网站上的设置 XR 配置

升级到 Unity 2022 LTS
Unity Building Blocks