mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2025-02-21 13:45:03 +08:00
fix: improve build performance by ~10x
CreateAsset, as it turns out, can be extremely slow, particularly when used on Mesh objects. By adding our generated objects as sub-objects of a container AnimatorController, we can minimize this overhead.
This commit is contained in:
parent
b13f60e80f
commit
250e8be54c
@ -52,9 +52,9 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
private int controllerBaseLayer = 0;
|
private int controllerBaseLayer = 0;
|
||||||
|
|
||||||
public AnimatorCombiner()
|
public AnimatorCombiner(BuildContext context)
|
||||||
{
|
{
|
||||||
_combined = Util.CreateAnimator();
|
_combined = context.CreateAnimator();
|
||||||
}
|
}
|
||||||
|
|
||||||
public AnimatorController Finish()
|
public AnimatorController Finish()
|
||||||
|
@ -156,16 +156,16 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
var context = new BuildContext(vrcAvatarDescriptor);
|
var context = new BuildContext(vrcAvatarDescriptor);
|
||||||
|
|
||||||
new RenameParametersHook().OnPreprocessAvatar(avatarGameObject);
|
new RenameParametersHook().OnPreprocessAvatar(avatarGameObject, context);
|
||||||
new MergeAnimatorProcessor().OnPreprocessAvatar(avatarGameObject);
|
new MergeAnimatorProcessor().OnPreprocessAvatar(avatarGameObject, context);
|
||||||
context.AnimationDatabase.Bootstrap(vrcAvatarDescriptor);
|
context.AnimationDatabase.Bootstrap(vrcAvatarDescriptor);
|
||||||
|
|
||||||
new MenuInstallHook().OnPreprocessAvatar(avatarGameObject);
|
new MenuInstallHook().OnPreprocessAvatar(avatarGameObject, context);
|
||||||
new MergeArmatureHook().OnPreprocessAvatar(context, avatarGameObject);
|
new MergeArmatureHook().OnPreprocessAvatar(context, avatarGameObject);
|
||||||
new BoneProxyProcessor().OnPreprocessAvatar(avatarGameObject);
|
new BoneProxyProcessor().OnPreprocessAvatar(avatarGameObject);
|
||||||
new VisibleHeadAccessoryProcessor(vrcAvatarDescriptor).Process();
|
new VisibleHeadAccessoryProcessor(vrcAvatarDescriptor).Process();
|
||||||
new RemapAnimationPass(vrcAvatarDescriptor).Process(context.AnimationDatabase);
|
new RemapAnimationPass(vrcAvatarDescriptor).Process(context.AnimationDatabase);
|
||||||
new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject, context.AnimationDatabase);
|
new BlendshapeSyncAnimationProcessor().OnPreprocessAvatar(avatarGameObject, context);
|
||||||
PhysboneBlockerPass.Process(avatarGameObject);
|
PhysboneBlockerPass.Process(avatarGameObject);
|
||||||
|
|
||||||
context.AnimationDatabase.Commit();
|
context.AnimationDatabase.Commit();
|
||||||
|
@ -16,7 +16,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
*/
|
*/
|
||||||
internal class BlendshapeSyncAnimationProcessor
|
internal class BlendshapeSyncAnimationProcessor
|
||||||
{
|
{
|
||||||
private Object _container;
|
private BuildContext _context;
|
||||||
private Dictionary<Motion, Motion> _motionCache;
|
private Dictionary<Motion, Motion> _motionCache;
|
||||||
private Dictionary<SummaryBinding, List<SummaryBinding>> _bindingMappings;
|
private Dictionary<SummaryBinding, List<SummaryBinding>> _bindingMappings;
|
||||||
|
|
||||||
@ -43,8 +43,11 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OnPreprocessAvatar(GameObject avatar, AnimationDatabase animDb)
|
public void OnPreprocessAvatar(GameObject avatar, BuildContext context)
|
||||||
{
|
{
|
||||||
|
_context = context;
|
||||||
|
var animDb = _context.AnimationDatabase;
|
||||||
|
|
||||||
var avatarDescriptor = avatar.GetComponent<VRCAvatarDescriptor>();
|
var avatarDescriptor = avatar.GetComponent<VRCAvatarDescriptor>();
|
||||||
_bindingMappings = new Dictionary<SummaryBinding, List<SummaryBinding>>();
|
_bindingMappings = new Dictionary<SummaryBinding, List<SummaryBinding>>();
|
||||||
_motionCache = new Dictionary<Motion, Motion>();
|
_motionCache = new Dictionary<Motion, Motion>();
|
||||||
@ -145,15 +148,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
var newTree = new BlendTree();
|
var newTree = new BlendTree();
|
||||||
EditorUtility.CopySerialized(tree, newTree);
|
EditorUtility.CopySerialized(tree, newTree);
|
||||||
if (_container == null)
|
_context.SaveAsset(newTree);
|
||||||
{
|
|
||||||
_container = newTree;
|
|
||||||
AssetDatabase.CreateAsset(_container, Util.GenerateAssetPath());
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
AssetDatabase.AddObjectToAsset(newTree, _container);
|
|
||||||
}
|
|
||||||
|
|
||||||
newTree.children = children;
|
newTree.children = children;
|
||||||
motion = newTree;
|
motion = newTree;
|
||||||
|
@ -1,4 +1,9 @@
|
|||||||
using VRC.SDK3.Avatars.Components;
|
using System;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEditor.Animations;
|
||||||
|
using UnityEngine;
|
||||||
|
using VRC.SDK3.Avatars.Components;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
namespace nadena.dev.modular_avatar.core.editor
|
namespace nadena.dev.modular_avatar.core.editor
|
||||||
{
|
{
|
||||||
@ -6,10 +11,66 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
internal readonly VRCAvatarDescriptor AvatarDescriptor;
|
internal readonly VRCAvatarDescriptor AvatarDescriptor;
|
||||||
internal readonly AnimationDatabase AnimationDatabase = new AnimationDatabase();
|
internal readonly AnimationDatabase AnimationDatabase = new AnimationDatabase();
|
||||||
|
internal readonly AnimatorController AssetContainer;
|
||||||
|
|
||||||
public BuildContext(VRCAvatarDescriptor avatarDescriptor)
|
public BuildContext(VRCAvatarDescriptor avatarDescriptor)
|
||||||
{
|
{
|
||||||
AvatarDescriptor = avatarDescriptor;
|
AvatarDescriptor = avatarDescriptor;
|
||||||
|
|
||||||
|
// AssetDatabase.CreateAsset is super slow - so only do it once, and add everything else as sub-assets.
|
||||||
|
// This animator controller exists for the sole purpose of providing a placeholder to dump everything we
|
||||||
|
// generate into.
|
||||||
|
AssetContainer = new AnimatorController();
|
||||||
|
AssetDatabase.CreateAsset(AssetContainer, Util.GenerateAssetPath());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void SaveAsset(Object obj)
|
||||||
|
{
|
||||||
|
if (AssetDatabase.IsMainAsset(obj) || AssetDatabase.IsSubAsset(obj)) return;
|
||||||
|
|
||||||
|
AssetDatabase.AddObjectToAsset(obj, AssetContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimatorController CreateAnimator(AnimatorController toClone = null)
|
||||||
|
{
|
||||||
|
AnimatorController controller;
|
||||||
|
if (toClone != null)
|
||||||
|
{
|
||||||
|
controller = Object.Instantiate(toClone);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
controller = new AnimatorController();
|
||||||
|
}
|
||||||
|
|
||||||
|
SaveAsset(controller);
|
||||||
|
|
||||||
|
return controller;
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimatorController DeepCloneAnimator(RuntimeAnimatorController controller)
|
||||||
|
{
|
||||||
|
var merger = new AnimatorCombiner(this);
|
||||||
|
switch (controller)
|
||||||
|
{
|
||||||
|
case AnimatorController ac:
|
||||||
|
merger.AddController("", ac, null);
|
||||||
|
break;
|
||||||
|
case AnimatorOverrideController oac:
|
||||||
|
merger.AddOverrideController("", oac, null);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception("Unknown RuntimeAnimatorContoller type " + controller.GetType());
|
||||||
|
}
|
||||||
|
|
||||||
|
return merger.Finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
public AnimatorController ConvertAnimatorController(AnimatorOverrideController overrideController)
|
||||||
|
{
|
||||||
|
var merger = new AnimatorCombiner(this);
|
||||||
|
merger.AddOverrideController("", overrideController, null);
|
||||||
|
return merger.Finish();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
using VRC.SDK3.Avatars.Components;
|
using VRC.SDK3.Avatars.Components;
|
||||||
@ -16,6 +17,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
"Packages/nadena.dev.modular-avatar/Runtime/Icons/Icon_More_A.png"
|
"Packages/nadena.dev.modular-avatar/Runtime/Icons/Icon_More_A.png"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
private BuildContext _context;
|
||||||
|
|
||||||
private Dictionary<VRCExpressionsMenu, VRCExpressionsMenu> _clonedMenus;
|
private Dictionary<VRCExpressionsMenu, VRCExpressionsMenu> _clonedMenus;
|
||||||
|
|
||||||
|
|
||||||
@ -24,9 +27,12 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
private MenuTree _menuTree;
|
private MenuTree _menuTree;
|
||||||
private Stack<ModularAvatarMenuInstaller> _visitedInstallerStack;
|
private Stack<ModularAvatarMenuInstaller> _visitedInstallerStack;
|
||||||
|
|
||||||
public void OnPreprocessAvatar(GameObject avatarRoot)
|
public void OnPreprocessAvatar(GameObject avatarRoot, BuildContext context)
|
||||||
{
|
{
|
||||||
ModularAvatarMenuInstaller[] menuInstallers = avatarRoot.GetComponentsInChildren<ModularAvatarMenuInstaller>(true)
|
_context = context;
|
||||||
|
|
||||||
|
ModularAvatarMenuInstaller[] menuInstallers = avatarRoot
|
||||||
|
.GetComponentsInChildren<ModularAvatarMenuInstaller>(true)
|
||||||
.Where(menuInstaller => menuInstaller.enabled)
|
.Where(menuInstaller => menuInstaller.enabled)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
if (menuInstallers.Length == 0) return;
|
if (menuInstallers.Length == 0) return;
|
||||||
@ -40,7 +46,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
if (avatar.expressionsMenu == null)
|
if (avatar.expressionsMenu == null)
|
||||||
{
|
{
|
||||||
var menu = ScriptableObject.CreateInstance<VRCExpressionsMenu>();
|
var menu = ScriptableObject.CreateInstance<VRCExpressionsMenu>();
|
||||||
AssetDatabase.CreateAsset(menu, Util.GenerateAssetPath());
|
_context.SaveAsset(menu);
|
||||||
avatar.expressionsMenu = menu;
|
avatar.expressionsMenu = menu;
|
||||||
_clonedMenus[menu] = menu;
|
_clonedMenus[menu] = menu;
|
||||||
}
|
}
|
||||||
@ -100,7 +106,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
// Split target menu
|
// Split target menu
|
||||||
var newMenu = ScriptableObject.CreateInstance<VRCExpressionsMenu>();
|
var newMenu = ScriptableObject.CreateInstance<VRCExpressionsMenu>();
|
||||||
AssetDatabase.CreateAsset(newMenu, Util.GenerateAssetPath());
|
_context.SaveAsset(newMenu);
|
||||||
const int keepCount = VRCExpressionsMenu.MAX_CONTROLS - 1;
|
const int keepCount = VRCExpressionsMenu.MAX_CONTROLS - 1;
|
||||||
newMenu.controls.AddRange(targetMenu.controls.Skip(keepCount));
|
newMenu.controls.AddRange(targetMenu.controls.Skip(keepCount));
|
||||||
targetMenu.controls.RemoveRange(keepCount,
|
targetMenu.controls.RemoveRange(keepCount,
|
||||||
@ -131,7 +137,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
if (menu == null) return null;
|
if (menu == null) return null;
|
||||||
if (_clonedMenus.TryGetValue(menu, out var newMenu)) return newMenu;
|
if (_clonedMenus.TryGetValue(menu, out var newMenu)) return newMenu;
|
||||||
newMenu = Object.Instantiate(menu);
|
newMenu = Object.Instantiate(menu);
|
||||||
AssetDatabase.CreateAsset(newMenu, Util.GenerateAssetPath());
|
_context.SaveAsset(newMenu);
|
||||||
_clonedMenus[menu] = newMenu;
|
_clonedMenus[menu] = newMenu;
|
||||||
|
|
||||||
foreach (var control in newMenu.controls)
|
foreach (var control in newMenu.controls)
|
||||||
|
@ -39,6 +39,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
private const string SAMPLE_PATH_LEGACY = "Assets/VRCSDK/Examples3/Animation/Controllers";
|
private const string SAMPLE_PATH_LEGACY = "Assets/VRCSDK/Examples3/Animation/Controllers";
|
||||||
|
|
||||||
|
private BuildContext _context;
|
||||||
|
|
||||||
private Dictionary<VRCAvatarDescriptor.AnimLayerType, AnimatorController> defaultControllers_ =
|
private Dictionary<VRCAvatarDescriptor.AnimLayerType, AnimatorController> defaultControllers_ =
|
||||||
new Dictionary<VRCAvatarDescriptor.AnimLayerType, AnimatorController>();
|
new Dictionary<VRCAvatarDescriptor.AnimLayerType, AnimatorController>();
|
||||||
|
|
||||||
@ -48,8 +50,10 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
Dictionary<VRCAvatarDescriptor.AnimLayerType, AnimatorCombiner> mergeSessions =
|
Dictionary<VRCAvatarDescriptor.AnimLayerType, AnimatorCombiner> mergeSessions =
|
||||||
new Dictionary<VRCAvatarDescriptor.AnimLayerType, AnimatorCombiner>();
|
new Dictionary<VRCAvatarDescriptor.AnimLayerType, AnimatorCombiner>();
|
||||||
|
|
||||||
internal void OnPreprocessAvatar(GameObject avatarGameObject)
|
internal void OnPreprocessAvatar(GameObject avatarGameObject, BuildContext context)
|
||||||
{
|
{
|
||||||
|
_context = context;
|
||||||
|
|
||||||
defaultControllers_.Clear();
|
defaultControllers_.Clear();
|
||||||
mergeSessions.Clear();
|
mergeSessions.Clear();
|
||||||
|
|
||||||
@ -77,7 +81,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
if (!mergeSessions.TryGetValue(merge.layerType, out var session))
|
if (!mergeSessions.TryGetValue(merge.layerType, out var session))
|
||||||
{
|
{
|
||||||
session = new AnimatorCombiner();
|
session = new AnimatorCombiner(context);
|
||||||
mergeSessions[merge.layerType] = session;
|
mergeSessions[merge.layerType] = session;
|
||||||
if (defaultControllers_.ContainsKey(merge.layerType))
|
if (defaultControllers_.ContainsKey(merge.layerType))
|
||||||
{
|
{
|
||||||
@ -131,7 +135,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
// For non-default layers, ensure we always clone the controller for the benefit of subsequent
|
// For non-default layers, ensure we always clone the controller for the benefit of subsequent
|
||||||
// processing phases
|
// processing phases
|
||||||
mergeSessions[layer.type] = new AnimatorCombiner();
|
mergeSessions[layer.type] = new AnimatorCombiner(_context);
|
||||||
mergeSessions[layer.type].AddController("", controller, null);
|
mergeSessions[layer.type].AddController("", controller, null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
RetainBoneReferences(c as Component);
|
RetainBoneReferences(c as Component);
|
||||||
}
|
}
|
||||||
|
|
||||||
new RetargetMeshes().OnPreprocessAvatar(avatarGameObject);
|
new RetargetMeshes().OnPreprocessAvatar(avatarGameObject, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RetainBoneReferences(Component c)
|
private void RetainBoneReferences(Component c)
|
||||||
|
@ -77,8 +77,12 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
internal class RetargetMeshes
|
internal class RetargetMeshes
|
||||||
{
|
{
|
||||||
internal void OnPreprocessAvatar(GameObject avatarGameObject)
|
private BuildContext _context;
|
||||||
|
|
||||||
|
internal void OnPreprocessAvatar(GameObject avatarGameObject, BuildContext context)
|
||||||
{
|
{
|
||||||
|
_context = context;
|
||||||
|
|
||||||
foreach (var renderer in avatarGameObject.GetComponentsInChildren<SkinnedMeshRenderer>(true))
|
foreach (var renderer in avatarGameObject.GetComponentsInChildren<SkinnedMeshRenderer>(true))
|
||||||
{
|
{
|
||||||
bool isRetargetable = false;
|
bool isRetargetable = false;
|
||||||
@ -93,7 +97,8 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
|
|
||||||
if (isRetargetable)
|
if (isRetargetable)
|
||||||
{
|
{
|
||||||
new MeshRetargeter(renderer).Retarget();
|
var newMesh = new MeshRetargeter(renderer).Retarget();
|
||||||
|
_context.SaveAsset(newMesh);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,7 +144,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
this.renderer = renderer;
|
this.renderer = renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Retarget()
|
public Mesh Retarget()
|
||||||
{
|
{
|
||||||
var avatar = RuntimeUtil.FindAvatarInParents(renderer.transform);
|
var avatar = RuntimeUtil.FindAvatarInParents(renderer.transform);
|
||||||
if (avatar == null) throw new System.Exception("Could not find avatar in parents of " + renderer.name);
|
if (avatar == null) throw new System.Exception("Could not find avatar in parents of " + renderer.name);
|
||||||
@ -164,7 +169,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
avatarTransform.rotation = avRot;
|
avatarTransform.rotation = avRot;
|
||||||
avatarTransform.localScale = avScale;
|
avatarTransform.localScale = avScale;
|
||||||
|
|
||||||
AssetDatabase.CreateAsset(dst, Util.GenerateAssetPath());
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void AdjustShapeKeys()
|
private void AdjustShapeKeys()
|
||||||
|
@ -17,13 +17,17 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
{
|
{
|
||||||
private const string DEFAULT_EXP_PARAMS_ASSET_GUID = "03a6d797deb62f0429471c4e17ea99a7";
|
private const string DEFAULT_EXP_PARAMS_ASSET_GUID = "03a6d797deb62f0429471c4e17ea99a7";
|
||||||
|
|
||||||
|
private BuildContext _context;
|
||||||
|
|
||||||
private int internalParamIndex = 0;
|
private int internalParamIndex = 0;
|
||||||
|
|
||||||
private Dictionary<string, VRCExpressionParameters.Parameter> _syncedParams =
|
private Dictionary<string, VRCExpressionParameters.Parameter> _syncedParams =
|
||||||
new Dictionary<string, VRCExpressionParameters.Parameter>();
|
new Dictionary<string, VRCExpressionParameters.Parameter>();
|
||||||
|
|
||||||
public void OnPreprocessAvatar(GameObject avatar)
|
public void OnPreprocessAvatar(GameObject avatar, BuildContext context)
|
||||||
{
|
{
|
||||||
|
_context = context;
|
||||||
|
|
||||||
_syncedParams.Clear();
|
_syncedParams.Clear();
|
||||||
|
|
||||||
WalkTree(avatar, ImmutableDictionary<string, string>.Empty, ImmutableDictionary<string, string>.Empty);
|
WalkTree(avatar, ImmutableDictionary<string, string>.Empty, ImmutableDictionary<string, string>.Empty);
|
||||||
@ -49,7 +53,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
}
|
}
|
||||||
|
|
||||||
expParams = Object.Instantiate(expParams);
|
expParams = Object.Instantiate(expParams);
|
||||||
AssetDatabase.CreateAsset(expParams, Util.GenerateAssetPath());
|
_context.SaveAsset(expParams);
|
||||||
|
|
||||||
var knownParams = expParams.parameters.Select(p => p.name).ToImmutableHashSet();
|
var knownParams = expParams.parameters.Select(p => p.name).ToImmutableHashSet();
|
||||||
var parameters = expParams.parameters.ToList();
|
var parameters = expParams.parameters.ToList();
|
||||||
@ -129,7 +133,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
// RuntimeAnimatorController may be AnimatorOverrideController, convert in case of AnimatorOverrideController
|
// RuntimeAnimatorController may be AnimatorOverrideController, convert in case of AnimatorOverrideController
|
||||||
if (anim.runtimeAnimatorController is AnimatorOverrideController overrideController)
|
if (anim.runtimeAnimatorController is AnimatorOverrideController overrideController)
|
||||||
{
|
{
|
||||||
anim.runtimeAnimatorController = Util.ConvertAnimatorController(overrideController);
|
anim.runtimeAnimatorController = _context.ConvertAnimatorController(overrideController);
|
||||||
}
|
}
|
||||||
|
|
||||||
var controller = anim.runtimeAnimatorController as AnimatorController;
|
var controller = anim.runtimeAnimatorController as AnimatorController;
|
||||||
@ -147,7 +151,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
// RuntimeAnimatorController may be AnimatorOverrideController, convert in case of AnimatorOverrideController
|
// RuntimeAnimatorController may be AnimatorOverrideController, convert in case of AnimatorOverrideController
|
||||||
if (merger.animator is AnimatorOverrideController overrideController)
|
if (merger.animator is AnimatorOverrideController overrideController)
|
||||||
{
|
{
|
||||||
merger.animator = Util.ConvertAnimatorController(overrideController);
|
merger.animator = _context.ConvertAnimatorController(overrideController);
|
||||||
}
|
}
|
||||||
|
|
||||||
var controller = merger.animator as AnimatorController;
|
var controller = merger.animator as AnimatorController;
|
||||||
@ -192,7 +196,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
if (remapped.TryGetValue(menu, out var newMenu)) return newMenu;
|
if (remapped.TryGetValue(menu, out var newMenu)) return newMenu;
|
||||||
|
|
||||||
newMenu = Object.Instantiate(menu);
|
newMenu = Object.Instantiate(menu);
|
||||||
AssetDatabase.CreateAsset(newMenu, Util.GenerateAssetPath());
|
_context.SaveAsset(newMenu);
|
||||||
remapped[menu] = newMenu;
|
remapped[menu] = newMenu;
|
||||||
ClonedMenuMappings.Add(menu, newMenu);
|
ClonedMenuMappings.Add(menu, newMenu);
|
||||||
|
|
||||||
@ -222,7 +226,7 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
// Deep clone the animator
|
// Deep clone the animator
|
||||||
if (!Util.IsTemporaryAsset(controller))
|
if (!Util.IsTemporaryAsset(controller))
|
||||||
{
|
{
|
||||||
controller = Util.DeepCloneAnimator(controller);
|
controller = _context.DeepCloneAnimator(controller);
|
||||||
}
|
}
|
||||||
|
|
||||||
var parameters = controller.parameters;
|
var parameters = controller.parameters;
|
||||||
|
@ -60,23 +60,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
EditorApplication.hierarchyChanged += () => { RuntimeUtil.InvokeHierarchyChanged(); };
|
EditorApplication.hierarchyChanged += () => { RuntimeUtil.InvokeHierarchyChanged(); };
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AnimatorController CreateAnimator(AnimatorController toClone = null)
|
|
||||||
{
|
|
||||||
AnimatorController controller;
|
|
||||||
if (toClone != null)
|
|
||||||
{
|
|
||||||
controller = Object.Instantiate(toClone);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
controller = new AnimatorController();
|
|
||||||
}
|
|
||||||
|
|
||||||
AssetDatabase.CreateAsset(controller, GenerateAssetPath());
|
|
||||||
|
|
||||||
return controller;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static string GenerateAssetPath()
|
public static string GenerateAssetPath()
|
||||||
{
|
{
|
||||||
return GetGeneratedAssetsFolder() + "/" + GUID.Generate() + ".asset";
|
return GetGeneratedAssetsFolder() + "/" + GUID.Generate() + ".asset";
|
||||||
@ -113,31 +96,6 @@ namespace nadena.dev.modular_avatar.core.editor
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public static AnimatorController DeepCloneAnimator(RuntimeAnimatorController controller)
|
|
||||||
{
|
|
||||||
var merger = new AnimatorCombiner();
|
|
||||||
switch (controller)
|
|
||||||
{
|
|
||||||
case AnimatorController ac:
|
|
||||||
merger.AddController("", ac, null);
|
|
||||||
break;
|
|
||||||
case AnimatorOverrideController oac:
|
|
||||||
merger.AddOverrideController("", oac, null);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new Exception("Unknown RuntimeAnimatorContoller type " + controller.GetType());
|
|
||||||
}
|
|
||||||
|
|
||||||
return merger.Finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static AnimatorController ConvertAnimatorController(AnimatorOverrideController overrideController)
|
|
||||||
{
|
|
||||||
var merger = new AnimatorCombiner();
|
|
||||||
merger.AddOverrideController("", overrideController, null);
|
|
||||||
return merger.Finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool IsTemporaryAsset(Object obj)
|
public static bool IsTemporaryAsset(Object obj)
|
||||||
{
|
{
|
||||||
var path = AssetDatabase.GetAssetPath(obj);
|
var path = AssetDatabase.GetAssetPath(obj);
|
||||||
|
Loading…
Reference in New Issue
Block a user