diff --git a/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/ArmatureLockController.cs b/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/ArmatureLockController.cs index 2d1a7e01..b5464431 100644 --- a/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/ArmatureLockController.cs +++ b/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/ArmatureLockController.cs @@ -10,6 +10,9 @@ namespace nadena.dev.modular_avatar.core.armature_lock { internal class ArmatureLockController : IDisposable { + private static long lastMovedFrame = 0; + public static bool MovedThisFrame => Time.frameCount == lastMovedFrame; + // Undo operations can reinitialize the MAMA component, which destroys critical lock controller state. // Avoid this issue by keeping a static reference to the controller for each MAMA component. private static Dictionary @@ -32,11 +35,11 @@ namespace nadena.dev.modular_avatar.core.armature_lock #if UNITY_EDITOR if (value) { - EditorApplication.update += VoidUpdate; + UpdateLoopController.OnArmatureLockUpdate += VoidUpdate; } else { - EditorApplication.update -= VoidUpdate; + UpdateLoopController.OnArmatureLockUpdate -= VoidUpdate; } _updateActive = value; @@ -121,6 +124,11 @@ namespace nadena.dev.modular_avatar.core.armature_lock if (_curMode == _mode) { result = _lock?.Execute() ?? LockResult.Failed; + if (result == LockResult.Success) + { + lastMovedFrame = Time.frameCount; + } + if (result != LockResult.Failed) return true; } diff --git a/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/OnewayArmatureLock.cs b/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/OnewayArmatureLock.cs index f263f54f..cca1b30f 100644 --- a/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/OnewayArmatureLock.cs +++ b/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/OnewayArmatureLock.cs @@ -50,7 +50,7 @@ namespace nadena.dev.modular_avatar.core.armature_lock } } - [BurstCompile] + //[BurstCompile] struct ComputePosition : IJobParallelFor { [ReadOnly] public NativeArray _boneStatic; @@ -75,6 +75,7 @@ namespace nadena.dev.modular_avatar.core.armature_lock if (TransformState.Differs(mergeSaved, mergeState)) { + TransformState.Differs(mergeSaved, mergeState); _fault.Increment(); } diff --git a/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/UpdateLoopController.cs b/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/UpdateLoopController.cs new file mode 100644 index 00000000..c9f03c84 --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/UpdateLoopController.cs @@ -0,0 +1,24 @@ +using System; + +namespace nadena.dev.modular_avatar.core.armature_lock +{ + internal static class UpdateLoopController + { + internal static event Action OnArmatureLockUpdate; + internal static event Action OnMoveIndependentlyUpdate; + +#if UNITY_EDITOR + [UnityEditor.InitializeOnLoadMethod] + private static void Init() + { +#if UNITY_EDITOR + UnityEditor.EditorApplication.update += () => + { + OnArmatureLockUpdate?.Invoke(); + OnMoveIndependentlyUpdate?.Invoke(); + }; +#endif + } +#endif + } +} \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/UpdateLoopController.cs.meta b/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/UpdateLoopController.cs.meta new file mode 100644 index 00000000..bcb64e6b --- /dev/null +++ b/Packages/nadena.dev.modular-avatar/Runtime/ArmatureAwase/UpdateLoopController.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 5f22557c7545402e89ebceae70132d85 +timeCreated: 1695811856 \ No newline at end of file diff --git a/Packages/nadena.dev.modular-avatar/Runtime/MAMoveIndependently.cs b/Packages/nadena.dev.modular-avatar/Runtime/MAMoveIndependently.cs index 9591ce6a..844172d9 100644 --- a/Packages/nadena.dev.modular-avatar/Runtime/MAMoveIndependently.cs +++ b/Packages/nadena.dev.modular-avatar/Runtime/MAMoveIndependently.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using nadena.dev.modular_avatar.core.armature_lock; using UnityEngine; using VRC.SDKBase; @@ -111,7 +112,7 @@ namespace nadena.dev.modular_avatar.core.ArmatureAwase var localRotation = child.localRotation; var localScale = child.localScale; - if (_children.TryGetValue(child, out var state)) + if (!ArmatureLockController.MovedThisFrame && _children.TryGetValue(child, out var state)) { var deltaPos = localPosition - state.childLocalPos; var deltaRot = Quaternion.Angle(localRotation, state.childLocalRot); @@ -120,16 +121,27 @@ namespace nadena.dev.modular_avatar.core.ArmatureAwase if (deltaPos.sqrMagnitude < EPSILON && deltaRot < EPSILON && deltaScale < EPSILON) { Matrix4x4 childNewLocal = parent.worldToLocalMatrix * state.childWorld; -#if UNITY_EDITOR - UnityEditor.Undo.RecordObject(child, UnityEditor.Undo.GetCurrentGroupName()); -#endif - child.localPosition = childNewLocal.MultiplyPoint(Vector3.zero); - child.localRotation = childNewLocal.rotation; - child.localScale = childNewLocal.lossyScale; - state.childLocalPos = child.localPosition; - state.childLocalRot = child.localRotation; - state.childLocalScale = child.localScale; + var newPosition = childNewLocal.MultiplyPoint(Vector3.zero); + var newRotation = childNewLocal.rotation; + var newScale = childNewLocal.lossyScale; + + if ((newPosition - localPosition).sqrMagnitude > EPSILON + || Quaternion.Angle(newRotation, localRotation) > EPSILON + || (newScale - localScale).sqrMagnitude > EPSILON) + { +#if UNITY_EDITOR + UnityEditor.Undo.RecordObject(child, UnityEditor.Undo.GetCurrentGroupName()); +#endif + + child.localPosition = newPosition; + child.localRotation = newRotation; + child.localScale = newScale; + + state.childLocalPos = child.localPosition; + state.childLocalRot = child.localRotation; + state.childLocalScale = child.localScale; + } _children[child] = state; @@ -151,8 +163,24 @@ namespace nadena.dev.modular_avatar.core.ArmatureAwase } } - void Update() + private void OnEnable() { + UpdateLoopController.OnMoveIndependentlyUpdate += OnUpdate; + } + + private void OnDisable() + { + UpdateLoopController.OnMoveIndependentlyUpdate -= OnUpdate; + } + + void OnUpdate() + { + if (this == null) + { + UpdateLoopController.OnMoveIndependentlyUpdate -= OnUpdate; + return; + } + var deltaPos = transform.position - _priorFrameState.MultiplyPoint(Vector3.zero); var deltaRot = Quaternion.Angle(_priorFrameState.rotation, transform.rotation); var deltaScale = (transform.lossyScale - _priorFrameState.lossyScale).sqrMagnitude;