Note: Follow the advice in this section in release order. For example, if you need to upgrade your project from 2019 to 2021, read the 2020 upgrade guide to see if there are any changes that you need to make before you read the 2021 upgrade guides.
This page lists changes in the Unity 2021 LTS version which might affect existing projects when you upgrade from a 2020 version to 2021 LTS.
Note: 2021LTS is also known as 2021.3.
This upgrade guide describes how to upgrade to version 2021 of Unity’s built-in render pipeline. To upgrade to other render pipelines to version 2021, see:
To upgrade other packages, refer to the documentation for the packages you are using.
The Device Simulator is now part of the Editor and is accessible from the Game window.
To set up the Device Simulator, add the UnityEngine.Device
namespace to the Screen, Application, and SystemInfo classes:
UnityEngine.Device.Screen;
UnityEngine.Device.Application;
UnityEngine.Device.SystemInfo;
To switch to UnityEngine.Device
, add the following logic to each script you want to use with the simulator:
using Screen = UnityEngine.Device.Screen;
using Application = UnityEngine.Device.Application;
using SystemInfo = UnityEngine.Device.SystemInfo;
The new namespace UnityEngine.Device
transitions smoothly from Simulator (when in Editor) to actual device API with a runtime build.
The Editor now automatically bakes the default skyboxA special type of Material used to represent skies. Usually six-sided. More info
See in Glossary probe and ambient probe and retains that data until you manually bake the SceneA Scene contains the environments and menus of your game. Think of each unique Scene file as a unique level. In each Scene, you place your environments, obstacles, and decorations, essentially designing and building your game in pieces. More info
See in Glossary. When you upgrade, Scenes with no ambient lightLight that doesn’t come from any specific direction, and contributes equal light in all directions to the Scene. More info
See in Glossary contribution might visually change. To restore the original look of these Scenes, set the Environment lighting intensity multiplier to 0. Alternatively, set the skybox to black, bake the scene, then reset the skybox to your preferred sky color.
Unity’s Progressive LightmapperA tool in Unity that bakes lightmaps according to the arrangement of lights and geometry in your scene. More info
See in Glossary now automatically generates the ambient probe and the skybox reflection probeA rendering component that captures a spherical view of its surroundings in all directions, rather like a camera. The captured image is then stored as a Cubemap that can be used by objects with reflective materials. More info
See in Glossary for every scene by default. This means that a scene automatically receives environment lighting in accordance with the settings in the Environment tab in the Lighting settings panel. The Editor updates the ambient probe and skybox reflection probe every time the environment lighting changes, until you generate lighting. When you bake with the Generate Lighting control, the Editor stops updating the probes, and only updates them again at the next bake. When you enable the Auto Generate option, the Editor continues to update the probes every time the environment lighting changes. If you generate lighting and then delete this lighting data by removing the Lighting Data Asset from the project, the Editor automatically generates the ambient probe and skybox reflection probe again.
There is one situation which requires action when you upgrade a project. This is when you don’t wish to have any Environment lighting contribution in a project which also:
In this situation, navigate to Window > Rendering > Lighting Settings > Environment and disable the environment contribution of the automatically generated ambient probe and skybox reflection probe by making one of the following changes:
The user interface for managing Code Coverage has moved from General Preferences to within the Code Coverage package.
The Code Coverage package is available as a released package via the Package Manager for Unity 2019.3 and above. The latest version is 1.0.0.
You can use one of the following methods to enable code coverage:
-enableCodeCoverage
in batchmode.Coverage.enabled
API. Example class:// 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;
}
}
Previously, some Force Field properties behaved differently at different frame rates (or if using the Time Scale in the Time Manager settings)
The Particle SystemA component that simulates fluid entities such as liquids, clouds and flames by generating and animating large numbers of small 2D images in the scene. More info
See in Glossary now uses a reference frame rate of 30fps to serve as the basis for the simulation. If your app runs at a different frame rate, the following settings might behave differently compared to earlier versions of Unity:
If these settings are affected, adjust the strengths of the affected areas to get the desired appearance.
Previously, Rate over Distance emission ignored the Start Delay setting. Now, if the Start Delay setting is defined, it delays the start for the distance-based emission.
If this field was previously set, you might need to adjust it.
PackedAssets.file has been marked obsolete without a direct replacement. Previously this held an integer signifying a file id or index into BuildReport.files To look up BuildReport files now, use PackedAssets.shortPath.
The experimental TerrainThe landscape in your scene. A Terrain GameObject adds a large flat plane to your scene and you can use the Terrain’s Inspector window to create a detailed landscape. More info
See in Glossary APIs have been moved to non-experimental namespaces. There have also been some other minor changes to the Terrain API. If you used the experimental Terrain APIs, use the following APIs instead:
UnityEngine.TerrainTools
;UnityEditor.TerrainTools
;UnityEngine.TerrainUtils
;Here is the full list of API changes:
UnityEngine.Experimental.TerrainAPI
and UnityEditor.Experimental.TerrainAPI
are now UnityEngine.TerrainTools
and UnityEditor.TerrainTools
, respectively. Some runtime APIs have moved to a new UnityEngine.TerrainUtils
namespace.GetDesc()
of the TerrainPaintTool<T>
class was renamed to GetDescription()
.TerrainUtility
class has moved from UnityEngine.Experimental.TerrainAPI
to UnityEngine.TerrainUtils
.TerrainUtility.TerrainMap
class is no longer an inner-class and belongs to the UnityEngine.TerrainUtils
namespace.TerrainMap.TileCoord
structure is no longer in the TerrainMap
class, has been renamed to TerrainTileCoord
, and is now also part of the UnityEngine.TerrainUtils
namespace.UnityEditor.Experimental.TerrainAPI.BrushPreviewMode
enum has been renamed to TerrainBrushPreviewMode
and moved to the UnityEditor.TerrainTools
namespace.TerrainPaintUtilityEditor.BuiltinPaintMaterialPasses
enum has moved from the TerrainPaintUtilityEditor
class and into the UnityEditor.TerrainTools
namespace. It has also been renamed to TerrainBuiltinPaintMaterialPasses
.ShowBrushGUI
functions in IOnInspectorGUI
have been merged into one function with default parameter values instead of the different overloaded functions.TerrainFilter
has been removed. Use System.Predicate<Terrain>
instead.
Texture2D.Resize
and its overloads have been renamed to Texture2D.Reinitialize
.
The API Updater should rename this automatically. If not, change any usage of Texture2D.Resize
to Texture2D.Reinitialize
.
A large part of the Android build pipeline is now incremental and Unity removed the following features that were in the previous build pipeline:
libil2cpp.so
symbols when it builds the application.The default launcherTemplate.gradle file has changed. If you use a custom launcher template, you must regenerate it and reapply your changes on top. Otherwise, your application can experience performance regressions if it uses Resources.Load.
Default Image.scaleMode was changed from ScaleAndCrop to ScaleToFit.
The expected behavior for an image is to scale to the size of the element, so we changed the default value of Image.scaleMode to ScaleToFit. If you didn’t override the Image scale mode, some cropped images might shrink to fit the size of the element. If ScaleAndCrop was the expected mode for your images, you can override their style by adding the following value in your UXML file inline style:
-unity-background-scale-mode: scale-and-crop;
You can also create a style class with the override and apply it to images that require ScaleAndCrop.
The underlying C# runtime, Mono, has been upgraded in the latest version. This includes many fixes from the upstream version of Mono, and some notable changes in behavior.
Directory.GetFiles
is no longer guaranteed to return a sorted list.
Directory.GetFiles(dir).OrderBy(f => f)
;Object.GetHashCode
now returns a different value and shouldn’t be relied on as a deterministic hashing algorithm between operating systems.
GetHashCode
outside of the current process, that is don’t serialize it or expect it to be the same the next time the code runs in a new process. Unity recommends using a deterministic hashing algorithm such as MD5.Version 3.0 of the Adaptive Performance package is now available. For information on how to upgrade to version 3.0, see the Adaptive Performance upgrade guides.
Previously, if you set the RenderTexture.depth
property to 32-bit, you could get D24_S8 depending on the platform. Now if you set it to 32-bit, you get D32_S8 with 32-bit for the depth component if that format is supported on the current platform. However, this doubles the memory usage for that depth bufferA memory store that holds the z-value depth of each pixel in an image, where the z-value is the depth for each rendered pixel from the projection plane. More info
See in Glossary.
The new RenderTexture.depthStencilFormat
property returns the format that the graphics API uses to create the resource in video memory. You can also use this property to request a specific format. However, not all platforms support all depth stencil formats. When you set the DepthStencilFormat
property to an unsupported format, Unity automatically selects a compatible format that has the equal or greater amount of bits for the depth and stencil components.
The RenderTexture asset now serializes the depth stencil format that you selected. If you use an API that takes a number of bits instead of a format, these bits get mapped to a format and that format is serialized. RenderTexture assets from previous versions that had the depth set to more than 16-bits are automatically upgraded to use D24_S8.
On some platforms (for example Windows) that use the DirectX graphics API, this results in a format with fewer depth bits because the graphics backend selects the D32_S8 format internally if you set bits>16. To ensure consistent upgrades across all platforms, D24_S8 is used on all platforms for the automatic upgrader. However, this might introduce visual artifacts in the render output of your project if you have RenderTexture assets in your project. Review these assets and change the depth stencil format to D32_S8 when needed. The following issues might occur:
The following graphics formats have now been deprecated:
These Auto formats are unclear about the exact format that’s used and might vary by platform.
The steps to remove the use of these deprecated formats depends on the format and use case.
To get the current platform’s automatic video format, use SystemInfo.GetGraphicsFormat(DefaultFormat.Video)
.
The GraphicsFormat API often uses DepthAuto or ShadowAuto to create render texturesA special type of Texture that is created and updated at runtime. To use them, first create a new Render Texture and designate one of your Cameras to render into it. Then you can use the Render Texture in a Material just like a regular Texture. More info
See in Glossary with depth-only rendering, and no color buffer. Examples of this use case are:
renderTextureDescriptor.graphicsFormat = GraphicsFormat.ShadowAuto
RenderTexture.GetTemporary(width, height, bits, GraphicsFormat.ShadowAuto)
To indicate depth-only (non-color) rendering, use GraphicsFormat.None as the new color format.
renderTextureDescriptor.graphicsFormat = GraphicsFormat.None;
If you used ShadowAuto, set the shadowSamplingMode of your RenderTextureDescriptor to ShadowSamplingMode.CompareDepths to enable depth-compare sampling on the depth texture, and change the code to use an overload that takes a RenderTextureDescriptor.
renderTextureDescriptor.shadowSamplingMode = ShadowSamplingMode.CompareDepths;
In some situations the DepthAuto/ShadowAuto formats represented an automatically selected depth format appropriate for the current platform. To replace the deprecated values in this case, use SystemInfo.GetGraphicsFormat(DefaultFormat.Depth/Shadow)
The asm.js Linker target that was available for advanced users is no longer available.
Pointer_stringify()
is now deprecated. Instead, call the function UTF8ToString()
to marshal a UTF8-encoded null-terminated C string from the WebAssembly heap to a JavaScript string.The Progressive GPU Lightmapper no longer supports CPU OpenCL devices. If no supported GPU is found but a CPU OpenCL device is detected, a warning message informs you that the device is skipped and falls back to the Progressive CPU Lightmapper. The Progressive CPU Lightmapper offers better performance for CPU-based computation of lightmapsA pre-rendered texture that contains the effects of light sources on static objects in the scene. Lightmaps are overlaid on top of scene geometry to create the effect of lighting. More info
See in Glossary.
This change of behavior will happen automatically and lightmaps should be computed as expected.
When Unity calls InitializeOnLoad
methods during the asset import process, asset loading can fail. During asset import, the asset database is in an update state and Unity can’t determine which assets have already been imported. InitializeOnLoad
methods can’t load assets that haven’t been imported.
To improve the asset import process, the OnPostprocessAllAssets
callback has been enhanced. In particular, the OnPostprocessAllAssets
callback:
didDomainReload
parameter, which is set to true if the domain has reloaded.Move any domain-related initialization logic that requires asset operations to the OnPostprocessAllAsset
callback; do not perform asset operations inside InitializeOnLoad
methods.
The following behavior change code examples show how asset operations were previously postponed.
Example 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!!");
}
}
}
Example 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");
}
}
}
The following example has the new OnPostprocessAllAssets
variant with the didDomainReload
parameter:
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");
}
All domain reloads are now processed inside the asset database.
OnPostprocessAllAssets
now works better with asset operations, but any processing in this callback increases asset database refresh and domain reload time. InitializeOnLoad
methods also add to domain reload time. It is best practice to minimize processing in these callbacks to improve Editor responsiveness between iterations.
Mixed mode point and spot lights now consistently contribute baked direct light in Scenes using Subtractive lighting mode, regardless of their Shadow Type setting. As a result, specular lighting for Static GameObjectsThe fundamental object in Unity scenes, which can represent characters, props, scenery, cameras, waypoints, and more. A GameObject’s functionality is defined by the Components attached to it. More info
See in Glossary may appear to be missing in affected Scenes. To resolve this issue, replace affected Mixed mode lights with Realtime mode Lights. Alternatively, use Baked Indirect or ShadowmaskA Texture that shares the same UV layout and resolution with its corresponding lightmap. More info
See in Glossary lighting mode(s) with Mixed lights.
The shaderA program that runs on the GPU. More info
See in Glossary keyword system now allows up to 65534 local keywords per shader or compute shader and 232–2 global keywords per project. All keywords you declare in a shader or compute shader are now local to this shader. Keywords you declare in a directive with the _local suffix aren’t affected by the state of global keywords.
Example:
A pass in a shader declares the following keywords:
#pragma shader_feature FOO BAR
#pragma shader_feature_local BOO BAZ
When using this pass, keywords FOO and BAR are enabled if they’re enabled either globally or on the material. Keywords BOO and BAZ are only enabled if they’re enabled on the material.
Unity now supports many additional APIs in the .NET base class libraries, including all APIs in the .NET Standard 2.1 API. Your project might fail to compile if any of your code has conflicts with new APIs.
To avoid errors when you upgrade projects created in previous versions of Unity, check and update your code to ensure that there are no conflicts with types and methods that are now available in .NET Standard 2.1.
Sources of conflict include the following:
If your code implements types or methods with a name that conflicts with types or methods that .NET Standard 2.1 adds, your code fails to compile. Name conflicts can lead to C# compiler errors due to ambiguous references.
For example, if you add a type named MyCompany.MyCode.Range
to your project’s code, this might conflict with the existing System.Range
type. Code that contains both using System;
and using MyCompany;
statements fails to compile.
To prevent errors, fully specify the namespace in the C# code for any types that have conflicting names.
If your existing code has an extension method that .NET Standard 2.1 now implements on a type directly, you can choose to rename your extension methods or to use the methods implemented by the base class library.
For example, code in your project might implement an extension method named CopyTo
on the ArraySegment
type. In .NET Standard 2.1, ArraySegment
has a built-in CopyTo
method. You can choose to rename your CopyTo
extension method, or eliminate it entirely and use the built-in one.
If your project uses precompiled assemblies (that is, managed plugins) that implement types and methods that are now part of the base class library, then remove these assemblies from your project and use the built-in implementations.
For example, in previous versions of Unity, you needed to use the System.Memory.dll
assembly from NuGet to access the System.Span
value type. Now, .NET Standard 2.1 provides System.Span
in the base class library. If you try to use the System.Memory.dll
managed plugin in Unity 2021.2, the project fails to build.
Microsoft has deprecated the Windows XRAn umbrella term encompassing Virtual Reality (VR), Augmented Reality (AR) and Mixed Reality (MR) applications. Devices supporting these forms of interactive applications can be referred to as XR devices. More info
See in Glossary plugin and now supports Windows Mixed RealityMixed Reality (MR) combines its own virtual environment with the user’s real-world environment and allows them to interact with each other.
See in Glossary (WMR) features and devices through the OpenXR plugin.
To upgrade to the Unity OpenXR plugin:
Once the OpenXR plugin is enabled, you can use the Mixed Reality Feature Tool provided by Microsoft to install the required supporting packages.
To install or update WMR features, tools, and samples:
For more information about setting up new and updated Unity projects to use Windows Mixed Reality, see Setting up your XR configuration on Microsoft’s documentation site.