diff --git a/.github/ProjectRoot/vpm-manifest-2022.json b/.github/ProjectRoot/vpm-manifest-2022.json index eaba4f86..60d7c06f 100644 --- a/.github/ProjectRoot/vpm-manifest-2022.json +++ b/.github/ProjectRoot/vpm-manifest-2022.json @@ -19,7 +19,7 @@ "dependencies": {} }, "nadena.dev.ndmf": { - "version": "1.5.0" + "version": "1.5.3" } } } \ No newline at end of file diff --git a/.github/workflows/deploy-pages.yml b/.github/workflows/deploy-pages.yml index 2ee06ea0..ec465e5c 100644 --- a/.github/workflows/deploy-pages.yml +++ b/.github/workflows/deploy-pages.yml @@ -122,7 +122,7 @@ jobs: workingDirectory: docs-site~ - name: Purge cache - uses: nathanvaughn/actions-cloudflare-purge@cd4afdf666c2e6a6720048f27ac9cbdd664a673a + uses: nathanvaughn/actions-cloudflare-purge@992cc4e96422fb8ddf077281678373fe41e7736c continue-on-error: true with: cf_zone: ${{ secrets.CF_ZONE_ID }} diff --git a/.github/workflows/gameci.yml b/.github/workflows/gameci.yml index 2d30547d..adf05e8e 100644 --- a/.github/workflows/gameci.yml +++ b/.github/workflows/gameci.yml @@ -116,6 +116,7 @@ jobs: with: repos: | https://vpm.nadena.dev/vpm-prerelease.json + https://vrchat.github.io/packages/index.json?download - if: ${{ steps.setup.outputs.should_test == 'true' }} name: "Debug: List project contents" diff --git a/Editor/Animation/AnimationDatabase.cs b/Editor/Animation/AnimationDatabase.cs index bf788923..dd594092 100644 --- a/Editor/Animation/AnimationDatabase.cs +++ b/Editor/Animation/AnimationDatabase.cs @@ -53,7 +53,21 @@ namespace nadena.dev.modular_avatar.animation set { _originalClip = value; - IsProxyAnimation = value != null && Util.IsProxyAnimation(value); + + var baseClip = ObjectRegistry.GetReference(value)?.Object as AnimationClip; + + IsProxyAnimation = false; + if (value != null && Util.IsProxyAnimation(value)) + { + IsProxyAnimation = true; + } + else if (baseClip != null && Util.IsProxyAnimation(baseClip)) + { + // RenameParametersPass replaces proxy clips outside of the purview of the animation database, + // so trace this using ObjectRegistry and correct the reference. + IsProxyAnimation = true; + _originalClip = baseClip; + } } } diff --git a/Editor/Animation/AnimatorCombiner.cs b/Editor/Animation/AnimatorCombiner.cs index 674140dc..6a64fe28 100644 --- a/Editor/Animation/AnimatorCombiner.cs +++ b/Editor/Animation/AnimatorCombiner.cs @@ -573,6 +573,8 @@ namespace nadena.dev.modular_avatar.animation private AnimatorStateMachine mapStateMachine(string basePath, AnimatorStateMachine layerStateMachine) { + if (layerStateMachine == null) return null; + var cacheKey = new KeyValuePair(basePath, layerStateMachine); if (_stateMachines.TryGetValue(cacheKey, out var asm)) diff --git a/Editor/Animation/GameObjectDisableDelayPass.cs b/Editor/Animation/GameObjectDisableDelayPass.cs index 1814e45a..87692657 100644 --- a/Editor/Animation/GameObjectDisableDelayPass.cs +++ b/Editor/Animation/GameObjectDisableDelayPass.cs @@ -1,10 +1,12 @@ #if MA_VRCSDK3_AVATARS using System.Linq; +using nadena.dev.modular_avatar.core.editor; using nadena.dev.ndmf; using UnityEditor; using UnityEditor.Animations; using UnityEngine; using VRC.SDK3.Avatars.Components; +using BuildContext = nadena.dev.ndmf.BuildContext; namespace nadena.dev.modular_avatar.animation { @@ -24,11 +26,16 @@ namespace nadena.dev.modular_avatar.animation if (fx == null) return; + var nullMotion = new AnimationClip(); + nullMotion.name = "NullMotion"; + var blendTree = new BlendTree(); blendTree.blendType = BlendTreeType.Direct; blendTree.useAutomaticThresholds = false; - blendTree.children = asc.BoundReadableProperties.Select(GenerateDelayChild).ToArray(); + blendTree.children = asc.BoundReadableProperties + .Select(prop => GenerateDelayChild(nullMotion, prop)) + .ToArray(); var asm = new AnimatorStateMachine(); var state = new AnimatorState(); @@ -53,9 +60,24 @@ namespace nadena.dev.modular_avatar.animation defaultWeight = 1, blendingMode = AnimatorLayerBlendingMode.Override }).ToArray(); + + // Ensure the initial state of readable props matches the actual state of the gameobject + var parameters = fx.parameters; + var paramToIndex = parameters.Select((p, i) => (p, i)).ToDictionary(x => x.p.name, x => x.i); + foreach (var (binding, prop) in asc.BoundReadableProperties) + { + var obj = asc.PathMappings.PathToObject(binding.path); + + if (obj != null && paramToIndex.TryGetValue(prop, out var index)) + { + parameters[index].defaultFloat = obj.activeSelf ? 1 : 0; + } + } + + fx.parameters = parameters; } - private ChildMotion GenerateDelayChild((EditorCurveBinding, string) binding) + private ChildMotion GenerateDelayChild(Motion nullMotion, (EditorCurveBinding, string) binding) { var ecb = binding.Item1; var prop = binding.Item2; @@ -65,10 +87,40 @@ namespace nadena.dev.modular_avatar.animation curve.AddKey(0, 1); AnimationUtility.SetEditorCurve(motion, ecb, curve); + // Occasionally, we'll have a very small value pop up, probably due to FP errors. + // To correct for this, instead of directly using the property in the direct blend tree, + // we'll use a 1D blend tree to give ourselves a buffer. + + var bufferBlendTree = new BlendTree(); + bufferBlendTree.blendType = BlendTreeType.Simple1D; + bufferBlendTree.useAutomaticThresholds = false; + bufferBlendTree.blendParameter = prop; + bufferBlendTree.children = new[] + { + new ChildMotion + { + motion = nullMotion, + timeScale = 1, + threshold = 0 + }, + new ChildMotion + { + motion = nullMotion, + timeScale = 1, + threshold = 0.01f + }, + new ChildMotion + { + motion = motion, + timeScale = 1, + threshold = 1 + } + }; + return new ChildMotion { - motion = motion, - directBlendParameter = prop, + motion = bufferBlendTree, + directBlendParameter = MergeBlendTreePass.ALWAYS_ONE, timeScale = 1 }; } diff --git a/Editor/HarmonyPatches/PatchLoader.cs b/Editor/HarmonyPatches/PatchLoader.cs index 0ce7ffa4..b368fca7 100644 --- a/Editor/HarmonyPatches/PatchLoader.cs +++ b/Editor/HarmonyPatches/PatchLoader.cs @@ -11,6 +11,8 @@ namespace nadena.dev.modular_avatar.core.editor.HarmonyPatches { internal class PatchLoader { + private const string HarmonyId = "nadena.dev.modular_avatar"; + private static readonly Action[] patches = new Action[] { //HierarchyViewPatches.Patch, @@ -19,7 +21,7 @@ namespace nadena.dev.modular_avatar.core.editor.HarmonyPatches [InitializeOnLoadMethod] static void ApplyPatches() { - var harmony = new Harmony("nadena.dev.modular_avatar"); + var harmony = new Harmony(HarmonyId); foreach (var patch in patches) { @@ -33,7 +35,7 @@ namespace nadena.dev.modular_avatar.core.editor.HarmonyPatches } } - AssemblyReloadEvents.beforeAssemblyReload += () => { harmony.UnpatchAll(); }; + AssemblyReloadEvents.beforeAssemblyReload += () => { harmony.UnpatchAll(HarmonyId); }; } } } \ No newline at end of file diff --git a/Editor/Inspector/DragAndDropManipulator.cs b/Editor/Inspector/DragAndDropManipulator.cs new file mode 100644 index 00000000..0d3de862 --- /dev/null +++ b/Editor/Inspector/DragAndDropManipulator.cs @@ -0,0 +1,106 @@ +using System; +using System.Linq; +using UnityEditor; +using UnityEngine; +using UnityEngine.UIElements; + +namespace nadena.dev.modular_avatar.core.editor +{ + internal abstract class DragAndDropManipulator : PointerManipulator where T : Component, IHaveObjReferences + { + private const string DragActiveClassName = "drop-area--drag-active"; + + public T TargetComponent { get; set; } + + protected virtual bool AllowKnownObjects => true; + + private Transform _avatarRoot; + private GameObject[] _draggingObjects = Array.Empty(); + + public DragAndDropManipulator(VisualElement targetElement, T targetComponent) + { + target = targetElement; + TargetComponent = targetComponent; + } + + protected sealed override void RegisterCallbacksOnTarget() + { + target.RegisterCallback(OnDragEnter); + target.RegisterCallback(OnDragLeave); + target.RegisterCallback(OnDragExited); + target.RegisterCallback(OnDragUpdated); + target.RegisterCallback(OnDragPerform); + } + + protected sealed override void UnregisterCallbacksFromTarget() + { + target.UnregisterCallback(OnDragEnter); + target.UnregisterCallback(OnDragLeave); + target.UnregisterCallback(OnDragExited); + target.UnregisterCallback(OnDragUpdated); + target.UnregisterCallback(OnDragPerform); + } + + private void OnDragEnter(DragEnterEvent _) + { + if (TargetComponent == null) return; + + _avatarRoot = RuntimeUtil.FindAvatarTransformInParents(TargetComponent.transform); + if (_avatarRoot == null) return; + + var knownObjects = TargetComponent.GetObjectReferences().Select(x => x.Get(TargetComponent)).ToHashSet(); + _draggingObjects = DragAndDrop.objectReferences.OfType() + .Where(x => AllowKnownObjects || !knownObjects.Contains(x)) + .Where(x => RuntimeUtil.FindAvatarTransformInParents(x.transform) == _avatarRoot) + .Where(FilterGameObject) + .ToArray(); + if (_draggingObjects.Length == 0) return; + + target.AddToClassList(DragActiveClassName); + } + + private void OnDragLeave(DragLeaveEvent _) + { + _draggingObjects = Array.Empty(); + target.RemoveFromClassList(DragActiveClassName); + } + + private void OnDragExited(DragExitedEvent _) + { + _draggingObjects = Array.Empty(); + target.RemoveFromClassList(DragActiveClassName); + } + + private void OnDragUpdated(DragUpdatedEvent _) + { + if (TargetComponent == null) return; + if (_avatarRoot == null) return; + if (_draggingObjects.Length == 0) return; + + DragAndDrop.visualMode = DragAndDropVisualMode.Generic; + } + + private void OnDragPerform(DragPerformEvent _) + { + if (TargetComponent == null) return; + if (_avatarRoot == null) return; + if (_draggingObjects.Length == 0) return; + + AddObjectReferences(_draggingObjects + .Select(x => + { + var reference = new AvatarObjectReference(); + reference.Set(x); + return reference; + }) + .ToArray()); + } + + protected virtual bool FilterGameObject(GameObject obj) + { + return true; + } + + protected abstract void AddObjectReferences(AvatarObjectReference[] references); + } +} diff --git a/Editor/Inspector/DragAndDropManipulator.cs.meta b/Editor/Inspector/DragAndDropManipulator.cs.meta new file mode 100644 index 00000000..b78bdf93 --- /dev/null +++ b/Editor/Inspector/DragAndDropManipulator.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 528c660b56905844ea2f88bc73837e9f +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs b/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs index c7410eb8..a2b055b3 100644 --- a/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs +++ b/Editor/Inspector/MaterialSetter/MaterialSetterEditor.cs @@ -16,6 +16,7 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger [SerializeField] private StyleSheet uss; [SerializeField] private VisualTreeAsset uxml; + private DragAndDropManipulator _dragAndDropManipulator; protected override void OnInnerInspectorGUI() { @@ -37,7 +38,44 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger listView.showBoundCollectionSize = false; listView.virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight; + _dragAndDropManipulator = new DragAndDropManipulator(root.Q("group-box"), target as ModularAvatarMaterialSetter); + return root; } + + private void OnEnable() + { + if (_dragAndDropManipulator != null) + _dragAndDropManipulator.TargetComponent = target as ModularAvatarMaterialSetter; + } + + private class DragAndDropManipulator : DragAndDropManipulator + { + public DragAndDropManipulator(VisualElement targetElement, ModularAvatarMaterialSetter targetComponent) + : base(targetElement, targetComponent) { } + + protected override bool FilterGameObject(GameObject obj) + { + if (obj.TryGetComponent(out var renderer)) + { + return renderer.sharedMaterials.Length > 0; + } + return false; + } + + protected override void AddObjectReferences(AvatarObjectReference[] references) + { + Undo.RecordObject(TargetComponent, "Add Material Switch Objects"); + + foreach (var reference in references) + { + var materialSwitchObject = new MaterialSwitchObject { Object = reference, MaterialIndex = 0 }; + TargetComponent.Objects.Add(materialSwitchObject); + } + + EditorUtility.SetDirty(TargetComponent); + PrefabUtility.RecordPrefabInstancePropertyModifications(TargetComponent); + } + } } } \ No newline at end of file diff --git a/Editor/Inspector/MaterialSetter/MaterialSetterStyles.uss b/Editor/Inspector/MaterialSetter/MaterialSetterStyles.uss index 84204231..8e422d2d 100644 --- a/Editor/Inspector/MaterialSetter/MaterialSetterStyles.uss +++ b/Editor/Inspector/MaterialSetter/MaterialSetterStyles.uss @@ -62,3 +62,13 @@ #f-material { flex-grow: 1; } + +.drop-area--drag-active { + background-color: rgba(0, 127, 255, 0.2); +} + +.drop-area--drag-active .unity-scroll-view, +.drop-area--drag-active .unity-list-view__footer, +.drop-area--drag-active .unity-list-view__reorderable-item { + background-color: rgba(0, 0, 0, 0.0); +} diff --git a/Editor/Inspector/Menu/MenuInstallerEditor.cs b/Editor/Inspector/Menu/MenuInstallerEditor.cs index 5110aa36..f32efe0f 100644 --- a/Editor/Inspector/Menu/MenuInstallerEditor.cs +++ b/Editor/Inspector/Menu/MenuInstallerEditor.cs @@ -368,7 +368,7 @@ namespace nadena.dev.modular_avatar.core.editor serializedObject.ApplyModifiedProperties(); - Localization.ShowLanguageUI(); + ShowLanguageUI(); } private string ObjectHierarchyOrder(Component arg) @@ -415,6 +415,9 @@ namespace nadena.dev.modular_avatar.core.editor var group = installer.gameObject.AddComponent(); var menuRoot = new GameObject(); menuRoot.name = "Menu"; + + group.targetObject = menuRoot; + Undo.RegisterCreatedObjectUndo(menuRoot, "Extract menu"); menuRoot.transform.SetParent(group.transform, false); foreach (var control in menu.controls) diff --git a/Editor/Inspector/Menu/MenuItemGUI.cs b/Editor/Inspector/Menu/MenuItemGUI.cs index c89c3817..8f4ab313 100644 --- a/Editor/Inspector/Menu/MenuItemGUI.cs +++ b/Editor/Inspector/Menu/MenuItemGUI.cs @@ -301,10 +301,9 @@ namespace nadena.dev.modular_avatar.core.editor EditorGUILayout.BeginVertical(); if (_type.hasMultipleDifferentValues) return; - VRCExpressionsMenu.Control.ControlType type = - (VRCExpressionsMenu.Control.ControlType) Enum - .GetValues(typeof(VRCExpressionsMenu.Control.ControlType)) - .GetValue(_type.enumValueIndex); + var controlTypeArray = Enum.GetValues(typeof(VRCExpressionsMenu.Control.ControlType)); + var index = Math.Clamp(_type.enumValueIndex, 0, controlTypeArray.Length - 1); + var type = (VRCExpressionsMenu.Control.ControlType)controlTypeArray.GetValue(index); switch (type) { @@ -646,6 +645,9 @@ namespace nadena.dev.modular_avatar.core.editor var myMenuItem = serializedObject.targetObject as ModularAvatarMenuItem; if (myMenuItem == null) return null; + var avatarRoot = RuntimeUtil.FindAvatarInParents(myMenuItem.gameObject.transform); + if (avatarRoot == null) return null; + var myParameterName = myMenuItem.Control.parameter.name; if (string.IsNullOrEmpty(myParameterName)) return new List(); @@ -653,7 +655,6 @@ namespace nadena.dev.modular_avatar.core.editor if (myMappings.TryGetValue((ParameterNamespace.Animator, myParameterName), out var myReplacement)) myParameterName = myReplacement.ParameterName; - var avatarRoot = RuntimeUtil.FindAvatarInParents(myMenuItem.gameObject.transform); var siblings = new List(); foreach (var otherMenuItem in avatarRoot.GetComponentsInChildren(true)) diff --git a/Editor/Inspector/MergeArmatureEditor.cs b/Editor/Inspector/MergeArmatureEditor.cs index 3785a608..0fd215b4 100644 --- a/Editor/Inspector/MergeArmatureEditor.cs +++ b/Editor/Inspector/MergeArmatureEditor.cs @@ -84,6 +84,7 @@ namespace nadena.dev.modular_avatar.core.editor } private bool posResetOptionFoldout = false; + private bool posReset_convertATPose = true; private bool posReset_adjustRotation = false; private bool posReset_adjustScale = false; private bool posReset_heuristicRootScale = true; @@ -134,14 +135,17 @@ namespace nadena.dev.modular_avatar.core.editor MessageType.Info ); + posReset_heuristicRootScale = EditorGUILayout.ToggleLeft( + G("merge_armature.reset_pos.heuristic_scale"), + posReset_heuristicRootScale); + posReset_convertATPose = EditorGUILayout.ToggleLeft( + G("merge_armature.reset_pos.convert_atpose"), + posReset_convertATPose); posReset_adjustRotation = EditorGUILayout.ToggleLeft( G("merge_armature.reset_pos.adjust_rotation"), posReset_adjustRotation); posReset_adjustScale = EditorGUILayout.ToggleLeft(G("merge_armature.reset_pos.adjust_scale"), posReset_adjustScale); - posReset_heuristicRootScale = EditorGUILayout.ToggleLeft( - G("merge_armature.reset_pos.heuristic_scale"), - posReset_heuristicRootScale); if (GUILayout.Button(G("merge_armature.reset_pos.execute"))) { @@ -188,6 +192,11 @@ namespace nadena.dev.modular_avatar.core.editor } } + if (posReset_convertATPose) + { + SetupOutfit.FixAPose(RuntimeUtil.FindAvatarTransformInParents(mergeTarget.transform).gameObject, mama.transform, false); + } + if (posReset_heuristicRootScale && !suppressRootScale) { AdjustRootScale(); @@ -279,4 +288,4 @@ namespace nadena.dev.modular_avatar.core.editor } } } -} \ No newline at end of file +} diff --git a/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs b/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs index 627121b7..999f596c 100644 --- a/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs +++ b/Editor/Inspector/ObjectToggle/ObjectSwitcherEditor.cs @@ -35,14 +35,12 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger ROSimulatorButton.BindRefObject(root, target); var listView = root.Q("Shapes"); - _dragAndDropManipulator = new DragAndDropManipulator(listView) - { - TargetComponent = target as ModularAvatarObjectToggle - }; listView.showBoundCollectionSize = false; listView.virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight; + _dragAndDropManipulator = new DragAndDropManipulator(root.Q("group-box"), target as ModularAvatarObjectToggle); + return root; } @@ -52,91 +50,25 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger _dragAndDropManipulator.TargetComponent = target as ModularAvatarObjectToggle; } - private class DragAndDropManipulator : PointerManipulator + private class DragAndDropManipulator : DragAndDropManipulator { - public ModularAvatarObjectToggle TargetComponent; - private GameObject[] _nowDragging = Array.Empty(); - private Transform _avatarRoot; + public DragAndDropManipulator(VisualElement targetElement, ModularAvatarObjectToggle targetComponent) + : base(targetElement, targetComponent) { } - private readonly VisualElement _parentElem; + protected override bool AllowKnownObjects => false; - public DragAndDropManipulator(VisualElement target) + protected override void AddObjectReferences(AvatarObjectReference[] references) { - this.target = target; - _parentElem = target.parent; - } + Undo.RecordObject(TargetComponent, "Add Toggled Objects"); - protected override void RegisterCallbacksOnTarget() - { - target.RegisterCallback(OnDragEnter); - target.RegisterCallback(OnDragLeave); - target.RegisterCallback(OnDragPerform); - target.RegisterCallback(OnDragUpdate); - } - - protected override void UnregisterCallbacksFromTarget() - { - target.UnregisterCallback(OnDragEnter); - target.UnregisterCallback(OnDragLeave); - target.UnregisterCallback(OnDragPerform); - target.RegisterCallback(OnDragUpdate); - } - - - private void OnDragEnter(DragEnterEvent evt) - { - if (TargetComponent == null) return; - - _avatarRoot = RuntimeUtil.FindAvatarTransformInParents(TargetComponent.transform); - if (_avatarRoot == null) return; - - _nowDragging = DragAndDrop.objectReferences.OfType() - .Where(o => RuntimeUtil.FindAvatarTransformInParents(o.transform) == _avatarRoot) - .ToArray(); - - if (_nowDragging.Length > 0) + foreach (var reference in references) { - DragAndDrop.visualMode = DragAndDropVisualMode.Link; - - _parentElem.AddToClassList("drop-area--drag-active"); - } - } - - private void OnDragUpdate(DragUpdatedEvent _) - { - if (_nowDragging.Length > 0) DragAndDrop.visualMode = DragAndDropVisualMode.Link; - } - - private void OnDragLeave(DragLeaveEvent evt) - { - _nowDragging = Array.Empty(); - _parentElem.RemoveFromClassList("drop-area--drag-active"); - } - - private void OnDragPerform(DragPerformEvent evt) - { - if (_nowDragging.Length > 0 && TargetComponent != null && _avatarRoot != null) - { - var knownObjs = TargetComponent.Objects.Select(o => o.Object.Get(TargetComponent)).ToHashSet(); - - Undo.RecordObject(TargetComponent, "Add Toggled Objects"); - foreach (var obj in _nowDragging) - { - if (knownObjs.Contains(obj)) continue; - - var aor = new AvatarObjectReference(); - aor.Set(obj); - - var toggledObject = new ToggledObject { Object = aor, Active = !obj.activeSelf }; - TargetComponent.Objects.Add(toggledObject); - } - - EditorUtility.SetDirty(TargetComponent); - PrefabUtility.RecordPrefabInstancePropertyModifications(TargetComponent); + var toggledObject = new ToggledObject { Object = reference, Active = !reference.Get(TargetComponent).activeSelf }; + TargetComponent.Objects.Add(toggledObject); } - _nowDragging = Array.Empty(); - _parentElem.RemoveFromClassList("drop-area--drag-active"); + EditorUtility.SetDirty(TargetComponent); + PrefabUtility.RecordPrefabInstancePropertyModifications(TargetComponent); } } } diff --git a/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss b/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss index d4bdedc5..12402b5d 100644 --- a/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss +++ b/Editor/Inspector/ObjectToggle/ObjectSwitcherStyles.uss @@ -51,6 +51,12 @@ width: 60px; } -.drop-area--drag-active > ListView ScrollView { - background-color: rgba(0, 255, 255, 0.1); +.drop-area--drag-active { + background-color: rgba(0, 127, 255, 0.2); +} + +.drop-area--drag-active .unity-scroll-view, +.drop-area--drag-active .unity-list-view__footer, +.drop-area--drag-active .unity-list-view__reorderable-item { + background-color: rgba(0, 0, 0, 0.0); } diff --git a/Editor/Inspector/Parameters/DefaultValueField.cs b/Editor/Inspector/Parameters/DefaultValueField.cs index 6ba6cd22..f29f217b 100644 --- a/Editor/Inspector/Parameters/DefaultValueField.cs +++ b/Editor/Inspector/Parameters/DefaultValueField.cs @@ -20,7 +20,8 @@ namespace nadena.dev.modular_avatar.core.editor private readonly DropdownField _boolField; private ParameterSyncType _syncType; - + private bool _hasInitialBinding; + public DefaultValueField() { // Hidden binding elements @@ -57,28 +58,39 @@ namespace nadena.dev.modular_avatar.core.editor { _numberField.style.display = DisplayStyle.Flex; _boolField.style.display = DisplayStyle.None; - OnUpdateNumberValue(_numberField.value); + OnUpdateNumberValue(_numberField.value, true); } else { _numberField.style.display = DisplayStyle.None; _boolField.style.display = DisplayStyle.Flex; - OnUpdateBoolValue(_boolField.value); + OnUpdateBoolValue(_boolField.value, true); } } - private void OnUpdateNumberValue(string value) + private void OnUpdateNumberValue(string value, bool implicitUpdate = false) { + // Upon initial creation, sometimes the OnUpdateSyncType fires before we receive the initial value event. + // In this case, suppress the update to avoid losing data. + if (implicitUpdate && !_hasInitialBinding) return; + + var theValue = _defaultValueField.value; if (string.IsNullOrWhiteSpace(value)) { - _defaultValueField.value = 0; + if (!implicitUpdate) + { + _defaultValueField.value = 0; + } + + theValue = _defaultValueField.value; + _hasExplicitDefaultValueField.value = false; } else if (float.TryParse(value, NumberStyles.Float, CultureInfo.InvariantCulture, out var parsed) && !float.IsNaN(parsed) && !float.IsInfinity(parsed)) { - _defaultValueField.value = _syncType switch + theValue = _defaultValueField.value = _syncType switch { ParameterSyncType.Int => Mathf.FloorToInt(Mathf.Clamp(parsed, 0, 255)), ParameterSyncType.Float => Mathf.Clamp(parsed, -1, 1), @@ -88,11 +100,15 @@ namespace nadena.dev.modular_avatar.core.editor _hasExplicitDefaultValueField.value = true; } - UpdateVisibleField(_defaultValueField.value, _hasExplicitDefaultValueField.value); + UpdateVisibleField(theValue, _hasExplicitDefaultValueField.value); } - private void OnUpdateBoolValue(string value) + private void OnUpdateBoolValue(string value, bool implicitUpdate = false) { + // Upon initial creation, sometimes the OnUpdateSyncType fires before we receive the initial value event. + // In this case, suppress the update to avoid losing data. + if (implicitUpdate && !_hasInitialBinding) return; + _defaultValueField.value = value == V_True ? 1 : 0; _hasExplicitDefaultValueField.value = value != V_None; @@ -101,6 +117,8 @@ namespace nadena.dev.modular_avatar.core.editor private void UpdateVisibleField(float value, bool hasExplicitValue) { + _hasInitialBinding = true; + if (hasExplicitValue || Mathf.Abs(value) > 0.0000001) { _numberField.SetValueWithoutNotify(value.ToString(CultureInfo.InvariantCulture)); diff --git a/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs b/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs index 9a278278..9bec32a3 100644 --- a/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs +++ b/Editor/Inspector/ShapeChanger/ShapeChangerEditor.cs @@ -19,6 +19,7 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger [SerializeField] private StyleSheet uss; [SerializeField] private VisualTreeAsset uxml; + private DragAndDropManipulator _dragAndDropManipulator; private BlendshapeSelectWindow _window; protected override void OnInnerInspectorGUI() @@ -41,6 +42,8 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger listView.showBoundCollectionSize = false; listView.virtualizationMethod = CollectionVirtualizationMethod.DynamicHeight; + _dragAndDropManipulator = new DragAndDropManipulator(root.Q("group-box"), target as ModularAvatarShapeChanger); + // The Add button callback isn't exposed publicly for some reason... var field_addButton = typeof(BaseListView).GetField("m_AddButton", NonPublic | Instance); var addButton = (Button)field_addButton.GetValue(listView); @@ -50,6 +53,41 @@ namespace nadena.dev.modular_avatar.core.editor.ShapeChanger return root; } + private void OnEnable() + { + if (_dragAndDropManipulator != null) + _dragAndDropManipulator.TargetComponent = target as ModularAvatarShapeChanger; + } + + private class DragAndDropManipulator : DragAndDropManipulator + { + public DragAndDropManipulator(VisualElement targetElement, ModularAvatarShapeChanger targetComponent) + : base(targetElement, targetComponent) { } + + protected override bool FilterGameObject(GameObject obj) + { + if (obj.TryGetComponent(out var smr)) + { + return smr.sharedMesh != null && smr.sharedMesh.blendShapeCount > 0; + } + return false; + } + + protected override void AddObjectReferences(AvatarObjectReference[] references) + { + Undo.RecordObject(TargetComponent, "Add Changed Shapes"); + + foreach (var reference in references) + { + var changedShape = new ChangedShape { Object = reference, ShapeName = string.Empty }; + TargetComponent.Shapes.Add(changedShape); + } + + EditorUtility.SetDirty(TargetComponent); + PrefabUtility.RecordPrefabInstancePropertyModifications(TargetComponent); + } + } + private void OnDisable() { if (_window != null) DestroyImmediate(_window); diff --git a/Editor/Inspector/ShapeChanger/ShapeChangerStyles.uss b/Editor/Inspector/ShapeChanger/ShapeChangerStyles.uss index adff445e..e74734ff 100644 --- a/Editor/Inspector/ShapeChanger/ShapeChangerStyles.uss +++ b/Editor/Inspector/ShapeChanger/ShapeChangerStyles.uss @@ -68,3 +68,13 @@ .change-type-delete #f-value-delete { display: flex; } + +.drop-area--drag-active { + background-color: rgba(0, 127, 255, 0.2); +} + +.drop-area--drag-active .unity-scroll-view, +.drop-area--drag-active .unity-list-view__footer, +.drop-area--drag-active .unity-list-view__reorderable-item { + background-color: rgba(0, 0, 0, 0.0); +} diff --git a/Editor/Localization/en-US.json b/Editor/Localization/en-US.json index bc7e8ec8..07a5a565 100644 --- a/Editor/Localization/en-US.json +++ b/Editor/Localization/en-US.json @@ -86,6 +86,7 @@ "merge_armature.lockmode.bidirectional.body": "The base armature and the merged armature will always have the same position. This is useful when creating animations that are meant to target the base armature. In order to activate this, your armatures must already be in the exact same position.", "merge_armature.reset_pos": "Reset position to base avatar", "merge_armature.reset_pos.info": "This command will force the position of all bones in the outfit to match that of the base avatar. This can be helpful as a starting point for installing outfits not set up for your current avatar.", + "merge_armature.reset_pos.convert_atpose": "Convert A-Pose/T-Pose to match base avatar", "merge_armature.reset_pos.adjust_rotation": "Also set rotation to base avatar", "merge_armature.reset_pos.adjust_scale": "Also set local scale to base avatar", "merge_armature.reset_pos.execute": "Do it!", @@ -149,6 +150,8 @@ "error.rename_params.default_value_conflict:hint": "To avoid unpredictable behavior, leave the default value field blank in all but on MA Parameters component. If multiple values are present, Modular Avatar will select the first default value specified in the hierarchy order.", "error.replace_object.null_target": "[MA-0008] No target specified", "error.replace_object.null_target:hint": "Replace object needs a target object to replace. Try setting one.", + "error.replace_object.replacing_replacement": "[MA-0009] The same target object cannot be specified in multiple Replace Object components", + "error.replace_object.parent_of_target": "[MA-0010] The target object cannot be a parent of this object", "validation.blendshape_sync.no_local_renderer": "[MA-1000] No renderer found on this object", "validation.blendshape_sync.no_local_renderer:hint": "Blendshape Sync acts on a Skinned Mesh Renderer on the same GameObject. Did you attach it to the right object?", "validation.blendshape_sync.no_local_mesh": "[MA-1001] No mesh found on the renderer on this object", diff --git a/Editor/Localization/ja-JP.json b/Editor/Localization/ja-JP.json index 94c6022a..ad1378f4 100644 --- a/Editor/Localization/ja-JP.json +++ b/Editor/Localization/ja-JP.json @@ -82,6 +82,7 @@ "merge_armature.lockmode.bidirectional.body": "アバターと統合されるアーマチュアは常に同じ位置になります。元のアバターを操作するアニメーションを作る時に便利かもしれません。有効にするためには、統合されるアーマチュアの位置を統合先と同じにしておく必要があります。", "merge_armature.reset_pos": "位置を元アバターに合わせてリセット", "merge_armature.reset_pos.info": "衣装のボーンの位置をアバターのボーンの位置に合わせます。非対応衣装を導入する際、アバウトに位置を合わせるのに便利です。", + "merge_armature.reset_pos.convert_atpose": "Aポーズ/Tポーズを合わせる", "merge_armature.reset_pos.adjust_rotation": "回転も合わせる", "merge_armature.reset_pos.adjust_scale": "スケールも合わせる", "merge_armature.reset_pos.execute": "実行", @@ -145,6 +146,8 @@ "error.rename_params.default_value_conflict:hint": "予測不可能な動作を避けるため、MA Parametersコンポーネントの初期値フィールドはパラメーター名毎に1つだけしか指定しないようにし、他のコンポーネントでは空白のままにしてください。複数の値が存在する場合、Modular Avatarは階層順で最初に指定された初期値を採用します。", "error.replace_object.null_target": "[MA-0008] 置き換え先が指定されていません", "error.replace_object.null_target:hint": "Replace Objectは置き換え先のオブジェクトを指定する必要があります。", + "error.replace_object.replacing_replacement": "[MA-0009] 複数のReplace Objectコンポーネントで、同じ置き換え先を指定できません", + "error.replace_object.parent_of_target": "[MA-0010] このオブジェクトの親を置き換え先に指定できません", "validation.blendshape_sync.no_local_renderer": "[MA-1000] このオブジェクトにはSkinned Mesh Rendererがありません。", "validation.blendshape_sync.no_local_renderer:hint": "Blendshape Syncは同じGameObject上のSkinned Mesh Rendererに作用します。コンポーネントが正しいオブジェクトに追加されているか確認してください。", "validation.blendshape_sync.no_local_mesh": "[MA-1001] このオブジェクトにはSkinned Mesh Rendererがありますが、メッシュがありません。", diff --git a/Editor/Localization/zh-Hant.json b/Editor/Localization/zh-Hant.json index 21cd5a61..bdc8b921 100644 --- a/Editor/Localization/zh-Hant.json +++ b/Editor/Localization/zh-Hant.json @@ -251,7 +251,7 @@ "reactive_object.inverse": "反轉條件", "reactive_object.material-setter.set-to": "將材質設定為:", "menuitem.misc.add_toggle": "新增開關", - "ro_sim.open_debugger_button": "開啟響應除錯工具", + "ro_sim.open_debugger_button": "開啟 Reaction 除錯工具", "ro_sim.window.title": "MA 響應除錯工具", "ro_sim.header.inspecting": "檢視物件", "ro_sim.header.clear_overrides": "清除所有覆寫", diff --git a/Editor/Menu/MenuExtractor.cs b/Editor/Menu/MenuExtractor.cs index 89ee232c..9f670382 100644 --- a/Editor/Menu/MenuExtractor.cs +++ b/Editor/Menu/MenuExtractor.cs @@ -119,9 +119,11 @@ namespace nadena.dev.modular_avatar.core.editor internal static VRCExpressionsMenu.Control CloneControl(VRCExpressionsMenu.Control c) { + var type = c.type != 0 ? c.type : VRCExpressionsMenu.Control.ControlType.Button; + return new VRCExpressionsMenu.Control() { - type = c.type, + type = type, name = c.name, icon = c.icon, parameter = new VRCExpressionsMenu.Control.Parameter() { name = c.parameter?.name }, diff --git a/Editor/MergeAnimatorProcessor.cs b/Editor/MergeAnimatorProcessor.cs index 50efd939..b0af81ac 100644 --- a/Editor/MergeAnimatorProcessor.cs +++ b/Editor/MergeAnimatorProcessor.cs @@ -246,6 +246,18 @@ namespace nadena.dev.modular_avatar.core.editor var stateMachineQueue = new Queue(); foreach (var layer in controller.layers) { + // Special case: A layer with a single state, which contains a blend tree, is ignored for WD analysis. + // This is because WD ON blend trees have different behavior from most WD ON states, and can be safely + // used in a WD OFF animator. + + if (layer.stateMachine.states.Length == 1 + && layer.stateMachine.states[0].state.motion is BlendTree + && layer.stateMachine.stateMachines.Length == 0 + ) + { + continue; + } + stateMachineQueue.Enqueue(layer.stateMachine); } diff --git a/Editor/PluginDefinition/PluginDefinition.cs b/Editor/PluginDefinition/PluginDefinition.cs index aa47c44c..4a31f17a 100644 --- a/Editor/PluginDefinition/PluginDefinition.cs +++ b/Editor/PluginDefinition/PluginDefinition.cs @@ -60,7 +60,13 @@ namespace nadena.dev.modular_avatar.core.editor.plugin #if MA_VRCSDK3_AVATARS seq.Run("Shape Changer", ctx => new ReactiveObjectPass(ctx).Execute()) .PreviewingWith(new ShapeChangerPreview(), new ObjectSwitcherPreview(), new MaterialSetterPreview()); + + // TODO: We currently run this above MergeArmaturePlugin, because Merge Armature might destroy + // game objects which contain Menu Installers. It'd probably be better however to teach Merge Armature + // to retain those objects? maybe? + seq.Run(MenuInstallPluginPass.Instance); #endif + seq.Run(MergeArmaturePluginPass.Instance); seq.Run(BoneProxyPluginPass.Instance); #if MA_VRCSDK3_AVATARS @@ -77,7 +83,6 @@ namespace nadena.dev.modular_avatar.core.editor.plugin seq.Run(ConstraintConverterPass.Instance); }); #if MA_VRCSDK3_AVATARS - seq.Run(MenuInstallPluginPass.Instance); seq.Run(PhysbonesBlockerPluginPass.Instance); seq.Run("Fixup Expressions Menu", ctx => { diff --git a/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs b/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs index c3bded7d..6a488a5a 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/AnimatedProperty.cs @@ -1,14 +1,14 @@ -using System.Collections.Generic; -using UnityEngine; +using System; +using System.Collections.Generic; +using System.Linq; +using Object = UnityEngine.Object; namespace nadena.dev.modular_avatar.core.editor { internal class AnimatedProperty { public TargetProp TargetProp { get; } - public string ControlParam { get; set; } - public bool alwaysDeleted; public object currentState; // Objects which trigger deletion of this shape key. @@ -25,5 +25,30 @@ namespace nadena.dev.modular_avatar.core.editor TargetProp = key; this.currentState = currentState; } + + protected bool Equals(AnimatedProperty other) + { + return Equals(currentState, other.currentState) && actionGroups.SequenceEqual(other.actionGroups) && + TargetProp.Equals(other.TargetProp); + } + + public override bool Equals(object obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((AnimatedProperty)obj); + } + + public override int GetHashCode() + { + var actionGroupHash = 0; + foreach (var ag in actionGroups) + { + actionGroupHash = HashCode.Combine(actionGroupHash, ag); + } + + return HashCode.Combine(currentState, actionGroupHash, TargetProp); + } } } \ No newline at end of file diff --git a/Editor/ReactiveObjects/AnimationGeneration/ControlCondition.cs b/Editor/ReactiveObjects/AnimationGeneration/ControlCondition.cs index 33368ea5..f61b33e0 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ControlCondition.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ControlCondition.cs @@ -1,11 +1,13 @@ -using UnityEngine; +using System; +using UnityEngine; +using Object = UnityEngine.Object; namespace nadena.dev.modular_avatar.core.editor { internal class ControlCondition { public string Parameter; - public UnityEngine.Object DebugReference; + public Object DebugReference; public string DebugName; public bool IsConstant; @@ -14,5 +16,31 @@ namespace nadena.dev.modular_avatar.core.editor public bool IsConstantActive => InitiallyActive && IsConstant; public GameObject ReferenceObject; + + protected bool Equals(ControlCondition other) + { + return Parameter == other.Parameter + && Equals(DebugReference, other.DebugReference) + && DebugName == other.DebugName + && IsConstant == other.IsConstant + && ParameterValueLo.Equals(other.ParameterValueLo) + && ParameterValueHi.Equals(other.ParameterValueHi) + && InitialValue.Equals(other.InitialValue) + && Equals(ReferenceObject, other.ReferenceObject); + } + + public override bool Equals(object obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((ControlCondition)obj); + } + + public override int GetHashCode() + { + return HashCode.Combine(Parameter, DebugReference, DebugName, IsConstant, ParameterValueLo, + ParameterValueHi, InitialValue, ReferenceObject); + } } } \ No newline at end of file diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs index 68ae3154..497046ab 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactionRule.cs @@ -1,7 +1,8 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; -using nadena.dev.modular_avatar.animation; using UnityEngine; +using Object = UnityEngine.Object; namespace nadena.dev.modular_avatar.core.editor { @@ -9,8 +10,8 @@ namespace nadena.dev.modular_avatar.core.editor { public ReactionRule(TargetProp key, float value) : this(key, (object)value) { } - - public ReactionRule(TargetProp key, UnityEngine.Object value) + + public ReactionRule(TargetProp key, Object value) : this(key, (object)value) { } private ReactionRule(TargetProp key, object value) @@ -31,13 +32,15 @@ namespace nadena.dev.modular_avatar.core.editor public bool InitiallyActive => ((ControllingConditions.Count == 0) || ControllingConditions.All(c => c.InitiallyActive)) ^ Inverted; - public bool IsDelete; public bool Inverted; - public bool IsConstant => ControllingConditions.Count == 0 || ControllingConditions.All(c => c.IsConstant); - public bool IsConstantOn => IsConstant && InitiallyActive; + public bool IsConstant => ControllingConditions.Count == 0 + || ControllingConditions.All(c => c.IsConstant) + || ControllingConditions.Any(c => c.IsConstant && !c.InitiallyActive); + public bool IsConstantActive => IsConstant && InitiallyActive ^ Inverted; + public override string ToString() { return $"AGK: {TargetProp}={Value}"; @@ -55,9 +58,36 @@ namespace nadena.dev.modular_avatar.core.editor } else return false; if (!ControllingConditions.SequenceEqual(other.ControllingConditions)) return false; - if (IsDelete || other.IsDelete) return false; return true; } + + protected bool Equals(ReactionRule other) + { + return TargetProp.Equals(other.TargetProp) + && Equals(Value, other.Value) + && Equals(ControllingObject, other.ControllingObject) + && ControllingConditions.SequenceEqual(other.ControllingConditions) + && Inverted == other.Inverted; + } + + public override bool Equals(object obj) + { + if (obj is null) return false; + if (ReferenceEquals(this, obj)) return true; + if (obj.GetType() != GetType()) return false; + return Equals((ReactionRule)obj); + } + + public override int GetHashCode() + { + var ccHash = 0; + foreach (var cc in ControllingConditions) + { + ccHash = HashCode.Combine(ccHash, cc); + } + + return HashCode.Combine(TargetProp, Value, ControllingObject, ccHash, Inverted); + } } } \ No newline at end of file diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs index af421739..7cc2e403 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.LocateReactions.cs @@ -1,5 +1,6 @@ #if MA_VRCSDK3_AVATARS using System.Collections.Generic; +using System.Collections.Immutable; using System.Linq; using nadena.dev.ndmf.preview; using UnityEngine; @@ -39,6 +40,77 @@ namespace nadena.dev.modular_avatar.core.editor return param; } } + + private readonly Dictionary<(SkinnedMeshRenderer, string), HashSet<(SkinnedMeshRenderer, string)>> + _blendshapeSyncMappings = new(); + + private void LocateBlendshapeSyncs(GameObject root) + { + var components = _computeContext.GetComponentsInChildren(root, true); + + foreach (var bss in components) + { + var localMesh = _computeContext.GetComponent(bss.gameObject); + if (localMesh == null) continue; + + foreach (var entry in _computeContext.Observe(bss, bss_ => bss_.Bindings.ToImmutableList(), + Enumerable.SequenceEqual)) + { + var src = entry.ReferenceMesh.Get(bss); + if (src == null) continue; + + var srcMesh = _computeContext.GetComponent(src); + + var localBlendshape = entry.LocalBlendshape; + if (string.IsNullOrWhiteSpace(localBlendshape)) + { + localBlendshape = entry.Blendshape; + } + + var srcBinding = (srcMesh, entry.Blendshape); + var dstBinding = (localMesh, localBlendshape); + + if (!_blendshapeSyncMappings.TryGetValue(srcBinding, out var dstSet)) + { + dstSet = new HashSet<(SkinnedMeshRenderer, string)>(); + _blendshapeSyncMappings[srcBinding] = dstSet; + } + + dstSet.Add(dstBinding); + } + } + + // For recursive blendshape syncs, we need to precompute the full set of affected blendshapes. + foreach (var (src, dsts) in _blendshapeSyncMappings) + { + var visited = new HashSet<(SkinnedMeshRenderer, string)>(); + foreach (var item in Visit(src, visited).ToList()) + { + dsts.Add(item); + } + } + + IEnumerable<(SkinnedMeshRenderer, string)> Visit( + (SkinnedMeshRenderer, string) key, + HashSet<(SkinnedMeshRenderer, string)> visited + ) + { + if (!visited.Add(key)) yield break; + + if (_blendshapeSyncMappings.TryGetValue(key, out var children)) + { + foreach (var child in children) + { + foreach (var item in Visit(child, visited)) + { + yield return item; + } + } + } + + yield return key; + } + } private void BuildConditions(Component controllingComponent, ReactionRule rule) { @@ -125,50 +197,80 @@ namespace nadena.dev.modular_avatar.core.editor var key = new TargetProp { TargetObject = renderer, - PropertyName = "blendShape." + shape.ShapeName, + PropertyName = BlendshapePrefix + shape.ShapeName }; + var currentValue = renderer.GetBlendShapeWeight(shapeId); var value = shape.ChangeType == ShapeChangeType.Delete ? 100 : shape.Value; - if (!shapeKeys.TryGetValue(key, out var info)) + + RegisterAction(key, currentValue, value, changer); + + if (_blendshapeSyncMappings.TryGetValue((renderer, shape.ShapeName), out var bindings)) { - info = new AnimatedProperty(key, renderer.GetBlendShapeWeight(shapeId)); - shapeKeys[key] = info; + // Propagate the new value through any Blendshape Syncs we might have. + // Note that we don't propagate deletes; it's common to e.g. want to delete breasts from the + // base model while retaining outerwear that matches the breast size. + foreach (var binding in bindings) + { + var bindingKey = new TargetProp + { + TargetObject = binding.Item1, + PropertyName = BlendshapePrefix + binding.Item2 + }; + var bindingRenderer = binding.Item1; - // Add initial state - var agk = new ReactionRule(key, value); - agk.Value = renderer.GetBlendShapeWeight(shapeId); - info.actionGroups.Add(agk); + var bindingMesh = bindingRenderer.sharedMesh; + if (bindingMesh == null) continue; + + var bindingShapeIndex = bindingMesh.GetBlendShapeIndex(binding.Item2); + if (bindingShapeIndex < 0) continue; + + var bindingInitialState = bindingRenderer.GetBlendShapeWeight(bindingShapeIndex); + + RegisterAction(bindingKey, bindingInitialState, value, changer); + } } - - var action = ObjectRule(key, changer, value); - action.Inverted = _computeContext.Observe(changer, c => c.Inverted); - var isCurrentlyActive = changer.gameObject.activeInHierarchy; - - if (shape.ChangeType == ShapeChangeType.Delete) + + key = new TargetProp { - action.IsDelete = true; - - if (isCurrentlyActive) info.currentState = 100; + TargetObject = renderer, + PropertyName = DeletedShapePrefix + shape.ShapeName + }; - info.actionGroups.Add(action); // Never merge - - continue; - } - - if (changer.gameObject.activeInHierarchy) info.currentState = action.Value; - - if (info.actionGroups.Count == 0) - { - info.actionGroups.Add(action); - } - else if (!info.actionGroups[^1].TryMerge(action)) - { - info.actionGroups.Add(action); - } + value = shape.ChangeType == ShapeChangeType.Delete ? 1 : 0; + RegisterAction(key, 0, value, changer); } } return shapeKeys; + + void RegisterAction(TargetProp key, float currentValue, float value, ModularAvatarShapeChanger changer) + { + if (!shapeKeys.TryGetValue(key, out var info)) + { + info = new AnimatedProperty(key, currentValue); + shapeKeys[key] = info; + + // Add initial state + var agk = new ReactionRule(key, value); + agk.Value = currentValue; + info.actionGroups.Add(agk); + } + + var action = ObjectRule(key, changer, value); + action.Inverted = _computeContext.Observe(changer, c => c.Inverted); + + if (changer.gameObject.activeInHierarchy) info.currentState = action.Value; + + if (info.actionGroups.Count == 0) + { + info.actionGroups.Add(action); + } + else if (!info.actionGroups[^1].TryMerge(action)) + { + info.actionGroups.Add(action); + } + } } private void FindMaterialSetters(Dictionary objectGroups, GameObject root) diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs index 744d620c..228f215c 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectAnalyzer.cs @@ -19,6 +19,11 @@ namespace nadena.dev.modular_avatar.core.editor private readonly ndmf.BuildContext _context; private readonly AnimationServicesContext _asc; private Dictionary _simulationInitialStates; + + public const string BlendshapePrefix = "blendShape."; + public const string DeletedShapePrefix = "deletedShape."; + + public bool OptimizeShapes = true; public ImmutableDictionary ForcePropertyOverrides { get; set; } = ImmutableDictionary.Empty; @@ -59,7 +64,6 @@ namespace nadena.dev.modular_avatar.core.editor { public Dictionary Shapes; public Dictionary InitialStates; - public HashSet DeletedShapes; } private static PropCache _analysisCache; @@ -87,7 +91,6 @@ namespace nadena.dev.modular_avatar.core.editor /// /// The avatar root /// A dictionary of target property to initial state (float or UnityEngine.Object) - /// A hashset of blendshape properties which are always deleted /// public AnalysisResult Analyze( GameObject root @@ -99,9 +102,10 @@ namespace nadena.dev.modular_avatar.core.editor { result.Shapes = new(); result.InitialStates = new(); - result.DeletedShapes = new(); return result; } + + LocateBlendshapeSyncs(root); Dictionary shapes = FindShapes(root); FindObjectToggles(shapes, root); @@ -110,7 +114,7 @@ namespace nadena.dev.modular_avatar.core.editor ApplyInitialStateOverrides(shapes); AnalyzeConstants(shapes); ResolveToggleInitialStates(shapes); - PreprocessShapes(shapes, out result.InitialStates, out result.DeletedShapes); + PreprocessShapes(shapes, out result.InitialStates); result.Shapes = shapes; return result; @@ -125,7 +129,7 @@ namespace nadena.dev.modular_avatar.core.editor foreach (var cond in rule.ControllingConditions) { var paramName = cond.Parameter; - if (ForcePropertyOverrides.TryGetValue(paramName, out var value)) + if (ForcePropertyOverrides?.TryGetValue(paramName, out var value) == true) { cond.InitialValue = value; } @@ -145,7 +149,7 @@ namespace nadena.dev.modular_avatar.core.editor HashSet toggledObjects = new(); if (asc == null) return; - + foreach (var targetProp in shapes.Keys) if (targetProp is { TargetObject: GameObject go, PropertyName: "m_IsActive" }) toggledObjects.Add(go); @@ -166,7 +170,7 @@ namespace nadena.dev.modular_avatar.core.editor group.actionGroups.RemoveAll(agk => agk.IsConstant && !agk.InitiallyActive); // Remove all action groups up until the last one where we're always on - var lastAlwaysOnGroup = group.actionGroups.FindLastIndex(ag => ag.IsConstantOn); + var lastAlwaysOnGroup = group.actionGroups.FindLastIndex(ag => ag.IsConstantActive); if (lastAlwaysOnGroup > 0) group.actionGroups.RemoveRange(0, lastAlwaysOnGroup - 1); } @@ -265,39 +269,26 @@ namespace nadena.dev.modular_avatar.core.editor } /// - /// Determine initial state and deleted shapes for all properties + /// Determine initial state for all properties /// /// /// - /// - private void PreprocessShapes(Dictionary shapes, out Dictionary initialStates, out HashSet deletedShapes) + private void PreprocessShapes(Dictionary shapes, + out Dictionary initialStates) { // For each shapekey, determine 1) if we can just set an initial state and skip and 2) if we can delete the // corresponding mesh. If we can't, delete ops are merged into the main list of operations. initialStates = new Dictionary(); - deletedShapes = new HashSet(); - + foreach (var (key, info) in shapes.ToList()) { if (info.actionGroups.Count == 0) { // never active control; ignore it entirely - shapes.Remove(key); + if (OptimizeShapes) shapes.Remove(key); continue; } - - var deletions = info.actionGroups.Where(agk => agk.IsDelete).ToList(); - if (deletions.Any(d => d.ControllingConditions.All(c => c.IsConstantActive))) - { - // always deleted - shapes.Remove(key); - deletedShapes.Add(key); - continue; - } - - // Move deleted shapes to the end of the list, so they override all Set actions - info.actionGroups = info.actionGroups.Where(agk => !agk.IsDelete).Concat(deletions).ToList(); var initialState = info.actionGroups.Where(agk => agk.InitiallyActive) .Select(agk => agk.Value) @@ -309,7 +300,7 @@ namespace nadena.dev.modular_avatar.core.editor // If we're now constant-on, we can skip animation generation if (info.actionGroups[^1].IsConstant) { - shapes.Remove(key); + if (OptimizeShapes) shapes.Remove(key); } } } diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs index e7111779..ae77c80f 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPass.cs @@ -3,7 +3,6 @@ using System; using System.Collections.Generic; -using System.Collections.Immutable; using System.Linq; using nadena.dev.modular_avatar.animation; using UnityEditor; @@ -43,10 +42,11 @@ namespace nadena.dev.modular_avatar.core.editor var shapes = analysis.Shapes; var initialStates = analysis.InitialStates; - var deletedShapes = analysis.DeletedShapes; GenerateActiveSelfProxies(shapes); + ProcessMeshDeletion(initialStates, shapes); + ProcessInitialStates(initialStates, shapes); ProcessInitialAnimatorVariables(shapes); @@ -54,8 +54,6 @@ namespace nadena.dev.modular_avatar.core.editor { ProcessShapeKey(groups); } - - ProcessMeshDeletion(deletedShapes); } private void GenerateActiveSelfProxies(Dictionary shapes) @@ -86,7 +84,7 @@ namespace nadena.dev.modular_avatar.core.editor initialValues[condition.Parameter] = condition.InitialValue; } } - } + } private void ProcessInitialStates(Dictionary initialStates, Dictionary shapes) @@ -226,30 +224,65 @@ namespace nadena.dev.modular_avatar.core.editor #region Mesh processing - private void ProcessMeshDeletion(HashSet deletedKeys) + private void ProcessMeshDeletion(Dictionary initialStates, + Dictionary shapes) { - ImmutableDictionary> renderers = deletedKeys - .GroupBy( - v => (SkinnedMeshRenderer) v.TargetObject - ).ToImmutableDictionary( - g => (SkinnedMeshRenderer) g.Key, - g => g.ToList() - ); + var renderers = initialStates + .Where(kvp => kvp.Key.PropertyName.StartsWith(ReactiveObjectAnalyzer.DeletedShapePrefix)) + .Where(kvp => kvp.Key.TargetObject is SkinnedMeshRenderer) + .Where(kvp => kvp.Value is float f && f > 0.5f) + // Filter any non-constant keys + .Where(kvp => + { + if (!shapes.ContainsKey(kvp.Key)) + { + // Constant value + return true; + } - foreach (var (renderer, infos) in renderers) + var lastGroup = shapes[kvp.Key].actionGroups.LastOrDefault(); + return lastGroup?.IsConstantActive == true && lastGroup.Value is float f && f > 0.5f; + }) + .GroupBy(kvp => kvp.Key.TargetObject as SkinnedMeshRenderer) + .Select(grouping => (grouping.Key, grouping.Select( + kvp => kvp.Key.PropertyName.Substring(ReactiveObjectAnalyzer.DeletedShapePrefix.Length) + ).ToList())) + .ToList(); + foreach (var (renderer, shapeNamesToDelete) in renderers) { if (renderer == null) continue; var mesh = renderer.sharedMesh; if (mesh == null) continue; - renderer.sharedMesh = RemoveBlendShapeFromMesh.RemoveBlendshapes( - mesh, - infos - .Select(i => mesh.GetBlendShapeIndex(i.PropertyName.Substring("blendShape.".Length))) - .Where(k => k >= 0) - .ToList() - ); + var shapesToDelete = shapeNamesToDelete + .Select(shape => mesh.GetBlendShapeIndex(shape)) + .Where(k => k >= 0) + .ToList(); + + renderer.sharedMesh = RemoveBlendShapeFromMesh.RemoveBlendshapes(mesh, shapesToDelete); + + foreach (var name in shapeNamesToDelete) + { + // Don't need to animate this anymore...! + shapes.Remove(new TargetProp + { + TargetObject = renderer, + PropertyName = ReactiveObjectAnalyzer.BlendshapePrefix + name + }); + + shapes.Remove(new TargetProp + { + TargetObject = renderer, + PropertyName = ReactiveObjectAnalyzer.DeletedShapePrefix + name + }); + + initialStates.Remove(new TargetProp + { + TargetObject = renderer, + PropertyName = ReactiveObjectAnalyzer.BlendshapePrefix + name + }); + } } } @@ -258,10 +291,6 @@ namespace nadena.dev.modular_avatar.core.editor private void ProcessShapeKey(AnimatedProperty info) { // TODO: prune non-animated keys - - // Check if this is non-animated and skip most processing if so - if (info.alwaysDeleted || info.actionGroups[^1].IsConstant) return; - var asm = GenerateStateMachine(info); ApplyController(asm, "MA Responsive: " + info.TargetProp.TargetObject.name); } @@ -301,8 +330,7 @@ namespace nadena.dev.modular_avatar.core.editor var transitionBuffer = new List<(AnimatorState, List)>(); var entryTransitions = new List(); - var initialStateTransitionList = new List(); - transitionBuffer.Add((initialState, initialStateTransitionList)); + transitionBuffer.Add((initialState, new List())); foreach (var group in info.actionGroups.Skip(lastConstant)) { @@ -322,30 +350,33 @@ namespace nadena.dev.modular_avatar.core.editor var conditions = GetTransitionConditions(asc, group); - if (!group.Inverted) + foreach (var (st, transitions) in transitionBuffer) { - var transition = new AnimatorStateTransition + if (!group.Inverted) { - isExit = true, - hasExitTime = false, - duration = 0, - hasFixedDuration = true, - conditions = (AnimatorCondition[])conditions.Clone() - }; - initialStateTransitionList.Add(transition); - } - else - { - foreach (var cond in conditions) - { - initialStateTransitionList.Add(new AnimatorStateTransition + var transition = new AnimatorStateTransition { isExit = true, hasExitTime = false, duration = 0, hasFixedDuration = true, - conditions = new[] { InvertCondition(cond) } - }); + conditions = (AnimatorCondition[])conditions.Clone() + }; + transitions.Add(transition); + } + else + { + foreach (var cond in conditions) + { + transitions.Add(new AnimatorStateTransition + { + isExit = true, + hasExitTime = false, + duration = 0, + hasFixedDuration = true, + conditions = new[] { InvertCondition(cond) } + }); + } } } diff --git a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPrepass.cs b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPrepass.cs index 16b37c81..cec2bf17 100644 --- a/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPrepass.cs +++ b/Editor/ReactiveObjects/AnimationGeneration/ReactiveObjectPrepass.cs @@ -15,11 +15,11 @@ namespace nadena.dev.modular_avatar.core.editor protected override void Execute(ndmf.BuildContext context) { - var hasShapeChanger = context.AvatarRootObject.GetComponentInChildren() != null; + var hasShapeChanger = context.AvatarRootObject.GetComponentInChildren(true) != null; var hasObjectSwitcher = - context.AvatarRootObject.GetComponentInChildren() != null; + context.AvatarRootObject.GetComponentInChildren(true) != null; var hasMaterialSetter = - context.AvatarRootObject.GetComponentInChildren() != null; + context.AvatarRootObject.GetComponentInChildren(true) != null; if (hasShapeChanger || hasObjectSwitcher || hasMaterialSetter) { var clip = new AnimationClip(); diff --git a/Editor/ReactiveObjects/ShapeChangerPreview.cs b/Editor/ReactiveObjects/ShapeChangerPreview.cs index 955e3aa0..d3cde839 100644 --- a/Editor/ReactiveObjects/ShapeChangerPreview.cs +++ b/Editor/ReactiveObjects/ShapeChangerPreview.cs @@ -73,8 +73,8 @@ namespace nadena.dev.modular_avatar.core.editor var analysis = ReactiveObjectAnalyzer.CachedAnalyze(context, avatarRoot); var shapes = analysis.Shapes; - ImmutableDictionary>.Builder rendererStates = - ImmutableDictionary.CreateBuilder>( + var rendererStates = + ImmutableDictionary.CreateBuilder>( ); var avatarRootTransform = avatarRoot.transform; @@ -84,16 +84,29 @@ namespace nadena.dev.modular_avatar.core.editor var target = prop.TargetProp; if (target.TargetObject == null || target.TargetObject is not SkinnedMeshRenderer r) continue; if (!r.transform.IsChildOf(avatarRootTransform)) continue; - if (!target.PropertyName.StartsWith("blendShape.")) continue; + var isDelete = false; + string shapeName = null; + if (target.PropertyName.StartsWith(ReactiveObjectAnalyzer.DeletedShapePrefix)) + { + isDelete = true; + shapeName = target.PropertyName.Substring(ReactiveObjectAnalyzer.DeletedShapePrefix.Length); + } + else if (target.PropertyName.StartsWith(ReactiveObjectAnalyzer.BlendshapePrefix)) + { + shapeName = target.PropertyName.Substring(ReactiveObjectAnalyzer.BlendshapePrefix.Length); + } + else + { + continue; + } + var mesh = r.sharedMesh; if (mesh == null) continue; - var shapeName = target.PropertyName.Substring("blendShape.".Length); - if (!rendererStates.TryGetValue(r, out var states)) { - states = ImmutableList<(int, float)>.Empty; + states = ImmutableDictionary.Empty; rendererStates[r] = states; } @@ -102,16 +115,32 @@ namespace nadena.dev.modular_avatar.core.editor var activeRule = prop.actionGroups.LastOrDefault(rule => rule.InitiallyActive); if (activeRule == null || activeRule.Value is not float value) continue; + if (activeRule.ControllingObject == null) continue; // default value is being inherited - value = Math.Clamp(value, 0, 100); - - if (activeRule.IsDelete) value = -1; - - states = states.Add((index, value)); + if (isDelete) + { + if (value < 0.5f) continue; + value = -1; + } + else + { + if (states.ContainsKey(index)) + { + // Delete takes precedence over set in preview + continue; + } + + value = Math.Clamp(value, 0, 100); + } + + states = states.SetItem(index, value); rendererStates[r] = states; } - - return rendererStates.ToImmutableDictionary(); + + return rendererStates.ToImmutableDictionary( + kvp => kvp.Key, + kvp => kvp.Value.Select(shapePair => (shapePair.Key, shapePair.Value) + ).ToImmutableList()); } private IEnumerable ShapesToGroups(GameObject avatarRoot, ImmutableDictionary> shapes) diff --git a/Editor/ReactiveObjects/Simulator/ROSimulator.cs b/Editor/ReactiveObjects/Simulator/ROSimulator.cs index b2afa56b..4d192515 100644 --- a/Editor/ReactiveObjects/Simulator/ROSimulator.cs +++ b/Editor/ReactiveObjects/Simulator/ROSimulator.cs @@ -257,7 +257,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator return; } - _btn_clear.SetEnabled(!PropertyOverrides.Value.IsEmpty || !MenuItemOverrides.Value.IsEmpty); + _btn_clear.SetEnabled(PropertyOverrides.Value?.IsEmpty == false || MenuItemOverrides.Value?.IsEmpty == false); e_debugInfo.style.display = DisplayStyle.Flex; @@ -265,6 +265,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator _lastComputeContext.InvokeOnInvalidate(this, MaybeRefreshUI); var analysis = new ReactiveObjectAnalyzer(_lastComputeContext); + analysis.OptimizeShapes = false; analysis.ForcePropertyOverrides = PropertyOverrides.Value; analysis.ForceMenuItems = MenuItemOverrides.Value; var result = analysis.Analyze(avatar.gameObject); @@ -472,7 +473,7 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator var f_set_inactive = effectGroup.Q("effect__set-inactive"); var f_value = effectGroup.Q("effect__value"); var f_material = effectGroup.Q("effect__material"); - var f_delete = effectGroup.Q("effect__deleted"); + var f_delete = effectGroup.Q("effect__deleted"); f_target_component.style.display = DisplayStyle.None; f_target_component.SetEnabled(false); @@ -505,9 +506,10 @@ namespace nadena.dev.modular_avatar.core.editor.Simulator f_property.value = targetProp.PropertyName; f_property.style.display = DisplayStyle.Flex; - if (reactionRule.IsDelete) + if (reactionRule.TargetProp.PropertyName.StartsWith(ReactiveObjectAnalyzer.DeletedShapePrefix)) { f_delete.style.display = DisplayStyle.Flex; + f_delete.value = reactionRule.Value is > 0.5f ? "DELETE" : "RETAIN"; } else if (reactionRule.Value is float f) { f_value.SetValueWithoutNotify(f); diff --git a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs index 542cd5ff..3b34cec1 100644 --- a/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs +++ b/Editor/ScaleAdjuster/ScaleAdjusterPreview.cs @@ -344,7 +344,7 @@ namespace nadena.dev.modular_avatar.core.editor if (proxy == null) return; var curParent = proxy.transform.parent ?? original.transform.parent; - if (_finalBonesMap.TryGetValue(curParent, out var newRoot)) + if (curParent != null && _finalBonesMap.TryGetValue(curParent, out var newRoot)) { // We need to remember this proxy so we can avoid destroying it when we destroy VirtualAvatarRoot // in Dispose diff --git a/Editor/SetupOutfit.cs b/Editor/SetupOutfit.cs index 922fbc74..ba69ed9f 100644 --- a/Editor/SetupOutfit.cs +++ b/Editor/SetupOutfit.cs @@ -229,7 +229,7 @@ namespace nadena.dev.modular_avatar.core.editor } } - private static void FixAPose(GameObject avatarRoot, Transform outfitArmature) + internal static void FixAPose(GameObject avatarRoot, Transform outfitArmature, bool strictMode = true) { var mergeArmature = outfitArmature.GetComponent(); if (mergeArmature == null) return; @@ -249,7 +249,7 @@ namespace nadena.dev.modular_avatar.core.editor { var lowerArm = (HumanBodyBones)((int)arm + 2); - // check if the rotation of the arm differs, but distances and origin point are the same + // check if the rotation of the arm differs(, but distances and origin point are the same when strictMode) var avatarArm = rootAnimator.GetBoneTransform(arm); var outfitArm = avatarToOutfit(avatarArm); @@ -259,22 +259,27 @@ namespace nadena.dev.modular_avatar.core.editor if (outfitArm == null) return; if (outfitLowerArm == null) return; - if ((avatarArm.position - outfitArm.position).magnitude > 0.001f) return; + if (strictMode) + { + if ((avatarArm.position - outfitArm.position).magnitude > 0.001f) return; - // check relative distance to lower arm as well - var avatarArmLength = (avatarLowerArm.position - avatarArm.position).magnitude; - var outfitArmLength = (outfitLowerArm.position - outfitArm.position).magnitude; + // check relative distance to lower arm as well + var avatarArmLength = (avatarLowerArm.position - avatarArm.position).magnitude; + var outfitArmLength = (outfitLowerArm.position - outfitArm.position).magnitude; - if (Mathf.Abs(avatarArmLength - outfitArmLength) > 0.001f) return; + if (Mathf.Abs(avatarArmLength - outfitArmLength) > 0.001f) return; + } else { + if (Vector3.Dot((outfitLowerArm.position - outfitArm.position).normalized, (avatarLowerArm.position - avatarArm.position).normalized) > 0.999f) return; + } - // Rotate the outfit arm to ensure these two points match. + // Rotate the outfit arm to ensure these two bone orientations match. + Undo.RecordObject(outfitArm, "Convert A/T Pose"); var relRot = Quaternion.FromToRotation( outfitLowerArm.position - outfitArm.position, avatarLowerArm.position - avatarArm.position ); outfitArm.rotation = relRot * outfitArm.rotation; PrefabUtility.RecordPrefabInstancePropertyModifications(outfitArm); - EditorUtility.SetDirty(outfitArm); } Transform avatarToOutfit(Transform avBone) diff --git a/README.md b/README.md index 033d49d3..c4b74d03 100644 --- a/README.md +++ b/README.md @@ -33,4 +33,4 @@ For more information, check out the [documentation](https://m-a.nadena.dev). * 部分的なアニメーターを親に統合することで、様々のギミックの実装を簡単にします。 * 他にもいろいろ! -詳しくは[ドキュメンテーションページにご参照ください](https://modular-avatar.nadena.dev/ja/). +詳しくは[ドキュメンテーションページをご覧ください](https://modular-avatar.nadena.dev/ja/). diff --git a/Runtime/ReactiveObjects/ModularAvatarMaterialSetter.cs b/Runtime/ReactiveObjects/ModularAvatarMaterialSetter.cs index 0a919dd0..dfe2cf7d 100644 --- a/Runtime/ReactiveObjects/ModularAvatarMaterialSetter.cs +++ b/Runtime/ReactiveObjects/ModularAvatarMaterialSetter.cs @@ -38,7 +38,7 @@ namespace nadena.dev.modular_avatar.core } [AddComponentMenu("Modular Avatar/MA Material Setter")] - [HelpURL("https://modular-avatar.nadena.dev/docs/reference/material-setter?lang=auto")] + [HelpURL("https://modular-avatar.nadena.dev/docs/reference/reaction/material-setter?lang=auto")] public class ModularAvatarMaterialSetter : ReactiveComponent, IHaveObjReferences { [SerializeField] private List m_objects = new(); diff --git a/Runtime/ReactiveObjects/ModularAvatarObjectToggle.cs b/Runtime/ReactiveObjects/ModularAvatarObjectToggle.cs index 93b1421a..74cc69a8 100644 --- a/Runtime/ReactiveObjects/ModularAvatarObjectToggle.cs +++ b/Runtime/ReactiveObjects/ModularAvatarObjectToggle.cs @@ -21,7 +21,7 @@ namespace nadena.dev.modular_avatar.core } [AddComponentMenu("Modular Avatar/MA Object Toggle")] - [HelpURL("https://modular-avatar.nadena.dev/docs/reference/object-toggle?lang=auto")] + [HelpURL("https://modular-avatar.nadena.dev/docs/reference/reaction/object-toggle?lang=auto")] public class ModularAvatarObjectToggle : ReactiveComponent, IHaveObjReferences { [SerializeField] private List m_objects = new(); diff --git a/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs b/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs index d8e1dea5..4fff480b 100644 --- a/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs +++ b/Runtime/ReactiveObjects/ModularAvatarShapeChanger.cs @@ -57,14 +57,9 @@ namespace nadena.dev.modular_avatar.core } [AddComponentMenu("Modular Avatar/MA Shape Changer")] - [HelpURL("https://modular-avatar.nadena.dev/docs/reference/shape-changer?lang=auto")] + [HelpURL("https://modular-avatar.nadena.dev/docs/reference/reaction/shape-changer?lang=auto")] public class ModularAvatarShapeChanger : ReactiveComponent, IHaveObjReferences { - // Migration field to help with 1.10-beta series avatar data. Since this was never in a released version of MA, - // this migration support will be removed in 1.10.0. - [SerializeField] [FormerlySerializedAs("targetRenderer")] [HideInInspector] - private AvatarObjectReference m_targetRenderer = new(); - [SerializeField] [FormerlySerializedAs("Shapes")] private List m_shapes = new(); @@ -82,40 +77,6 @@ namespace nadena.dev.modular_avatar.core } } - private void OnEnable() - { - MigrateTargetRenderer(); - } - - protected override void OnValidate() - { - base.OnValidate(); - MigrateTargetRenderer(); - } - - // Migrate early versions of MASC (from Modular Avatar 1.10.0-beta.4 or earlier) to the new format, where the - // target renderer is stored separately for each shape. - // This logic will be removed in 1.10.0. - private void MigrateTargetRenderer() - { - // Note: This method runs in the context of OnValidate, and therefore cannot touch any other unity objects. - if (!string.IsNullOrEmpty(m_targetRenderer.referencePath) || m_targetRenderer.targetObject != null) - { - foreach (var shape in m_shapes) - { - if (shape.Object == null) shape.Object = new AvatarObjectReference(); - - if (string.IsNullOrEmpty(shape.Object.referencePath) && shape.Object.targetObject == null) - { - shape.Object.referencePath = m_targetRenderer.referencePath; - shape.Object.targetObject = m_targetRenderer.targetObject; - } - } - m_targetRenderer.referencePath = null; - m_targetRenderer.targetObject = null; - } - } - public IEnumerable GetObjectReferences() { foreach (var shape in m_shapes) diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim.meta b/UnitTests~/MergeAnimatorTests/ProxyAnim.meta new file mode 100644 index 00000000..659236e2 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 130af01284a51c24f99eeb52361a81fb +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller b/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller new file mode 100644 index 00000000..9a6333ca --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller @@ -0,0 +1,72 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1102 &-9046052599989551153 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: proxy_tpose + m_Speed: 1 + m_CycleOffset: 0 + m_Transitions: [] + m_StateMachineBehaviours: [] + m_Position: {x: 50, y: 50, z: 0} + m_IKOnFeet: 0 + m_WriteDefaultValues: 1 + m_Mirror: 0 + m_SpeedParameterActive: 0 + m_MirrorParameterActive: 0 + m_CycleOffsetParameterActive: 0 + m_TimeParameterActive: 0 + m_Motion: {fileID: 7400000, guid: 645a7092829eff9478fb3a29f959a6fa, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: New Animator Controller + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: proxy + m_StateMachine: {fileID: 1953483892909110087} + m_Mask: {fileID: 0} + m_Motions: [] + m_Behaviours: [] + m_BlendingMode: 0 + m_SyncedLayerIndex: -1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1107 &1953483892909110087 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: proxy + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: -9046052599989551153} + m_Position: {x: 360, y: 110, z: 0} + m_ChildStateMachines: [] + m_AnyStateTransitions: [] + m_EntryTransitions: [] + m_StateMachineTransitions: {} + m_StateMachineBehaviours: [] + m_AnyStatePosition: {x: 50, y: 20, z: 0} + m_EntryPosition: {x: 50, y: 120, z: 0} + m_ExitPosition: {x: 800, y: 120, z: 0} + m_ParentStateMachinePosition: {x: 800, y: 20, z: 0} + m_DefaultState: {fileID: -9046052599989551153} diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller.meta b/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller.meta new file mode 100644 index 00000000..b2d87165 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/New Animator Controller.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 60603c8e68ac87447b02be4e3af6a7bd +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs new file mode 100644 index 00000000..b67e30d1 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs @@ -0,0 +1,28 @@ +using modular_avatar_tests; +using nadena.dev.modular_avatar.core; +using nadena.dev.modular_avatar.core.editor; +using NUnit.Framework; +using UnityEditor.Animations; +using UnityEngine; + +namespace UnitTests.MergeAnimatorTests.ProxyAnim +{ + public class ProxyAnimTest : TestBase + { + [Test] + public void whenProxyAnimIsMerged_itIsNotReplaced() + { + var root = CreatePrefab("ProxyAnimTest.prefab"); + + var originalAnimator = (AnimatorController) root.GetComponentInChildren().animator; + var originalClip = originalAnimator.layers[0].stateMachine.states[0].state.motion as AnimationClip; + + AvatarProcessor.ProcessAvatar(root); + + var resultLayer = findFxLayer(root, "proxy"); + var resultClip = resultLayer.stateMachine.states[0].state.motion as AnimationClip; + + Assert.AreEqual(originalClip, resultClip); + } + } +} \ No newline at end of file diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs.meta b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs.meta new file mode 100644 index 00000000..bc3638bd --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 2cfba229fa1e4c718f5cb5dd579d3319 +timeCreated: 1728166108 \ No newline at end of file diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab new file mode 100644 index 00000000..dff56d51 --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab @@ -0,0 +1,378 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &603567390109878184 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2557688482630581002} + - component: {fileID: 2868037606074871127} + - component: {fileID: 1028276594299388724} + - component: {fileID: 223023489903813839} + m_Layer: 0 + m_Name: ProxyAnimTest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2557688482630581002 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603567390109878184} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.1618705, y: 1.0265146, z: 1.8807894} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 2189711873526373063} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &2868037606074871127 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603567390109878184} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &1028276594299388724 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603567390109878184} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &223023489903813839 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 603567390109878184} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!1 &1425973809379277617 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2189711873526373063} + - component: {fileID: 3380859768730913427} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2189711873526373063 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1425973809379277617} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 2557688482630581002} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3380859768730913427 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1425973809379277617} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1bb122659f724ebf85fe095ac02dc339, type: 3} + m_Name: + m_EditorClassIdentifier: + animator: {fileID: 9100000, guid: 60603c8e68ac87447b02be4e3af6a7bd, type: 2} + layerType: 5 + deleteAttachedAnimator: 1 + pathMode: 0 + matchAvatarWriteDefaults: 0 + relativePathRoot: + referencePath: + targetObject: {fileID: 0} + layerPriority: 0 diff --git a/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab.meta b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab.meta new file mode 100644 index 00000000..6ceea0ce --- /dev/null +++ b/UnitTests~/MergeAnimatorTests/ProxyAnim/ProxyAnimTest.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a77dd3314cc88714bb6e9f1ad014cfc8 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs new file mode 100644 index 00000000..19d61e6c --- /dev/null +++ b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs @@ -0,0 +1,61 @@ +using System.Linq; +using modular_avatar_tests; +using nadena.dev.modular_avatar.core.editor; +using NUnit.Framework; +using UnityEngine; + +namespace UnitTests.ReactiveComponent +{ + public class BlendshapeSyncTest : TestBase + { + [Test] + public void blendshapeSync_propagatesThroughMeshes() + { + var root = CreatePrefab("BlendshapeSyncTest.prefab"); + + var analysis = new ReactiveObjectAnalyzer().Analyze(root); + + var m1 = analysis.Shapes[new TargetProp() + { + TargetObject = root.transform.Find("m1").GetComponent(), + PropertyName = "blendShape.bottom" + }]; + var m2 = analysis.Shapes[new TargetProp() + { + TargetObject = root.transform.Find("m2").GetComponent(), + PropertyName = "blendShape.bottom" + }]; + var m3 = analysis.Shapes[new TargetProp() + { + TargetObject = root.transform.Find("m3").GetComponent(), + PropertyName = "blendShape.top" + }]; + + Assert.IsTrue(analysis.Shapes.ContainsKey(new TargetProp() + { + TargetObject = root.transform.Find("m1").GetComponent(), + PropertyName = "deletedShape.bottom" + })); + + Assert.AreEqual(4, analysis.Shapes.Count); + + foreach (var ag in m1.actionGroups) + { + ag.TargetProp = new TargetProp(); + } + + foreach (var ag in m2.actionGroups) + { + ag.TargetProp = new TargetProp(); + } + + foreach (var ag in m3.actionGroups) + { + ag.TargetProp = new TargetProp(); + } + + Assert.AreEqual(m2.actionGroups, m1.actionGroups); + Assert.AreEqual(m3.actionGroups, m1.actionGroups); + } + } +} \ No newline at end of file diff --git a/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs.meta b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs.meta new file mode 100644 index 00000000..c614946b --- /dev/null +++ b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: f74d4e816d0247159d977e21ebc57458 +timeCreated: 1728168066 \ No newline at end of file diff --git a/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab new file mode 100644 index 00000000..c0b98180 --- /dev/null +++ b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab @@ -0,0 +1,799 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &4750389987621451750 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3724328547737935111} + - component: {fileID: 6141552197888553193} + - component: {fileID: 866105862211182099} + - component: {fileID: 5955186656294850035} + m_Layer: 0 + m_Name: New Toggle + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3724328547737935111 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4750389987621451750} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 295226914695240947} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6141552197888553193 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4750389987621451750} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b29d45007c5493d926d2cd45a489529, type: 3} + m_Name: + m_EditorClassIdentifier: + Control: + name: New Toggle + icon: {fileID: 0} + type: 102 + parameter: + name: + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: [] + labels: [] + MenuSource: 1 + menuSource_otherObjectChildren: {fileID: 0} + isSynced: 1 + isSaved: 1 + isDefault: 1 + automaticValue: 1 +--- !u!114 &866105862211182099 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4750389987621451750} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7ef83cb0c23d4d7c9d41021e544a1978, type: 3} + m_Name: + m_EditorClassIdentifier: + menuToAppend: {fileID: 0} + installTargetMenu: {fileID: 0} +--- !u!114 &5955186656294850035 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 4750389987621451750} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: m1 + targetObject: {fileID: 7767603723203631002} + ShapeName: bottom + ChangeType: 1 + Value: 100 +--- !u!1 &7303978391080220300 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 295226914695240947} + - component: {fileID: 1177795503533185300} + - component: {fileID: 7792711537747161192} + - component: {fileID: 8538029171187693289} + m_Layer: 0 + m_Name: BlendshapeSyncTest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &295226914695240947 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303978391080220300} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.1618705, y: 1.0265146, z: 1.8807894} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 6955742288500591904} + - {fileID: 2035853062413530075} + - {fileID: 2118711245520540949} + - {fileID: 3724328547737935111} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &1177795503533185300 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303978391080220300} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &7792711537747161192 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303978391080220300} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &8538029171187693289 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7303978391080220300} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!1001 &1940371780088492798 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 295226914695240947} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.x + value: 5.33 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_ConstrainProportionsScale + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.z + value: 2 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_Name + value: m3 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + insertIndex: -1 + addedObject: {fileID: 4462016549056391230} + m_SourcePrefab: {fileID: 100100000, guid: fe5b76dae94c07345b74d51e9a9a8440, type: 3} +--- !u!1 &1597929094539956143 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 1940371780088492798} + m_PrefabAsset: {fileID: 0} +--- !u!114 &4462016549056391230 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1597929094539956143} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6fd7cab7d93b403280f2f9da978d8a4f, type: 3} + m_Name: + m_EditorClassIdentifier: + Bindings: + - ReferenceMesh: + referencePath: m2 + targetObject: {fileID: 1660453041666320737} + Blendshape: bottom + LocalBlendshape: top +--- !u!4 &2118711245520540949 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 1940371780088492798} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &2002541556693849136 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 295226914695240947} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.x + value: 2.75 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_ConstrainProportionsScale + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.z + value: 2 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_Name + value: m2 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: + - targetCorrespondingSourceObject: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + insertIndex: -1 + addedObject: {fileID: 1532028097981150578} + m_SourcePrefab: {fileID: 100100000, guid: fe5b76dae94c07345b74d51e9a9a8440, type: 3} +--- !u!1 &1660453041666320737 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 2002541556693849136} + m_PrefabAsset: {fileID: 0} +--- !u!114 &1532028097981150578 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1660453041666320737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 6fd7cab7d93b403280f2f9da978d8a4f, type: 3} + m_Name: + m_EditorClassIdentifier: + Bindings: + - ReferenceMesh: + referencePath: m1 + targetObject: {fileID: 7767603723203631002} + Blendshape: bottom + LocalBlendshape: +--- !u!4 &2035853062413530075 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 2002541556693849136} + m_PrefabAsset: {fileID: 0} +--- !u!1001 &7425727422508624587 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 295226914695240947} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.z + value: 2 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_Materials.Array.data[0] + value: + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_Name + value: m1 + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: fe5b76dae94c07345b74d51e9a9a8440, type: 3} +--- !u!4 &6955742288500591904 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 7425727422508624587} + m_PrefabAsset: {fileID: 0} +--- !u!1 &7767603723203631002 stripped +GameObject: + m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 7425727422508624587} + m_PrefabAsset: {fileID: 0} diff --git a/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab.meta b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab.meta new file mode 100644 index 00000000..d6863646 --- /dev/null +++ b/UnitTests~/ReactiveComponent/BlendshapeSyncTest.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 05653f5cab04e764b80709fe866c1b35 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/ReactiveComponent/DeletionTest.prefab b/UnitTests~/ReactiveComponent/DeletionTest.prefab new file mode 100644 index 00000000..6cefc636 --- /dev/null +++ b/UnitTests~/ReactiveComponent/DeletionTest.prefab @@ -0,0 +1,666 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &2464504760772767737 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3251791125987375227} + - component: {fileID: 6611954401356246169} + - component: {fileID: 4257580493320060063} + - component: {fileID: 7095484051158404692} + m_Layer: 0 + m_Name: DeletionTest + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3251791125987375227 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2464504760772767737} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0.06867766, y: 0.7869835, z: -0.57959247} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: + - {fileID: 8671858138418525756} + - {fileID: 3787319563290092876} + - {fileID: 2780879708549973278} + - {fileID: 6867583134219554799} + - {fileID: 3617623734196600728} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &6611954401356246169 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2464504760772767737} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &4257580493320060063 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2464504760772767737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &7095484051158404692 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2464504760772767737} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!1 &3134446681435896768 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2780879708549973278} + - component: {fileID: 2470606632396626262} + m_Layer: 0 + m_Name: Delete + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2780879708549973278 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3134446681435896768} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 3251791125987375227} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2470606632396626262 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 3134446681435896768} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: shape deletion test mesh + targetObject: {fileID: 0} + ShapeName: bottom + ChangeType: 0 + Value: 50 +--- !u!1 &7874409458034691206 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3787319563290092876} + - component: {fileID: 8462455628590652122} + m_Layer: 0 + m_Name: PriorSet + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3787319563290092876 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7874409458034691206} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 3251791125987375227} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8462455628590652122 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7874409458034691206} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: shape deletion test mesh + targetObject: {fileID: 0} + ShapeName: bottom + ChangeType: 1 + Value: 50 +--- !u!1 &7956182162252432618 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3617623734196600728} + - component: {fileID: 4167915178638071617} + - component: {fileID: 3280847981733507148} + m_Layer: 0 + m_Name: MenuSet + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &3617623734196600728 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7956182162252432618} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 3251791125987375227} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &4167915178638071617 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7956182162252432618} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: shape deletion test mesh + targetObject: {fileID: 0} + ShapeName: bottom + ChangeType: 1 + Value: 0 +--- !u!114 &3280847981733507148 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7956182162252432618} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b29d45007c5493d926d2cd45a489529, type: 3} + m_Name: + m_EditorClassIdentifier: + Control: + name: + icon: {fileID: 0} + type: 102 + parameter: + name: + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: [] + labels: [] + MenuSource: 1 + menuSource_otherObjectChildren: {fileID: 0} + isSynced: 1 + isSaved: 1 + isDefault: 0 + automaticValue: 1 +--- !u!1 &8389945206789797712 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6867583134219554799} + - component: {fileID: 8099891503683627458} + m_Layer: 0 + m_Name: NullSet + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &6867583134219554799 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8389945206789797712} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 1 + m_Children: [] + m_Father: {fileID: 3251791125987375227} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8099891503683627458 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8389945206789797712} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: shape deletion test mesh + targetObject: {fileID: 0} + ShapeName: bottom + ChangeType: 1 + Value: 0 +--- !u!1001 &9210451080691405271 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 3251791125987375227} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_AABB.m_Extent.z + value: 2 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 0 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + propertyPath: m_Name + value: shape deletion test mesh + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: fe5b76dae94c07345b74d51e9a9a8440, type: 3} +--- !u!4 &8671858138418525756 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: fe5b76dae94c07345b74d51e9a9a8440, + type: 3} + m_PrefabInstance: {fileID: 9210451080691405271} + m_PrefabAsset: {fileID: 0} diff --git a/UnitTests~/ReactiveComponent/DeletionTest.prefab.meta b/UnitTests~/ReactiveComponent/DeletionTest.prefab.meta new file mode 100644 index 00000000..0197de59 --- /dev/null +++ b/UnitTests~/ReactiveComponent/DeletionTest.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: a82669288fc87d94db320a2494fd76c5 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/ReactiveComponent/ObjectToggleTests.cs b/UnitTests~/ReactiveComponent/ObjectToggleTests.cs new file mode 100644 index 00000000..6637ff05 --- /dev/null +++ b/UnitTests~/ReactiveComponent/ObjectToggleTests.cs @@ -0,0 +1,50 @@ +using System.Linq; +using modular_avatar_tests; +using nadena.dev.modular_avatar.core; +using nadena.dev.modular_avatar.core.editor; +using NUnit.Framework; +using UnityEditor.Animations; +using UnityEngine; + +namespace UnitTests.ReactiveComponent +{ + internal class ObjectToggleTests : TestBase + { + [Test] + public void WhenObjectIsAlwaysOn_CorrectProxyParameterIsGenerated() + { + var root = CreateRoot("root"); + var obj = CreateChild(root, "obj"); + var toggle = CreateChild(root, "toggle"); + + // Prevent obj from being removed by the GC game objects pass + obj.AddComponent(); + + var toggleComponent = toggle.AddComponent(); + var aor = new AvatarObjectReference(); + aor.Set(obj); + + toggleComponent.Objects = new() + { + new() + { + Active = false, + Object = aor + } + }; + + AvatarProcessor.ProcessAvatar(root); + + // TODO: Ideally we should start using play mode testing for these things... + var fx = (AnimatorController)FindFxController(root).animatorController; + var readableProp = fx.parameters.FirstOrDefault( + p => p.name.StartsWith("__MA/ReadableProp/obj/UnityEngine.GameObject/m_IsActive") + ); + + Assert.IsNotNull(readableProp); + Assert.AreEqual(readableProp.defaultFloat, 0); + + Assert.IsFalse(obj.activeSelf); + } + } +} \ No newline at end of file diff --git a/UnitTests~/ReactiveComponent/ObjectToggleTests.cs.meta b/UnitTests~/ReactiveComponent/ObjectToggleTests.cs.meta new file mode 100644 index 00000000..9e86034a --- /dev/null +++ b/UnitTests~/ReactiveComponent/ObjectToggleTests.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 7c68d69f7b4a46c5b2ce3d8f26b0fa76 +timeCreated: 1729376563 \ No newline at end of file diff --git a/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs b/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs new file mode 100644 index 00000000..7cb78e50 --- /dev/null +++ b/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs @@ -0,0 +1,98 @@ +using System.Collections; +using System.Collections.Generic; +using System.Linq; +using modular_avatar_tests; +using nadena.dev.modular_avatar.core; +using nadena.dev.modular_avatar.core.editor; +using NUnit.Framework; +using UnityEngine; + +public class ShapeDeletionAnalysis : TestBase +{ + [Test] + public void BasicShapeDeletionAnalysis() + { + var root = CreatePrefab("DeletionTest.prefab"); + + var mesh = AssertPreviewDeletion(root); + + AssertBuildDeletion(mesh, root); + } + + [Test] + public void WhenShapeDeletionIsConditionedOnSubsequentChanger_DoesNotDelete() + { + var root = CreatePrefab("DeletionTest.prefab"); + root.transform.Find("MenuSet").gameObject.SetActive(true); + + AssertPreviewDeletion(root); + AssertNoMeshDeletion(root); + + var mesh = root.GetComponentInChildren(); + Assert.AreEqual(100, mesh.GetBlendShapeWeight(mesh.sharedMesh.GetBlendShapeIndex("bottom"))); + } + + + [Test] + public void WhenShapeDeletionIsConditionedOnItself_DoesNotDelete() + { + var root = CreatePrefab("DeletionTest.prefab"); + root.transform.Find("Delete").gameObject.AddComponent().InitSettings(); + + AssertNoPreviewDeletion(root); + AssertNoMeshDeletion(root); + + var mesh = root.GetComponentInChildren(); + // deletion action is initially off, so we use the shape changer above it, which is set to 50. + Assert.AreEqual(50f, mesh.GetBlendShapeWeight(mesh.sharedMesh.GetBlendShapeIndex("bottom"))); + } + + private static void AssertBuildDeletion(SkinnedMeshRenderer mesh, GameObject root) + { + var originalSharedMesh = mesh.sharedMesh; + AvatarProcessor.ProcessAvatar(root); + Assert.AreNotEqual(originalSharedMesh, mesh.sharedMesh); + + Assert.IsTrue(mesh.sharedMesh.vertices.All(v => v.z >= 0)); + } + + private static SkinnedMeshRenderer AssertPreviewDeletion(GameObject root) + { + var mesh = root.GetComponentInChildren(); + var analysis = new ReactiveObjectAnalyzer().Analyze(root); + var deletedShape = analysis.Shapes.GetValueOrDefault(new TargetProp() + { + TargetObject = mesh, + PropertyName = "deletedShape.bottom" + }); + Assert.IsNotNull(deletedShape); + var activeGroup = deletedShape.actionGroups.LastOrDefault(ag => ag.InitiallyActive); + Assert.AreEqual(1.0f, activeGroup?.Value); + return mesh; + } + + private static void AssertNoPreviewDeletion(GameObject root) + { + var mesh = root.GetComponentInChildren(); + var analysis = new ReactiveObjectAnalyzer().Analyze(root); + var deletedShape = analysis.Shapes.GetValueOrDefault(new TargetProp() + { + TargetObject = mesh, + PropertyName = "deletedShape.bottom" + }); + if (deletedShape != null) + { + var activeGroup = deletedShape.actionGroups.LastOrDefault(ag => ag.InitiallyActive); + Assert.IsFalse(activeGroup?.Value is float f && f > 0); + } + + } + + private static void AssertNoMeshDeletion(GameObject root) + { + var mesh = root.GetComponentInChildren(); + var originalSharedMesh = mesh.sharedMesh; + AvatarProcessor.ProcessAvatar(root); + Assert.AreEqual(originalSharedMesh, mesh.sharedMesh); + } +} diff --git a/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs.meta b/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs.meta new file mode 100644 index 00000000..024b7f11 --- /dev/null +++ b/UnitTests~/ReactiveComponent/ShapeDeletionAnalysis.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 18eb55e1b66a00243a91142456dfd5f5 +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx b/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx new file mode 100644 index 00000000..52fa8bb9 Binary files /dev/null and b/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx differ diff --git a/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx.meta b/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx.meta new file mode 100644 index 00000000..0f60ec10 --- /dev/null +++ b/UnitTests~/ReactiveComponent/shape deletion test mesh.fbx.meta @@ -0,0 +1,109 @@ +fileFormatVersion: 2 +guid: fe5b76dae94c07345b74d51e9a9a8440 +ModelImporter: + serializedVersion: 22200 + internalIDToNameTable: [] + externalObjects: {} + materials: + materialImportMode: 2 + materialName: 0 + materialSearch: 1 + materialLocation: 1 + animations: + legacyGenerateAnimations: 4 + bakeSimulation: 0 + resampleCurves: 1 + optimizeGameObjects: 0 + removeConstantScaleCurves: 0 + motionNodeName: + rigImportErrors: + rigImportWarnings: + animationImportErrors: + animationImportWarnings: + animationRetargetingWarnings: + animationDoRetargetingWarnings: 0 + importAnimatedCustomProperties: 0 + importConstraints: 0 + animationCompression: 1 + animationRotationError: 0.5 + animationPositionError: 0.5 + animationScaleError: 0.5 + animationWrapMode: 0 + extraExposedTransformPaths: [] + extraUserProperties: [] + clipAnimations: [] + isReadable: 0 + meshes: + lODScreenPercentages: [] + globalScale: 1 + meshCompression: 0 + addColliders: 0 + useSRGBMaterialColor: 1 + sortHierarchyByName: 1 + importPhysicalCameras: 1 + importVisibility: 1 + importBlendShapes: 1 + importCameras: 1 + importLights: 1 + nodeNameCollisionStrategy: 1 + fileIdsGeneration: 2 + swapUVChannels: 0 + generateSecondaryUV: 0 + useFileUnits: 1 + keepQuads: 0 + weldVertices: 1 + bakeAxisConversion: 0 + preserveHierarchy: 0 + skinWeightsMode: 0 + maxBonesPerVertex: 4 + minBoneWeight: 0.001 + optimizeBones: 1 + meshOptimizationFlags: -1 + indexFormat: 0 + secondaryUVAngleDistortion: 8 + secondaryUVAreaDistortion: 15.000001 + secondaryUVHardAngle: 88 + secondaryUVMarginMethod: 1 + secondaryUVMinLightmapResolution: 40 + secondaryUVMinObjectScale: 1 + secondaryUVPackMargin: 4 + useFileScale: 1 + strictVertexDataChecks: 0 + tangentSpace: + normalSmoothAngle: 60 + normalImportMode: 0 + tangentImportMode: 3 + normalCalculationMode: 4 + legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0 + blendShapeNormalImportMode: 1 + normalSmoothingSource: 0 + referencedClips: [] + importAnimation: 1 + humanDescription: + serializedVersion: 3 + human: [] + skeleton: [] + armTwist: 0.5 + foreArmTwist: 0.5 + upperLegTwist: 0.5 + legTwist: 0.5 + armStretch: 0.05 + legStretch: 0.05 + feetSpacing: 0 + globalScale: 1 + rootMotionBoneName: + hasTranslationDoF: 0 + hasExtraRoot: 0 + skeletonHasParents: 1 + lastHumanDescriptionAvatarSource: {instanceID: 0} + autoGenerateAvatarMappingIfUnspecified: 1 + animationType: 2 + humanoidOversampling: 1 + avatarSetup: 0 + addHumanoidExtraRootOnlyWhenUsingAvatar: 1 + importBlendShapeDeformPercent: 1 + remapMaterialsIfMaterialImportModeIsNone: 0 + additionalBone: 0 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs index 13be9ca7..c1061b3e 100644 --- a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.cs @@ -14,7 +14,67 @@ namespace ShapeChangerTests [Test] public void SetsCorrectInitialStatesAndAnimations() { - var root = CreatePrefab("SCDefaultAnimation.prefab"); + SetsCorrectInitialStatesAndAnimations("SCDefaultAnimation.prefab"); + } + + [Test] + public void SetsCorrectInitialStatesAndAnimationsForInactiveSC() + { + var root = CreatePrefab("SCDefaultAnimationInactive.prefab"); + AvatarProcessor.ProcessAvatar(root); + + var fx = (AnimatorController) FindFxController(root).animatorController; + var baseLayer = fx.layers[0]; + + var bt = baseLayer.stateMachine.states[0].state.motion as BlendTree; + Assert.NotNull(bt); + var subBt = bt.children[0].motion as BlendTree; + Assert.NotNull(subBt); + var clip = subBt.children[0].motion as AnimationClip; + Assert.NotNull(clip); + + var smr = root.transform.Find("test mesh").GetComponent(); + var sharedMesh = smr.sharedMesh; + + var bindings = AnimationUtility.GetCurveBindings(clip); + var curve = AnimationUtility.GetEditorCurve(clip, EditorCurveBinding.FloatCurve( + "test mesh", + typeof(SkinnedMeshRenderer), + "blendShape.key1" + )); + Assert.IsNull(curve); // always off MenuItem (due to object disable), no curve should be generated + + curve = AnimationUtility.GetEditorCurve(clip, EditorCurveBinding.FloatCurve( + "test mesh", + typeof(SkinnedMeshRenderer), + "blendShape.key2" + )); + // Always-on delete, no curve should be generated + Assert.IsNull(curve); + + curve = AnimationUtility.GetEditorCurve(clip, EditorCurveBinding.FloatCurve( + "test mesh", + typeof(SkinnedMeshRenderer), + "blendShape.key3" + )); + // Always-on set, no curve should be generated + Assert.IsNull(curve); + + // Check actual blendshape states + Assert.AreEqual(10.0f, smr.GetBlendShapeWeight(sharedMesh.GetBlendShapeIndex("key1")), 0.1f); + Assert.AreEqual(5.0f, smr.GetBlendShapeWeight(sharedMesh.GetBlendShapeIndex("key2")), 0.1f); + Assert.AreEqual(100.0f, smr.GetBlendShapeWeight(sharedMesh.GetBlendShapeIndex("key3")), 0.1f); + } + + [Test] + public void SetsCorrectInitialStatesAndAnimationsForInvertedSC() + { + SetsCorrectInitialStatesAndAnimations("SCDefaultAnimationInverted.prefab"); + } + + private void SetsCorrectInitialStatesAndAnimations(string prefabPath) + { + var root = CreatePrefab(prefabPath); AvatarProcessor.ProcessAvatar(root); var fx = (AnimatorController) FindFxController(root).animatorController; diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab index f6431564..6dbfb2b7 100644 --- a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimation.prefab @@ -46,10 +46,13 @@ MonoBehaviour: m_EditorClassIdentifier: m_inverted: 0 m_targetRenderer: - referencePath: test mesh + referencePath: targetObject: {fileID: 0} m_shapes: - - ShapeName: key2 + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key2 ChangeType: 0 Value: 100 --- !u!1 &2598725701317979415 @@ -98,10 +101,13 @@ MonoBehaviour: m_EditorClassIdentifier: m_inverted: 0 m_targetRenderer: - referencePath: test mesh + referencePath: targetObject: {fileID: 0} m_shapes: - - ShapeName: key1 + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 ChangeType: 1 Value: 10 --- !u!1 &2845086157653980983 @@ -150,10 +156,13 @@ MonoBehaviour: m_EditorClassIdentifier: m_inverted: 0 m_targetRenderer: - referencePath: test mesh + referencePath: targetObject: {fileID: 0} m_shapes: - - ShapeName: key3 + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key3 ChangeType: 1 Value: 100 --- !u!1 &6385483934583485188 @@ -174,7 +183,7 @@ GameObject: m_Icon: {fileID: 0} m_NavMeshLayer: 0 m_StaticEditorFlags: 0 - m_IsActive: 0 + m_IsActive: 1 --- !u!4 &569625391371299408 Transform: m_ObjectHideFlags: 0 @@ -204,10 +213,13 @@ MonoBehaviour: m_EditorClassIdentifier: m_inverted: 0 m_targetRenderer: - referencePath: test mesh + referencePath: targetObject: {fileID: 0} m_shapes: - - ShapeName: key1 + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 ChangeType: 1 Value: 20 --- !u!114 &2918390808850211981 @@ -238,6 +250,7 @@ MonoBehaviour: isSynced: 1 isSaved: 1 isDefault: 0 + automaticValue: 0 --- !u!114 &664065153831629983 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab new file mode 100644 index 00000000..e7640290 --- /dev/null +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab @@ -0,0 +1,668 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1307328145036867423 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7471115643889882934} + - component: {fileID: 2015798673852064281} + m_Layer: 0 + m_Name: AlwaysOffDelete + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &7471115643889882934 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1307328145036867423} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2015798673852064281 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1307328145036867423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key2 + ChangeType: 0 + Value: 100 +--- !u!1 &2598725701317979415 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1861262250770563182} + - component: {fileID: 8866671501173891171} + m_Layer: 0 + m_Name: Toggled + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &1861262250770563182 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2598725701317979415} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8866671501173891171 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2598725701317979415} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 + ChangeType: 1 + Value: 10 +--- !u!1 &2845086157653980983 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 110069860838053623} + - component: {fileID: 8218581995269956798} + m_Layer: 0 + m_Name: AlwaysOffSet + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &110069860838053623 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2845086157653980983} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8218581995269956798 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2845086157653980983} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key3 + ChangeType: 1 + Value: 100 +--- !u!1 &6385483934583485188 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 569625391371299408} + - component: {fileID: 3841502665919975468} + - component: {fileID: 2918390808850211981} + - component: {fileID: 664065153831629983} + m_Layer: 0 + m_Name: InitialOffToggled + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &569625391371299408 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3841502665919975468 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 0 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 + ChangeType: 1 + Value: 20 +--- !u!114 &2918390808850211981 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b29d45007c5493d926d2cd45a489529, type: 3} + m_Name: + m_EditorClassIdentifier: + Control: + name: + icon: {fileID: 0} + type: 102 + parameter: + name: + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: [] + labels: [] + MenuSource: 1 + menuSource_otherObjectChildren: {fileID: 0} + isSynced: 1 + isSaved: 1 + isDefault: 0 + automaticValue: 0 +--- !u!114 &664065153831629983 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7ef83cb0c23d4d7c9d41021e544a1978, type: 3} + m_Name: + m_EditorClassIdentifier: + menuToAppend: {fileID: 0} + installTargetMenu: {fileID: 0} +--- !u!1 &6855505756433160176 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8936933457054072598} + - component: {fileID: 6580323041906195452} + - component: {fileID: 146169679456758165} + - component: {fileID: 5146811121193962360} + m_Layer: 0 + m_Name: SCDefaultAnimationInactive + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8936933457054072598 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.0024816, y: 0.25853348, z: -0.63345385} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1861262250770563182} + - {fileID: 7471115643889882934} + - {fileID: 110069860838053623} + - {fileID: 569625391371299408} + - {fileID: 1326682634762807916} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &6580323041906195452 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &146169679456758165 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &5146811121193962360 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!1001 &1577363430154308999 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 8936933457054072598} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 5 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[1] + value: 6 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[2] + value: 7 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_Name + value: test mesh + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} +--- !u!4 &1326682634762807916 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + m_PrefabInstance: {fileID: 1577363430154308999} + m_PrefabAsset: {fileID: 0} diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab.meta b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab.meta new file mode 100644 index 00000000..d37cf9c1 --- /dev/null +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInactive.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 4744d7b0db7db0d459f3aa7e6a0cf7db +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab new file mode 100644 index 00000000..daa2600d --- /dev/null +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab @@ -0,0 +1,668 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1307328145036867423 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7471115643889882934} + - component: {fileID: 2015798673852064281} + m_Layer: 0 + m_Name: AlwaysOffDelete + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &7471115643889882934 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1307328145036867423} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &2015798673852064281 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1307328145036867423} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key2 + ChangeType: 0 + Value: 100 +--- !u!1 &2598725701317979415 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 1861262250770563182} + - component: {fileID: 8866671501173891171} + m_Layer: 0 + m_Name: Toggled + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &1861262250770563182 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2598725701317979415} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8866671501173891171 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2598725701317979415} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 + ChangeType: 1 + Value: 10 +--- !u!1 &2845086157653980983 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 110069860838053623} + - component: {fileID: 8218581995269956798} + m_Layer: 0 + m_Name: AlwaysOffSet + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 0 +--- !u!4 &110069860838053623 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2845086157653980983} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8218581995269956798 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 2845086157653980983} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key3 + ChangeType: 1 + Value: 100 +--- !u!1 &6385483934583485188 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 569625391371299408} + - component: {fileID: 3841502665919975468} + - component: {fileID: 2918390808850211981} + - component: {fileID: 664065153831629983} + m_Layer: 0 + m_Name: InitialOnToggled + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &569625391371299408 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 0, y: 0, z: 0} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: [] + m_Father: {fileID: 8936933457054072598} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &3841502665919975468 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 2db441f589c3407bb6fb5f02ff8ab541, type: 3} + m_Name: + m_EditorClassIdentifier: + m_inverted: 1 + m_shapes: + - Object: + referencePath: test mesh + targetObject: {fileID: 0} + ShapeName: key1 + ChangeType: 1 + Value: 20 +--- !u!114 &2918390808850211981 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 3b29d45007c5493d926d2cd45a489529, type: 3} + m_Name: + m_EditorClassIdentifier: + Control: + name: + icon: {fileID: 0} + type: 102 + parameter: + name: + value: 1 + style: 0 + subMenu: {fileID: 0} + subParameters: [] + labels: [] + MenuSource: 1 + menuSource_otherObjectChildren: {fileID: 0} + isSynced: 1 + isSaved: 1 + isDefault: 1 + automaticValue: 0 +--- !u!114 &664065153831629983 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6385483934583485188} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 7ef83cb0c23d4d7c9d41021e544a1978, type: 3} + m_Name: + m_EditorClassIdentifier: + menuToAppend: {fileID: 0} + installTargetMenu: {fileID: 0} +--- !u!1 &6855505756433160176 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 8936933457054072598} + - component: {fileID: 6580323041906195452} + - component: {fileID: 146169679456758165} + - component: {fileID: 5146811121193962360} + m_Layer: 0 + m_Name: SCDefaultAnimationInverted + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &8936933457054072598 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 1.0024816, y: 0.25853348, z: -0.63345385} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 1861262250770563182} + - {fileID: 7471115643889882934} + - {fileID: 110069860838053623} + - {fileID: 569625391371299408} + - {fileID: 1326682634762807916} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &6580323041906195452 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 0} + m_CullingMode: 0 + m_UpdateMode: 0 + m_ApplyRootMotion: 0 + m_LinearVelocityBlending: 0 + m_StabilizeFeet: 0 + m_WarningMessage: + m_HasTransformHierarchy: 1 + m_AllowConstantClipSamplingOptimization: 1 + m_KeepAnimatorStateOnDisable: 0 + m_WriteDefaultValuesOnDisable: 0 +--- !u!114 &146169679456758165 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 542108242, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + Name: + ViewPosition: {x: 0, y: 1.6, z: 0.2} + Animations: 0 + ScaleIPD: 1 + lipSync: 0 + lipSyncJawBone: {fileID: 0} + lipSyncJawClosed: {x: 0, y: 0, z: 0, w: 1} + lipSyncJawOpen: {x: 0, y: 0, z: 0, w: 1} + VisemeSkinnedMesh: {fileID: 0} + MouthOpenBlendShapeName: Facial_Blends.Jaw_Down + VisemeBlendShapes: [] + unityVersion: + portraitCameraPositionOffset: {x: 0, y: 0, z: 0} + portraitCameraRotationOffset: {x: 0, y: 1, z: 0, w: -0.00000004371139} + networkIDs: [] + customExpressions: 0 + expressionsMenu: {fileID: 0} + expressionParameters: {fileID: 0} + enableEyeLook: 0 + customEyeLookSettings: + eyeMovement: + confidence: 0.5 + excitement: 0.5 + leftEye: {fileID: 0} + rightEye: {fileID: 0} + eyesLookingStraight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingUp: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingDown: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingLeft: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyesLookingRight: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidType: 0 + upperLeftEyelid: {fileID: 0} + upperRightEyelid: {fileID: 0} + lowerLeftEyelid: {fileID: 0} + lowerRightEyelid: {fileID: 0} + eyelidsDefault: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsClosed: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingUp: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsLookingDown: + upper: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + lower: + linked: 1 + left: {x: 0, y: 0, z: 0, w: 0} + right: {x: 0, y: 0, z: 0, w: 0} + eyelidsSkinnedMesh: {fileID: 0} + eyelidsBlendshapes: + customizeAnimationLayers: 0 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 4 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 5 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + specialAnimationLayers: + - isEnabled: 0 + type: 6 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 7 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 8 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + AnimationPreset: {fileID: 0} + animationHashSet: [] + autoFootsteps: 1 + autoLocomotion: 1 + collider_head: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_torso: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_footL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_handL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleL: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerIndexR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerMiddleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerRingR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} + collider_fingerLittleR: + isMirrored: 1 + state: 0 + transform: {fileID: 0} + radius: 0 + height: 0 + position: {x: 0, y: 0, z: 0} + rotation: {x: 0, y: 0, z: 0, w: 1} +--- !u!114 &5146811121193962360 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 6855505756433160176} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3} + m_Name: + m_EditorClassIdentifier: + launchedFromSDKPipeline: 0 + completedSDKPipeline: 0 + blueprintId: + contentType: 0 + assetBundleUnityVersion: + fallbackStatus: 0 +--- !u!1001 &1577363430154308999 +PrefabInstance: + m_ObjectHideFlags: 0 + serializedVersion: 2 + m_Modification: + serializedVersion: 3 + m_TransformParent: {fileID: 8936933457054072598} + m_Modifications: + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.x + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalPosition.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.w + value: 0.7071067 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.x + value: -0.7071068 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalRotation.z + value: -0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.x + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.y + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_LocalEulerAnglesHint.z + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_DirtyAABB + value: 0 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_AABB.m_Extent.x + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_AABB.m_Extent.y + value: 1 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[0] + value: 5 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[1] + value: 6 + objectReference: {fileID: 0} + - target: {fileID: -3887185075125053422, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_BlendShapeWeights.Array.data[2] + value: 7 + objectReference: {fileID: 0} + - target: {fileID: 919132149155446097, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + propertyPath: m_Name + value: test mesh + objectReference: {fileID: 0} + m_RemovedComponents: [] + m_RemovedGameObjects: [] + m_AddedGameObjects: [] + m_AddedComponents: [] + m_SourcePrefab: {fileID: 100100000, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} +--- !u!4 &1326682634762807916 stripped +Transform: + m_CorrespondingSourceObject: {fileID: -8679921383154817045, guid: cd28f61dacdc2424d951194ff69ba154, type: 3} + m_PrefabInstance: {fileID: 1577363430154308999} + m_PrefabAsset: {fileID: 0} diff --git a/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab.meta b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab.meta new file mode 100644 index 00000000..487346d8 --- /dev/null +++ b/UnitTests~/ShapeChanger/InitialStates/SCDefaultAnimationInverted.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: c86e54d4b828d364aa677a5b3ce7be12 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/VirtualMenuTests/VirtualMenuTests.cs b/UnitTests~/VirtualMenuTests/VirtualMenuTests.cs index 81a9ffa3..5450dba0 100644 --- a/UnitTests~/VirtualMenuTests/VirtualMenuTests.cs +++ b/UnitTests~/VirtualMenuTests/VirtualMenuTests.cs @@ -698,6 +698,32 @@ namespace modular_avatar_tests.VirtualMenuTests Assert.AreEqual(4, virtualMenu.RootMenuNode.Controls[0].SubmenuNode.Controls[5].subParameters.Length); } + [Test] + public void MergeArmatureAndMenuInstallerOnSameObjectWorks() + { + var root = CreateRoot("root"); + var armature = CreateChild(root, "Armature"); + var installer = armature.AddComponent(); + + var merge = installer.gameObject.AddComponent(); + merge.mergeTarget.Set(root); + + var menu = Create(); + menu.controls.Add(new VRCExpressionsMenu.Control() + { + name = "control", + type = VRCExpressionsMenu.Control.ControlType.Toggle + }); + + installer.menuToAppend = menu; + + AvatarProcessor.ProcessAvatar(root); + + var realizedMenu = root.GetComponent().expressionsMenu; + Assert.AreEqual(1, realizedMenu.controls.Count); + Assert.AreEqual("control", realizedMenu.controls[0].name); + } + ModularAvatarMenuInstaller CreateInstaller(string name) { GameObject obj = new GameObject(); diff --git a/docs~/docs/reference/reaction/debugger/index.md b/docs~/docs/reference/reaction/debugger/index.md index 6cbfbf47..2eae1191 100644 --- a/docs~/docs/reference/reaction/debugger/index.md +++ b/docs~/docs/reference/reaction/debugger/index.md @@ -1,5 +1,4 @@ - ---- +--- sidebar_position: 900 --- diff --git a/docs~/src/pages/index.module.css b/docs~/src/pages/index.module.css index a8166690..9ef0a6aa 100644 --- a/docs~/src/pages/index.module.css +++ b/docs~/src/pages/index.module.css @@ -23,6 +23,7 @@ justify-content: center; column-gap: 2rem; row-gap: 1rem; + margin-bottom: 1em; } @media screen and (max-width: 996px) { @@ -36,4 +37,4 @@ div.logo { text-align: center; display: flex; justify-content: center; -} \ No newline at end of file +} diff --git a/docs~/src/pages/index.tsx b/docs~/src/pages/index.tsx index 88796298..889f8ced 100644 --- a/docs~/src/pages/index.tsx +++ b/docs~/src/pages/index.tsx @@ -29,7 +29,7 @@ function HomepageHeader() {

Drag-and-Drop Avatar Assembly

-