bd_ e471df8860
fix: incorrect first layer weights in Merge Animator (#1473)
Unity ignores the weight of the first layer in a controller, and forces it to one; here, we replicate that behavior in Merge Animator.

Note that we choose to do this here rather than in NDMF - this is because NDMF-level APIs are trying to accurately represent the data in the animator, and should be able to round-trip even "garbage" data there.

Closes: https://github.com/bdunderscore/ndmf/issues/534
Closes: #1472
2025-03-07 18:41:26 -08:00

106 lines
3.5 KiB
C#

#if MA_VRCSDK3_AVATARS
using modular_avatar_tests;
using nadena.dev.modular_avatar.animation;
using nadena.dev.modular_avatar.core;
using nadena.dev.modular_avatar.core.editor;
using nadena.dev.ndmf;
using nadena.dev.ndmf.animator;
using NUnit.Framework;
using UnityEditor.Animations;
using UnityEngine;
using VRC.SDK3.Avatars.Components;
using BuildContext = nadena.dev.ndmf.BuildContext;
namespace UnitTests.MergeAnimatorTests
{
internal class MergeSingleTests : TestBase
{
[Test]
public void NoErrorWhenAnimatorIsNull()
{
var av = CreateRoot("root");
var merge = av.AddComponent<ModularAvatarMergeAnimator>();
var ctx = new BuildContext(av, null);
ctx.ActivateExtensionContext<ModularAvatarContext>();
ctx.ActivateExtensionContextRecursive<AnimatorServicesContext>();
var errors = ErrorReport.CaptureErrors(() =>
{
new MergeAnimatorProcessor().OnPreprocessAvatar(av, ctx);
ctx.DeactivateAllExtensionContexts();
});
Assert.IsEmpty(errors);
}
[Test]
public void MergeAnimationOverrideController()
{
var av = CreateRoot("root");
var merge = av.AddComponent<ModularAvatarMergeAnimator>();
merge.animator = LoadAsset<AnimatorOverrideController>("AOC_Override.overrideController");
var ctx = new BuildContext(av, null);
ctx.ActivateExtensionContext<ModularAvatarContext>();
ctx.ActivateExtensionContextRecursive<AnimatorServicesContext>();
var errors = ErrorReport.CaptureErrors(() =>
{
new MergeAnimatorProcessor().OnPreprocessAvatar(av, ctx);
ctx.DeactivateAllExtensionContexts();
});
ctx.DeactivateAllExtensionContexts();
Assert.IsEmpty(errors);
var state = FindStateInLayer(findFxLayer(av, "Target"), "Anim1");
Assert.IsTrue(state.motion.name.StartsWith("Anim2"));
}
[Test]
public void MergeAnimation_ForcesFirstLayerToWeightOne()
{
var av = CreateRoot("root");
var controller = new AnimatorController();
var stateMachine = new AnimatorStateMachine();
stateMachine.name = "test machine";
controller.AddLayer(new AnimatorControllerLayer()
{
name = "Base",
stateMachine = stateMachine,
defaultWeight = 0
});
var merge = av.AddComponent<ModularAvatarMergeAnimator>();
merge.animator = controller;
merge.layerType = VRCAvatarDescriptor.AnimLayerType.FX;
var ctx = new BuildContext(av, null);
ctx.ActivateExtensionContext<ModularAvatarContext>();
ctx.ActivateExtensionContextRecursive<AnimatorServicesContext>();
var errors = ErrorReport.CaptureErrors(() =>
{
new MergeAnimatorProcessor().OnPreprocessAvatar(av, ctx);
ctx.DeactivateAllExtensionContexts();
});
ctx.DeactivateAllExtensionContexts();
Assert.IsEmpty(errors);
var layer = ((AnimatorController) FindFxController(av).animatorController).layers[^1];
Assert.AreEqual(1, layer.defaultWeight);
}
}
}
#endif