From 12fe3f2c87c773018fc6b4136469c8a1b242c842 Mon Sep 17 00:00:00 2001 From: bd_ Date: Sun, 11 Sep 2022 14:53:25 -0700 Subject: [PATCH] Improve stability of locked merge armature system --- .../Runtime/MAInternalOffsetMarker.cs | 81 ----------- .../Runtime/MAInternalOffsetMarker.cs.meta | 3 - .../Runtime/ModularAvatarMergeArmature.cs | 136 ++++++++++++++---- 3 files changed, 108 insertions(+), 112 deletions(-) delete mode 100644 Packages/net.fushizen.modular-avatar/Runtime/MAInternalOffsetMarker.cs delete mode 100644 Packages/net.fushizen.modular-avatar/Runtime/MAInternalOffsetMarker.cs.meta diff --git a/Packages/net.fushizen.modular-avatar/Runtime/MAInternalOffsetMarker.cs b/Packages/net.fushizen.modular-avatar/Runtime/MAInternalOffsetMarker.cs deleted file mode 100644 index 08bdf40b..00000000 --- a/Packages/net.fushizen.modular-avatar/Runtime/MAInternalOffsetMarker.cs +++ /dev/null @@ -1,81 +0,0 @@ -/* - * MIT License - * - * Copyright (c) 2022 bd_ - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -using UnityEngine; - -namespace net.fushizen.modular_avatar.core -{ - [ExecuteInEditMode] - public class MAInternalOffsetMarker : AvatarTagComponent - { - void OnValidate() - { -#if MODULAR_AVATAR_DEBUG - hideFlags = HideFlags.None; -#else - hideFlags = HideFlags.HideInInspector; -#endif - } - - private const float POS_EPSILON = 0.01f; - private const float ROT_EPSILON = 0.01f; - - private Vector3 lastLocalPos; - private Vector3 lastLocalScale; - private Quaternion lastLocalRot; - - public Transform correspondingObject; - - public bool lockBasePosition; - - public void Update() - { - if (correspondingObject == null) return; - - // ReSharper disable once LocalVariableHidesMember - var transform = this.transform; - if ((transform.localPosition - lastLocalPos).sqrMagnitude > POS_EPSILON - || (transform.localScale - lastLocalScale).sqrMagnitude > POS_EPSILON - || Quaternion.Angle(lastLocalRot, transform.localRotation) > ROT_EPSILON) - { - if (lockBasePosition) transform.position = correspondingObject.position; - else correspondingObject.localPosition = transform.localPosition; - - correspondingObject.localScale = transform.localScale; - correspondingObject.localRotation = transform.localRotation; - } - else - { - if (lockBasePosition) transform.position = correspondingObject.position; - else transform.localPosition = correspondingObject.localPosition; - transform.localScale = correspondingObject.localScale; - transform.localRotation = correspondingObject.localRotation; - } - - lastLocalPos = transform.localPosition; - lastLocalScale = transform.localScale; - lastLocalRot = transform.localRotation; - } - } -} \ No newline at end of file diff --git a/Packages/net.fushizen.modular-avatar/Runtime/MAInternalOffsetMarker.cs.meta b/Packages/net.fushizen.modular-avatar/Runtime/MAInternalOffsetMarker.cs.meta deleted file mode 100644 index de60abbc..00000000 --- a/Packages/net.fushizen.modular-avatar/Runtime/MAInternalOffsetMarker.cs.meta +++ /dev/null @@ -1,3 +0,0 @@ -fileFormatVersion: 2 -guid: 7b59aa936ba8466e85aede8aa3631b84 -timeCreated: 1661807782 \ No newline at end of file diff --git a/Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarMergeArmature.cs b/Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarMergeArmature.cs index cb92d220..6912b696 100644 --- a/Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarMergeArmature.cs +++ b/Packages/net.fushizen.modular-avatar/Runtime/ModularAvatarMergeArmature.cs @@ -23,6 +23,8 @@ */ using System; +using System.Collections.Generic; +using UnityEditor; using UnityEngine; namespace net.fushizen.modular_avatar.core @@ -30,13 +32,26 @@ namespace net.fushizen.modular_avatar.core [ExecuteInEditMode] public class ModularAvatarMergeArmature : AvatarTagComponent { + private const float POS_EPSILON = 0.01f; + private const float ROT_EPSILON = 0.01f; + public GameObject mergeTarget; public string mergeTargetPath; public string prefix; public string suffix; public bool locked; - private bool wasLocked; + private class BoneBinding + { + public Transform baseBone; + public Transform mergeBone; + + public Vector3 lastLocalPos; + public Vector3 lastLocalScale; + public Quaternion lastLocalRot; + } + + private List lockedBones; void OnValidate() { RuntimeUtil.delayCall(() => @@ -70,50 +85,115 @@ namespace net.fushizen.modular_avatar.core }); } + private void OnEnable() + { + RuntimeUtil.delayCall(CheckLock); + } + + private void OnDisable() + { + RuntimeUtil.delayCall(CheckLock); + } + + private void OnDestroy() + { +#if UNITY_EDITOR + EditorApplication.update -= EditorUpdate; +#endif + } + + void EditorUpdate() + { + if (this == null || lockedBones == null) + { +#if UNITY_EDITOR + EditorApplication.update -= EditorUpdate; +#endif + return; + } + + if (lockedBones != null) + { + foreach (var bone in lockedBones) + { + if (bone.baseBone == null || bone.mergeBone == null) + { + lockedBones = null; + break; + } + + var mergeBone = bone.mergeBone; + var correspondingObject = bone.baseBone; + bool lockBasePosition = bone.baseBone == mergeTarget.transform; + + if ((mergeBone.localPosition - bone.lastLocalPos).sqrMagnitude > POS_EPSILON + || (mergeBone.localScale - bone.lastLocalScale).sqrMagnitude > POS_EPSILON + || Quaternion.Angle(bone.lastLocalRot, mergeBone.localRotation) > ROT_EPSILON) + { + if (lockBasePosition) mergeBone.position = correspondingObject.position; + else correspondingObject.localPosition = mergeBone.localPosition; + + correspondingObject.localScale = mergeBone.localScale; + correspondingObject.localRotation = mergeBone.localRotation; + } + else + { + if (lockBasePosition) mergeBone.position = correspondingObject.position; + else mergeBone.localPosition = correspondingObject.localPosition; + mergeBone.localScale = correspondingObject.localScale; + mergeBone.localRotation = correspondingObject.localRotation; + } + + bone.lastLocalPos = mergeBone.localPosition; + bone.lastLocalScale = mergeBone.localScale; + bone.lastLocalRot = mergeBone.localRotation; + } + } + } + void CheckLock() { if (RuntimeUtil.isPlaying) return; + + #if UNITY_EDITOR + EditorApplication.update -= EditorUpdate; + #endif - if (locked != wasLocked) + bool shouldLock = locked && isActiveAndEnabled; + bool wasLocked = lockedBones != null; + if (shouldLock != wasLocked) { - if (!locked) + if (!shouldLock) { - foreach (var comp in GetComponentsInChildren()) - { - DestroyImmediate(comp); - } - - wasLocked = false; + lockedBones = null; } else { if (mergeTarget == null) return; + lockedBones = new List(); + foreach (var xform in GetComponentsInChildren(true)) { Transform baseObject = FindCorresponding(xform); - var marker = xform.gameObject.GetComponent(); - - if (baseObject == null) + + lockedBones.Add(new BoneBinding() { - if (marker != null) - { - DestroyImmediate(marker); - } - } - else - { - if (marker == null) - { - marker = xform.gameObject.AddComponent(); - } - marker.correspondingObject = baseObject; - marker.lockBasePosition = baseObject.gameObject == mergeTarget; - } + baseBone = baseObject, + mergeBone = xform, + lastLocalPos = xform.localPosition, + lastLocalScale = xform.localScale, + lastLocalRot = xform.localRotation + }); } - - wasLocked = true; } } + +#if UNITY_EDITOR + if (locked) + { + EditorApplication.update += EditorUpdate; + } +#endif } private Transform FindCorresponding(Transform xform)