本页面列出了从 2020 版本升级到 2021 LTS 时在 Unity 2021 LTS 版本中可能对现有项目造成影响的更改。
注意:2021 LTS 也称为 2021.3。
本升级指南介绍如何升级到 Unity 2021 版内置渲染管线。要升级到 2021 版的其他渲染管线,请参阅:
要升级其他包,请参阅所使用包的文档。
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。
现在,编辑器会自动烘焙默认的天空盒探针和环境探针,并保留该数据,直到手动烘焙场景。升级时,没有环境光贡献的场景在视觉上可能会发生变化。要恢复这些场景的原始外观,请将环境光照强度乘数设置为 0。或者,将天空盒设置为黑色,烘焙场景,然后将天空盒重置为偏好的天空颜色。
现在,Unity 的渐进式光照贴图默认为每个场景自动生成环境探针和天空盒反射探针。这意味着场景会根据光照设置面板中环境选项卡中的设置自动接收环境光照。每次环境光照发生变化时,编辑器都会更新环境探针和天空盒反射探针,直到生成光照。使用生成光照控件进行烘焙时,编辑器会停止更新探针,仅在下一次烘焙时再次更新探针。启用自动生成选项时,编辑器会在每次环境光照发生变化时继续更新探针。如果生成光照,然后通过从项目中移除光照数据资产来删除此光照数据,则编辑器会再次自动生成环境探针和天空盒反射探针。
在升级项目时,有一种情形需要采取行动。即当您不希望项目中有任何环境光照贡献时,项目存在以下情况:
在这种情况下,找到窗口 (Window) > 渲染 (Rendering) > 光照设置 (Lighting Settings) > 环境 (Environment),然后通过进行以下其中一项更改来禁用自动生成环境探针和天空盒反射探针的环境贡献:
用于管理代码覆盖率的用户界面已从常规首选项移至代码覆盖率包中。
代码覆盖率包作为已发布包通过 Unity 2019.3 及更高版本的包管理器提供。最新版本为 1.0.0。
可以使用以下方法之一启用代码覆盖率:
-enableCodeCoverage。Coverage.enabled API。类示例:// 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 版本不同:
如果这些设置受到影响,请调整受影响区域的强度以获得所需外观。
以前,单位距离发射率会忽略启动延迟设置。现在,如果定义了启动延迟设置,则会延迟基于距离发射的启动。
如果以前设置了此字段,可能需要进行调整。
PackedAssets.file 已标记为过时,没有直接替换方案。以前,它包含一个整数,表示 BuildReport.files 中的文件 ID 或索引。现在要查找 BuildReport 文件,请使用 PackedAssets.shortPath。
实验性地形 API 已移至非实验性命名空间。地形 API 还有一些其他小更改。如果您使用了实验性地形 API,请改用以下 API:
UnityEngine.TerrainTools;UnityEditor.TerrainTools;UnityEngine.TerrainUtils;以下是 API 更改的完整列表:
UnityEngine.Experimental.TerrainAPI 和 UnityEditor.Experimental.TerrainAPI 现在分别为 UnityEngine.TerrainTools 和 UnityEditor.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 及其重载已重命名为 Texture2D.Reinitialize。
API Updater 将自动重命名此项。如果没有,请将 Texture2D.Resize 的任何用法更改为 Texture2D.Reinitialize。
现在,Android 构建管线的很大一部分为增量,Unity 删除了先前构建管线中的以下功能:
libil2cpp.so 符号。默认的 mainTemplate.gradle 文件已更改。如果使用自定义主模板,必须重新生成该模板并在顶部重新应用更改。否则,如果使用 Resources.Load,应用程序可能会出现性能下降。
默认 Image.scaleMode 已从 ScaleAndCrop 更改为 ScaleToFit。
图像的预期行为是缩放到元素大小,因此我们将 Image.scaleMode 的默认值更改为 ScaleToFit。如果未覆盖图像缩放模式,某些裁剪图像可能会缩小以适应元素的大小。如果 ScaleAndCrop 是图像的预期模式,则可以通过在 UXML 文件内联样式中添加以下值来覆盖其样式:
-unity-background-scale-mode: scale-and-crop;
还可以使用覆盖创建一个样式类,并将其应用于需要 ScaleAndCrop 的图像。
底层 C# 运行时 Mono 在最新版本中已升级。其中包括来自 Mono 上游版本的许多修复,以及一些显著的行为变化。
Directory.GetFiles 不再保证返回排序列表。
Directory.GetFiles(dir).OrderBy(f => f);Object.GetHashCode 现在返回不同的值,不应被视为操作系统之间的确定性哈希算法。
GetHashCode 的结果,即不要序列化结果或期望下次在新进程中运行代码时结果相同。Unity 建议使用确定性哈希算法,例如 MD5。
Adaptive Performance 包的 3.0 版现已推出。有关如何升级到 3.0 版的信息,请参阅 Adaptive Performance 升级指南。
以前,如果将 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。可能会出现以下问题:
以下图形格式现已弃用:
对于这些 Auto 格式,使用的确切格式并不清楚,可能会因平台而异。
删除这些已弃用格式的步骤取决于格式和用例。
要获取当前平台的自动视频格式,请使用 SystemInfo.GetGraphicsFormat(DefaultFormat.Video)。
GraphicsFormat API 通常使用 DepthAuto 或 ShadowAuto 来创建具有仅深度渲染而没有颜色缓冲区的渲染纹理。此用例的示例如下:
renderTextureDescriptor.graphicsFormat = GraphicsFormat.ShadowAutoRenderTexture.GetTemporary(width, height, bits, GraphicsFormat.ShadowAuto)要指示仅深度(非颜色)渲染,请将 GraphicsFormat.None 用作新颜色格式。renderTextureDescriptor.graphicsFormat = GraphicsFormat.None;
如果使用的是 ShadowAuto,请将 RenderTextureDescriptor 的 shadowSamplingMode 设置为 ShadowSamplingMode.CompareDepths 以在深度纹理上启用深度比较采样,并将代码更改为采用 RenderTextureDescriptor 的过载。renderTextureDescriptor.shadowSamplingMode = ShadowSamplingMode.CompareDepths;
在某些情况下,DepthAuto/ShadowAuto 格式表示自动选择的适用于当前平台的深度格式。要替换这种情形下的已弃用值,请使用 SystemInfo.GetGraphicsFormat(DefaultFormat.Depth/Shadow)
以前可供高级用户使用的 asm.js Linker 目标不再可用。
Pointer_stringify() 现已弃用。应调用函数 UTF8ToString() 将 UTF8 编码的以空字符结尾的 C 字符串从 WebAssembly 堆封装到 JavaScript 字符串。
渐进式 GPU 光照贴图不再支持 CPU OpenCL 设备。如果未找到受支持的 GPU,但检测到 CPU OpenCL 设备,则会显示一条警告消息,告知设备被跳过并回退到渐进式 CPU 光照贴图。渐进式 CPU 光照贴图为基于 CPU 的光照贴图计算提供更好的性能。此行为更改将自动发生,光照贴图应按预期计算。
当 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 光照模式的场景中始终提供烘焙直射光,无论其阴影类型设置如何。因此,在受影响的场景中,静态__ GameObjects__Unity 场景中的基础对象,可以表示角色、道具、风景、摄像机、路径点等。GameObject 的功能由所附的组件决定。更多信息
See in Glossary 的镜面光照可能看起来缺失。要解决此问题,请将受影响的混合模式光源替换为实时模式光源。或者,将 Baked Indirect 或 Shadowmask 光照模式与混合光源一起使用。
现在,着色器关键字系统允许每个着色器或计算着色器最多有 65534 个本地关键字,每个项目最多 232–2 个全局关键字。现在,在着色器或计算着色器中声明的所有关键字都是此着色器的本地关键字。在带有 _local 后缀的指令中声明的关键字不受全局关键字状态的影响。
示例:
着色器中的通道声明以下关键字:
#pragma shader_feature FOO BAR#pragma shader_feature_local BOO BAZ使用此通道时,如果全局或在材质上启用了关键字 FOO 和 BAR,则会启用它们。关键字 BOO 和 BAZ 仅在材质上启用时才启用。
现在,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 托管插件,项目将无法构建。
Microsoft 已弃用 Windows__ XR__虚拟现实(VR)、增强现实(AR)和混合现实(MR)应用的泛指术语。支持这些形式的交互式应用程序的设备可被称为 XR 设备。更多信息
See in Glossary 插件,现在通过 OpenXR 插件支持 Windows 混合现实 (WMR) 功能和设备。
要升级到 Unity OpenXR 插件:
启用 OpenXR 插件后,您可以使用 Microsoft 提供的混合现实功能工具安装所需的支持包。
要安装或更新 WMR 功能、工具和示例,请执行以下操作:
有关设置新的和更新的 Unity 项目以使用 Windows 混合现实的更多信息,请参阅 Microsoft 文档网站上的设置 XR 配置。