With Presets, you can customize the default state of just about anything in Unity – Components, Importers, Managers – without coding. Presets can benefit development teams of all sizes, from streamlining repetitive tasks or validating design decisions, to enforcing standards and project templating. In this post, we’ll dig into many of the features provided by Presets, including basic functionality, tips and tricks, and then delve into some advanced use cases.
First things first: what is a Preset?
Fundamentally, a Preset is an Asset that allows you to override the defaults for a given Component, Importer, or Manager (anything that extends Unity.Object, in fact). Would it make more sense in your project for a RigidBody to default to a mass of 10 instead of 1, but have gravity turned off? Make it so with a preset.
We can use Presets on things that get imported or instantiated in the hierarchy: Textures, FBX files, MonoBehaviour components like Light, Camera, or RigidBody.
Note that Presets are an Editor feature, designed to improve your authoring workflow, not a runtime feature. The Presets aren’t shipped with your binary, so don’t expect GameObject.AddComponent<RigidBody>() to apply these same defaults. However, the Editor-time ObjectFactory API does support Presets, so ObjectFactory.AddComponent<RigidBody>() operates with the assumption that the project Presets will be respected.
To create a Preset, all you need to do is go to an existing importer or component of the same type, make your adjustments to it in the Inspector, then click the Preset Icon in the upper right. A window will open where you can choose «Save Current To…» to save out the asset.
Tips and tricks for working quickly with Presets
Here are a few fun ways to apply Presets in your project.
Click the Preset Icon
OK, this one is (hopefully) pretty obvious. Clicking the Preset Icon in any Inspector will allow you to select any preset for the same component or file Type.
Drag-and-drop to Inspector
You can simply drag a preset from the Project Window and onto a component in the Inspector if you want to change the values of that component.
You can also add a new Component to a GameObject by dragging the preset into the Inspector.
Drag-and-drop to Hierarchy
Presets can also be used to create new objects in the hierarchy. You can quickly create a new GameObject containing the preset’s associated component by dragging from the Project Window straight into the hierarchy.
This workflow is a little bit like working with a prefab, but note that Presets are not prefabs! The preset – by design – maintains no link with any object created from that preset.
You can even drag-and-drop multiple Presets and generate a GameObject with all the associated components!
Managing Presets
Presets work in conjunction with the Preset Manager, a UI found within Edit → Project Settings…
To add a default, open the Preset Manager, click «Add Default Preset», then select the Type for which you want a default. Finally, click the circle to the right of None (Preset) and select a preset asset that matches the Type from the Select Preset popup.
Here’s a more populated Preset Manager in which we can see the RigidBody 10 preset that we created at the start of this blog post, applied as the project default for RigidBody.
With this setup, every RigidBody created will, by default, come with a mass of 10 and gravity disabled.
But check out how the Preset Manager allows more than one default per Type. This powerful extension of the preset idea – new in 2019.3 – means that we can have multiple «defaults» between which we can discriminate based on a name. Looking at Camera in the image above, you’ll observe that the blank filter uses the Camera Gameplay preset. This means that by default every camera will use this preset. But we’ve tied the filter «UI» to a Camera UI preset for use with our UI cameras. With this setup, if I create any camera with «UI» anywhere in the GameObject name – «UICamera», «Camera UI», or «HUDUICamera» – the Camera UI preset will be used in preference to the default one.
Some notes about Preset Manager:
- String matching is case-insensitive, so in the «UI» example above be careful of a name like «GuideCamera», which includes the matching «UI» string but may not be what you intended!
- Where an object matches multiple defaults for a single type, the preset applied will be the LAST match in the list.
- You can reset any component to a default by choosing «Reset» for that component.
- For importers, it’s the file name, rather than the GameObject name, that drives which filter gets used.
Presets for managers
One of the great virtues of Presets is their ability to align a team on key art and design decisions: what color are our lights? How heavy do we want RigidBodies to be? What are our standards for importing normal maps? When applying Presets to managers, we can carry this idea forward to the project level. Let’s look, for example, at the Physics Manager and the Tags and Layers Manager.
In the example, we’ve gone to rather a lot of trouble to ensure a specific set of physics interactions between layers (enemies don’t interact with other enemies, allies and their bullets don’t interact with other allies). These decisions may have relevance for follow-on or adjoining projects, and Presets make it easy to memorialize decisions and share those from one project to another.
In the animation below, watch how we save the two managers out and apply them to a separate project. This can be a big help for bootstrapping new projects in your organization.
Of course there’s an API!
For the majority of cases, the visual interface above is probably sufficient, but if you’re authoring, say, an import pipeline or building tooling it might help to have programmatic control over your Presets. To this end we’ve exposed the Presets API for your enjoyment and productivity.
The following examples are all available on Github.
Let’s start with a simple example. Imagine we want to add a tool that applies one or more properties from a single light to all the lights in a scene.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[MenuItem("CONTEXT/Light/Replicate Color in Scene")] public static void ApplyAllLights(MenuCommand command) { // Get our current selected light var referenceLight = command.context as Light; if (referenceLight != null) { // Create a Preset out of it var lightPreset = new Preset(referenceLight); // Find all Light components in the scene of our reference light var allLights = referenceLight.gameObject.scene.GetRootGameObjects() .SelectMany(r => r.GetComponentsInChildren<Light>(true)); // Choose which serialized property we want to apply to everyone var propertyToApply = new[] { "m_Color" }; // Apply the Preset with only the selected property to all the Lights foreach (var light in allLights) { lightPreset.ApplyTo(light, propertyToApply); } } } |
This code takes a reference object, a light, and then creates a Preset on-the-fly (var lightPreset = new Preset(referenceLight)). It then uses m_Color from the referenceLight to apply that value to all other lights in the scene.
Here’s how our new tool behaves inside Unity.
Note that this demonstrates a programmatic example of a partial preset, i.e., the code grabs and applies just a subset of the full preset property set. This is a functionality we hope to expose in UI sometime soon.
For our second example, let’s look at how we can apply a single preset to all assets of the same Type in a project folder.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
[MenuItem("CONTEXT/Material/Replicate Material Color in Folder")] public static void ApplyAllMaterialsInFolder(MenuCommand command) { // Get our current selected Material var referenceMaterial = command.context as Material; if (referenceMaterial != null) { var assetPath = AssetDatabase.GetAssetPath(referenceMaterial); if (!string.IsNullOrEmpty(assetPath)) { // Create a Preset out of it var materialPreset = new Preset(referenceMaterial); // Find all Material assets in the same folder var assetFolder = Path.GetDirectoryName(assetPath); var allMaterials = AssetDatabase.FindAssets("t:Material", new[] { assetFolder }) .Select(AssetDatabase.GUIDToAssetPath) .Select(AssetDatabase.LoadAssetAtPath<Material>); // Select the first color entry; in the standard shader this entry is _Color var propertyToApply = new[] { "m_SavedProperties.m_Colors.Array.data[0]" }; // Apply the Preset with only the selected property to all the Materials foreach (var material in allMaterials) { materialPreset.ApplyTo(material, propertyToApply); } } } } |
As before, we take a reference object, this time a selected Material (var referenceMaterial = command.context as Material), then use it to create a Preset on-the-fly (var materialPreset = new Preset(referenceMaterial)). Then we locate the folder in which this material resides and apply the Color property to all materials in the same folder.
Again, let’s see how this plays out in the Editor.
Finally, let’s look at a somewhat more complex example. In this snippet, we’re taking a selected light and – depending on whether a Light default already exists – either creating that preset or updating the default preset to match the selection. Follow the comments in the code below to understand how it works.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 |
public static void UpdateOrAddLightDefaults(MenuCommand command) { // Get our current selected light var referenceLight = command.context as Light; // Get the list of default Presets that apply to that light var defaults = Preset.GetDefaultPresetsForObject(referenceLight); if (defaults.Length == 0) { // We don't have a default yet, let's create one! var defaultLight = new Preset(referenceLight); // We're kind people, so let's nicely ask the user where to save this default var path = EditorUtility.SaveFilePanelInProject("Create Default Light preset", "Light", "preset", "Select a folder to save the new default"); // If the selected path already contains a Preset, its instanceID would be changed by a plain replace // We use this trick to replace the values only so an Object referencing the existing asset will not break var existingAsset = AssetDatabase.LoadAssetAtPath<Preset>(path); if (existingAsset != null) { EditorUtility.CopySerialized(defaultLight, existingAsset); defaultLight = existingAsset; } else { AssetDatabase.CreateAsset(defaultLight, path); } // Load the existing default list // We don't want to lose any configuration that may point specific GameObject because of the filters var existingDefault = Preset.GetDefaultPresetsForType(defaultLight.GetPresetType()).ToList(); // Insert the new one at the beginning of the list with no filter // so it applies to any Light that doesn't have a default existingDefault.Insert(0, new DefaultPreset("", defaultLight)); // Set the new list as default for Lights. Preset.SetDefaultPresetsForType(defaultLight.GetPresetType(), existingDefault.ToArray()); } else { // We want to update the values only to the last default // because maybe other Presets apply to other objects first // and we don't want to change them var lastPreset = defaults.Last(); lastPreset.UpdateProperties(referenceLight); } } |
Here’s an animation showing how this works in Unity. Notice how on our first pass through we are guided through the creation of a new preset, but on our second pass, we simply update the existing one.
Next steps: Presets are what you want them to be!
We have several ideas in the works for upcoming versions of the feature, including (as mentioned above) partial Presets, improved filtering functionality, and application of Presets to folders. But as we said at the outset, Presets are all about making Unity behave the way you need it to behave. With that in mind, it’s important to us that we hear from you. Do you have ideas for what you could be doing to improve your workflow with this feature? Let us know your thoughts in the comments!
iSinner
octubre 21, 2019 a las 10:09 amDoing a load on all assets with «.Select(AssetDatabase.LoadAssetAtPath)» on something heavier than materials, lets say a 60gb folder with models, would crash unity with out of memory exception, and the bigger issue is that there is no good way of avoiding it because unity doesn’t have a way to unload the assets from memory with a line of code.
I stumbled on this issue recently and explained it in detail in this forum post: https://forum.unity.com/threads/help-editorutility-unloadunusedassetsimmediate-doesnt-work.763046/
DoktorAce
octubre 21, 2019 a las 8:34 amMaybe I’m missing something but I would have expected assets that I’ve set to a preset to be updated once a preset is changed. I don’t really see the point otherwise.
Marc Tanenbaum
octubre 16, 2019 a las 5:45 pmThanks to everyone who’s offered ideas, suggestions and criticisms. We’re looking at all of them to see how we can improve.
Mark
octubre 15, 2019 a las 2:14 pmWill there be a way to create presets for HDRP assets in the project settings?
In the beta it seems you can create a preset for the HDRPasset, but there is no way to apply that in the project settings windows (Qualiy>HDRP). Would be great to setup low / medium / high settings that are selected from the Quality window.
Joshua
octubre 12, 2019 a las 1:07 pmNow if you only could make our life easier and practice what you preach. :P Please set a default preset in Unity for everyone, to automatically set every normal map as normal map. It would be great. :) Unreal does it for ages. With other things too. i.e. custom collision meshes. Just let us know from now on that, i.e. every texture with the suffix _normal will be automatically set as such.
Felix Herbst
octubre 12, 2019 a las 12:10 pmAny information on when Presets will actually work for creating GameObjects? ar Presets are currently not used at all when e.g. creating a new cube – the Components in that cube should respect the presets for them and only apply necessary changes on top (e.g. use a cube mesh).
Ed
octubre 12, 2019 a las 12:55 amSupport for applying a preset to all assets in a folder would be invaluable. Making sure Texture assets are imported with a standard set of settings is a common use case we’ve had to implement manually before, but presets would be perfect for this.
Gleb
octubre 12, 2019 a las 12:02 amWhy don’t you use regex values for filtering multiple defaults per type, it will help to avoid such problems as applying a preset to GuideCamera gameobject because of «ui» part which is not even case sensitive? ((
Kailash C Vetal
octubre 11, 2019 a las 7:30 pmDoes preset manager works with the Player Settings preset ?
Marc Tanenbaum
octubre 11, 2019 a las 7:44 pm@Kailash The Preset Manager does not at present support Presets for other project managers. It’s a perfectly valid use case, though, and one we’re considering. Thanks for the question!
Pieter
octubre 14, 2019 a las 11:30 amThis would be very useful to create different player configurations for debug builds and release builds. We can then just modify the presets and apply those depending on which build we want to trigger.
Brian
octubre 16, 2019 a las 10:32 pmGood call, this would be useful!
The Tick
octubre 11, 2019 a las 6:25 pmReally cool blog, i need to start using it presets more.