How do you make a separate blend tree asset?

5823484--617119--upload_2020-5-8_18-6-14.png

How do you make the blend tree “separate”?

When a I create a blend tree in an animation controller nothing shows up in the assets.

I believe that a blend tree is embedded in the animation controller and can’t be created on his own as an asset.
You might want to take a look at animation controller override asset instead.

Hmm, that doesn’t seem to be it, I need the BlendTree to be an asset so it can be referenced by another script’s public BlendTree tree property. I managed to create one by just copying the asset data, but I couldn’t find a way to create one through the editor.

Well accessing the BlendTree through a script and having it as an asset are two different things.

Here’s a thread that talks about that:

What are you trying to do with that blend tree?

I’m following Unity.Animation samples along and this is the pattern they seem to follow.

public class AnimationAuthor : MonoBehaviour, IConvertGameObjectToEntity, IDeclareReferencedPrefabs
{
    public BlendTree BlendTree;
    public GameObject RigPrefab;

    public void Convert(Entity entity, EntityManager manager, GameObjectConversionSystem converter)
    {
        ...

        var blendTreeIndex = BlendTreeConversion.Convert(BlendTree, rigEntity, manager, bakeOptions);
        manager.AddComponentData(rigEntity, new BlendTreeIndex { Value = blendTreeIndex });
    }
}

https://github.com/Unity-Technologies/Unity.Animation.Samples/blob/master/UnityAnimationHDRPExamples/Assets/Scenes/Examples/BlendTree1D/BlendTree1DGraph.cs#L10-L30

It seems to be how they get UnityEngine animations into the ECS world

From there the inputs to the blend tree are generated by a data flow graph (I think)

I’m honestly not sure about all that. The only thing I know is that you can create a blend tree in an asset in advance and override the animations using the “animation controller override” asset. That’s what I do.

        [MenuItem("Assets/Create/Blend Tree")]
        private static void CreateBlendTree()
        {
            var asset = new BlendTree();
            MethodInfo _tryGetActiveFolderPath = typeof(ProjectWindowUtil).GetMethod("TryGetActiveFolderPath", BindingFlags.Static | BindingFlags.NonPublic);

            object[] args = new object[] { null };
            bool found = (bool)_tryGetActiveFolderPath.Invoke(null, args);
            string path = (string)args[0];
            if (found)
            {
                path += "/" + $"{ObjectNames.GetUniqueName(new[] { "NewBlendTree" }, "NewBlendTree")}.asset";
                AssetDatabase.CreateAsset(asset, path);
            }
        }

The post above no longer works as of 2022.3.62 - here’s an updated version:

using System.Reflection;
using System.Linq;
using System.IO;
using UnityEditor;
using UnityEditor.Animations;
using UnityEngine;

namespace Assets
{
	public static class MenuItems
	{
		[MenuItem("Assets/Create/Blend Tree")]
		private static void CreateBlendTree()
		{
			var asset = new BlendTree();
			MethodInfo _tryGetActiveFolderPath = typeof(ProjectWindowUtil).GetMethod("TryGetActiveFolderPath", BindingFlags.Static | BindingFlags.NonPublic);

			object[] args = new object[] { null };
			bool found = (bool)_tryGetActiveFolderPath.Invoke(null, args);
			string path = (string)args[0];
			if (found)
			{
				path += "/" + $"{ObjectNames.GetUniqueName(new[] { "NewBlendTree" }, "NewBlendTree")}.asset";
				AssetDatabase.CreateAsset(asset, path);
			}
		}

		[MenuItem("Assets/Extract Blend Trees")]
		private static void ExtractBlendTrees()
		{
			Selection.objects
				.Cast<Object>()
				.Where(EditorUtility.IsPersistent)
				.Select(AssetDatabase.GetAssetPath)
				.SelectMany(AssetDatabase.LoadAllAssetsAtPath)
				.Where(a => a is BlendTree)
				.ToList()
				.ForEach(a =>
				{
					string path = AssetDatabase.GetAssetPath(a);
					var newAsset = Object.Instantiate(a);
					path = ObjectNames.GetUniqueName(new[] { path }, path);
					path = Path.ChangeExtension(path, "asset");
					AssetDatabase.CreateAsset(newAsset, path);
				});

			AssetDatabase.SaveAssets();
			AssetDatabase.Refresh();
		}
	}
}