diff --git a/Editor/Animation/DeepClone.cs b/Editor/Animation/DeepClone.cs index d63c81ac..8980548e 100644 --- a/Editor/Animation/DeepClone.cs +++ b/Editor/Animation/DeepClone.cs @@ -33,7 +33,7 @@ namespace nadena.dev.modular_avatar.animation if (original == null) return null; if (cloneMap == null) cloneMap = new Dictionary(); - System.Func visitor = null; + Func visitor = null; if (basePath != null) { visitor = o => CloneWithPathMapping(o, basePath); @@ -126,8 +126,12 @@ namespace nadena.dev.modular_avatar.animation { case SerializedPropertyType.ObjectReference: { - var newObj = DoClone(prop.objectReferenceValue, basePath, cloneMap); - prop.objectReferenceValue = newObj; + if (prop.objectReferenceValue != null && prop.objectReferenceValue != obj) + { + var newObj = DoClone(prop.objectReferenceValue, basePath, cloneMap); + prop.objectReferenceValue = newObj; + } + break; } // Iterating strings can get super slow... diff --git a/Editor/RenameParametersHook.cs b/Editor/RenameParametersHook.cs index b2bb3e21..c5598a9a 100644 --- a/Editor/RenameParametersHook.cs +++ b/Editor/RenameParametersHook.cs @@ -374,23 +374,26 @@ namespace nadena.dev.modular_avatar.core.editor merger.animator = _context.ConvertAnimatorController(overrideController); } - var controller = merger.animator as AnimatorController; - if (controller != null) + var mappings = paramInfo.GetParameterRemappingsAt(obj); + var remap = mappings.SelectMany(item => { - var mappings = paramInfo.GetParameterRemappingsAt(obj); - var remap = mappings.SelectMany(item => - { - if (item.Key.Item1 == ParameterNamespace.Animator) return new[] { item }; + if (item.Key.Item1 == ParameterNamespace.Animator) return new[] { item }; - return PhysBoneSuffixes.Select(suffix => - new KeyValuePair<(ParameterNamespace, string), ParameterMapping>( - (ParameterNamespace.Animator, item.Key.Item2 + suffix), - new ParameterMapping(item.Value.ParameterName + suffix, item.Value.IsHidden) - ) - ); - }).ToImmutableDictionary(); - ProcessAnimator(ref controller, remap); - merger.animator = controller; + return PhysBoneSuffixes.Select(suffix => + new KeyValuePair<(ParameterNamespace, string), ParameterMapping>( + (ParameterNamespace.Animator, item.Key.Item2 + suffix), + new ParameterMapping(item.Value.ParameterName + suffix, item.Value.IsHidden) + ) + ); + }).ToImmutableDictionary(); + + if (merger.animator != null) + { + Profiler.BeginSample("DeepCloneAnimator"); + merger.animator = new DeepClone(_context.PluginBuildContext).DoClone(merger.animator); + Profiler.EndSample(); + + ProcessRuntimeAnimatorController(merger.animator, remap); } break; @@ -482,6 +485,28 @@ namespace nadena.dev.modular_avatar.core.editor return rv; } + private void ProcessRuntimeAnimatorController(RuntimeAnimatorController controller, + ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> remap) + { + if (controller is AnimatorController ac) + { + ProcessAnimator(ac, remap); + } + else if (controller is AnimatorOverrideController aoc) + { + var list = new List>(); + aoc.GetOverrides(list); + + for (var i = 0; i < list.Count; i++) + { + var kvp = list[i]; + if (kvp.Value != null) ProcessClip(kvp.Value, remap); + } + + ProcessRuntimeAnimatorController(aoc.runtimeAnimatorController, remap); + } + } + private void ProcessMenuInstaller(ModularAvatarMenuInstaller installer, ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> remaps) { @@ -500,20 +525,14 @@ namespace nadena.dev.modular_avatar.core.editor }); } - private void ProcessAnimator(ref AnimatorController controller, ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> remaps) + private void ProcessAnimator(AnimatorController controller, + ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> remaps) { if (remaps.IsEmpty) return; var visited = new HashSet(); var queue = new Queue(); - // Deep clone the animator - if (!_context.PluginBuildContext.IsTemporaryAsset(controller)) - { - Profiler.BeginSample("DeepCloneAnimator"); - controller = _context.DeepCloneAnimator(controller); - Profiler.EndSample(); - } var parameters = controller.parameters; for (int i = 0; i < parameters.Length; i++) @@ -598,9 +617,53 @@ namespace nadena.dev.modular_avatar.core.editor } } - if (state.motion is BlendTree blendTree) + ProcessMotion(state.motion, remaps); + } + + private void ProcessMotion(Motion motion, + ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> remaps) + { + if (motion is BlendTree blendTree) ProcessBlendtree(blendTree, remaps); + + if (motion is AnimationClip clip) ProcessClip(clip, remaps); + } + + private void ProcessClip(AnimationClip clip, + ImmutableDictionary<(ParameterNamespace, string), ParameterMapping> remaps) + { + var curveBindings = AnimationUtility.GetCurveBindings(clip); + + var bindingsToUpdate = new List(); + var newCurves = new List(); + + foreach (var binding in curveBindings) { - ProcessBlendtree(blendTree, remaps); + if (binding.path != "" || binding.type != typeof(Animator)) continue; + if (remaps.TryGetValue((ParameterNamespace.Animator, binding.propertyName), out var newBinding)) + { + var curCurve = AnimationUtility.GetEditorCurve(clip, binding); + + bindingsToUpdate.Add(binding); + newCurves.Add(null); + + bindingsToUpdate.Add(new EditorCurveBinding + { + path = "", + type = typeof(Animator), + propertyName = newBinding.ParameterName + }); + newCurves.Add(curCurve); + } + } + + if (bindingsToUpdate.Any()) + { + AnimationUtility.SetEditorCurves(clip, bindingsToUpdate.ToArray(), newCurves.ToArray()); + + // Workaround apparent unity bug where the clip's curves are not deleted + for (var i = 0; i < bindingsToUpdate.Count; i++) + if (newCurves[i] == null && AnimationUtility.GetEditorCurve(clip, bindingsToUpdate[i]) != null) + AnimationUtility.SetEditorCurve(clip, bindingsToUpdate[i], newCurves[i]); } } @@ -613,10 +676,7 @@ namespace nadena.dev.modular_avatar.core.editor for (int i = 0; i < children.Length; i++) { var childMotion = children[i]; - if (childMotion.motion is BlendTree subTree) - { - ProcessBlendtree(subTree, remaps); - } + ProcessMotion(childMotion.motion, remaps); childMotion.directBlendParameter = remap(remaps, childMotion.directBlendParameter); children[i] = childMotion; diff --git a/UnitTests~/Animation/AnimParameterPathRewrite.meta b/UnitTests~/Animation/AnimParameterPathRewrite.meta new file mode 100644 index 00000000..d3efea9d --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2e5b23715e0c7134eb51bbf4948db3a9 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewriting.prefab b/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewriting.prefab new file mode 100644 index 00000000..613035f2 --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewriting.prefab @@ -0,0 +1,524 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &302339574752509481 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6359461429068357436} + - component: {fileID: 5173578812323945314} + - component: {fileID: 891240256333545410} + - component: {fileID: 3339357898973004722} + m_Layer: 0 + m_Name: o2 + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6359461429068357436 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 302339574752509481} + 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: 7462472502468143500} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &5173578812323945314 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 302339574752509481} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 22100000, guid: 6f4d2f99ba5c4ec45aeb1a0947b058ca, type: 2} + 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 &891240256333545410 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 302339574752509481} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 71a96d4ea0c344f39e277d82035bf9bd, type: 3} + m_Name: + m_EditorClassIdentifier: + parameters: + - nameOrPrefix: p + remapTo: x + internalParameter: 0 + isPrefix: 0 + syncType: 0 + localOnly: 0 + defaultValue: 0 + saved: 0 + hasExplicitDefaultValue: 0 + m_overrideAnimatorDefaults: 0 +--- !u!114 &3339357898973004722 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 302339574752509481} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1bb122659f724ebf85fe095ac02dc339, type: 3} + m_Name: + m_EditorClassIdentifier: + animator: {fileID: 22100000, guid: 6f4d2f99ba5c4ec45aeb1a0947b058ca, type: 2} + layerType: 5 + deleteAttachedAnimator: 1 + pathMode: 0 + matchAvatarWriteDefaults: 0 + relativePathRoot: + referencePath: + targetObject: {fileID: 0} + layerPriority: 0 +--- !u!1 &542376843316153556 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 3552196613977309505} + - component: {fileID: 3784784085405600826} + - component: {fileID: 6629898499184844742} + - component: {fileID: 7657981511350229554} + m_Layer: 0 + m_Name: o + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &3552196613977309505 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542376843316153556} + 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: 7462472502468143500} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &3784784085405600826 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542376843316153556} + m_Enabled: 1 + m_Avatar: {fileID: 0} + m_Controller: {fileID: 9100000, guid: 86f3cbf9e58a4824096d5335ce7dbd97, type: 2} + 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 &6629898499184844742 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542376843316153556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 71a96d4ea0c344f39e277d82035bf9bd, type: 3} + m_Name: + m_EditorClassIdentifier: + parameters: + - nameOrPrefix: p + remapTo: x + internalParameter: 0 + isPrefix: 0 + syncType: 0 + localOnly: 0 + defaultValue: 0 + saved: 0 + hasExplicitDefaultValue: 0 + m_overrideAnimatorDefaults: 0 +--- !u!114 &7657981511350229554 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 542376843316153556} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1bb122659f724ebf85fe095ac02dc339, type: 3} + m_Name: + m_EditorClassIdentifier: + animator: {fileID: 9100000, guid: 86f3cbf9e58a4824096d5335ce7dbd97, type: 2} + layerType: 5 + deleteAttachedAnimator: 1 + pathMode: 0 + matchAvatarWriteDefaults: 0 + relativePathRoot: + referencePath: + targetObject: {fileID: 0} + layerPriority: 0 +--- !u!1 &937779371009764840 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 7462472502468143500} + - component: {fileID: 8062259706123878597} + - component: {fileID: 5313020126984717461} + - component: {fileID: 1244417098746484615} + m_Layer: 0 + m_Name: AnimParameterPathRewriting + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &7462472502468143500 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 937779371009764840} + serializedVersion: 2 + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -0.024706353, y: 0.69251794, z: -0.07990309} + m_LocalScale: {x: 1, y: 1, z: 1} + m_ConstrainProportionsScale: 0 + m_Children: + - {fileID: 3552196613977309505} + - {fileID: 6359461429068357436} + m_Father: {fileID: 0} + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!95 &8062259706123878597 +Animator: + serializedVersion: 5 + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 937779371009764840} + 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 &5313020126984717461 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 937779371009764840} + 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 &1244417098746484615 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 937779371009764840} + 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 diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewriting.prefab.meta b/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewriting.prefab.meta new file mode 100644 index 00000000..877231b5 --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewriting.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: cf573b71e8571ce46b1c3178cf9cb53b +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewritingTest.cs b/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewritingTest.cs new file mode 100644 index 00000000..cf51e6b2 --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewritingTest.cs @@ -0,0 +1,39 @@ +using nadena.dev.modular_avatar.core.editor; +using NUnit.Framework; +using UnityEditor; +using UnityEngine; + +namespace modular_avatar_tests +{ + public class AnimParameterPathRewritingTest : TestBase + { + [Test] + public void test_AnimParameterPathRewriting() + { + var prefab = CreatePrefab("AnimParameterPathRewriting.prefab"); + + var originalClip = LoadAsset("clip.anim"); + + AvatarProcessor.ProcessAvatar(prefab); + + var origCurves = AnimationUtility.GetCurveBindings(originalClip); + Assert.AreEqual(1, origCurves.Length); + Assert.AreEqual("", origCurves[0].path); + Assert.AreEqual(typeof(Animator), origCurves[0].type); + Assert.AreEqual("p", origCurves[0].propertyName); + + var curves = AnimationUtility.GetCurveBindings(findFxClip(prefab, "l1")); + Assert.AreEqual(1, curves.Length); + Assert.AreEqual("", curves[0].path); + Assert.AreEqual(typeof(Animator), curves[0].type); + Assert.AreEqual("x", curves[0].propertyName); + + // Animation override controller handling + curves = AnimationUtility.GetCurveBindings(findFxClip(prefab, "l2")); + Assert.AreEqual(1, curves.Length); + Assert.AreEqual("", curves[0].path); + Assert.AreEqual(typeof(Animator), curves[0].type); + Assert.AreEqual("x", curves[0].propertyName); + } + } +} \ No newline at end of file diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewritingTest.cs.meta b/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewritingTest.cs.meta new file mode 100644 index 00000000..f3c7f0ed --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/AnimParameterPathRewritingTest.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 52bac4b6d5014bd29cfffe3520b8eb85 +timeCreated: 1725154964 \ No newline at end of file diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/ac1.controller b/UnitTests~/Animation/AnimParameterPathRewrite/ac1.controller new file mode 100644 index 00000000..f08d9c9a --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/ac1.controller @@ -0,0 +1,78 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1107 &-1755145870298617964 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: l1 + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: 3116197472753520068} + m_Position: {x: 101.60004, y: 211.2, 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: 3116197472753520068} +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: ac1 + serializedVersion: 5 + m_AnimatorParameters: + - m_Name: p + m_Type: 1 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 9100000} + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: l1 + m_StateMachine: {fileID: -1755145870298617964} + 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!1102 &3116197472753520068 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: clip + 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: 423128d1abfae154b8c2e9fe7db98495, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/ac1.controller.meta b/UnitTests~/Animation/AnimParameterPathRewrite/ac1.controller.meta new file mode 100644 index 00000000..b1873b36 --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/ac1.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 86f3cbf9e58a4824096d5335ce7dbd97 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/ac2.controller b/UnitTests~/Animation/AnimParameterPathRewrite/ac2.controller new file mode 100644 index 00000000..0da2fbf5 --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/ac2.controller @@ -0,0 +1,78 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1107 &-1755145870298617964 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: l2 + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: 3116197472753520068} + m_Position: {x: 101.60004, y: 211.2, 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: 3116197472753520068} +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: ac2 + serializedVersion: 5 + m_AnimatorParameters: + - m_Name: p + m_Type: 1 + m_DefaultFloat: 0 + m_DefaultInt: 0 + m_DefaultBool: 0 + m_Controller: {fileID: 9100000} + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: l2 + m_StateMachine: {fileID: -1755145870298617964} + 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!1102 &3116197472753520068 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: clip + 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: b6906f5e1ec7713458d5cc3a8b28f0a8, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/ac2.controller.meta b/UnitTests~/Animation/AnimParameterPathRewrite/ac2.controller.meta new file mode 100644 index 00000000..798ebcea --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/ac2.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 3283dfb3691bbf14d92bc3926c4a87e7 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/aoc.overrideController b/UnitTests~/Animation/AnimParameterPathRewrite/aoc.overrideController new file mode 100644 index 00000000..1fdcb873 --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/aoc.overrideController @@ -0,0 +1,13 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!221 &22100000 +AnimatorOverrideController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: aoc + m_Controller: {fileID: 9100000, guid: 3283dfb3691bbf14d92bc3926c4a87e7, type: 2} + m_Clips: + - m_OriginalClip: {fileID: 7400000, guid: b6906f5e1ec7713458d5cc3a8b28f0a8, type: 2} + m_OverrideClip: {fileID: 7400000, guid: 423128d1abfae154b8c2e9fe7db98495, type: 2} diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/aoc.overrideController.meta b/UnitTests~/Animation/AnimParameterPathRewrite/aoc.overrideController.meta new file mode 100644 index 00000000..09faf767 --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/aoc.overrideController.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6f4d2f99ba5c4ec45aeb1a0947b058ca +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 22100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/clip.anim b/UnitTests~/Animation/AnimParameterPathRewrite/clip.anim new file mode 100644 index 00000000..e50d4e9b --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/clip.anim @@ -0,0 +1,122 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: clip + serializedVersion: 7 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: p + path: + classID: 95 + script: {fileID: 0} + flags: 16 + m_PPtrCurves: [] + m_SampleRate: 60 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: + - serializedVersion: 2 + path: 0 + attribute: 2181537457 + script: {fileID: 0} + typeID: 95 + customType: 0 + isPPtrCurve: 0 + isIntCurve: 0 + isSerializeReferenceCurve: 0 + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 1 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: + - serializedVersion: 2 + curve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 136 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + attribute: p + path: + classID: 95 + script: {fileID: 0} + flags: 16 + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/clip.anim.meta b/UnitTests~/Animation/AnimParameterPathRewrite/clip.anim.meta new file mode 100644 index 00000000..d1e78870 --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/clip.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 423128d1abfae154b8c2e9fe7db98495 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/clip2.anim b/UnitTests~/Animation/AnimParameterPathRewrite/clip2.anim new file mode 100644 index 00000000..ad46a32b --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/clip2.anim @@ -0,0 +1,53 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!74 &7400000 +AnimationClip: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: clip2 + serializedVersion: 7 + m_Legacy: 0 + m_Compressed: 0 + m_UseHighQualityCurve: 1 + m_RotationCurves: [] + m_CompressedRotationCurves: [] + m_EulerCurves: [] + m_PositionCurves: [] + m_ScaleCurves: [] + m_FloatCurves: [] + m_PPtrCurves: [] + m_SampleRate: 60 + m_WrapMode: 0 + m_Bounds: + m_Center: {x: 0, y: 0, z: 0} + m_Extent: {x: 0, y: 0, z: 0} + m_ClipBindingConstant: + genericBindings: [] + pptrCurveMapping: [] + m_AnimationClipSettings: + serializedVersion: 2 + m_AdditiveReferencePoseClip: {fileID: 0} + m_AdditiveReferencePoseTime: 0 + m_StartTime: 0 + m_StopTime: 1 + m_OrientationOffsetY: 0 + m_Level: 0 + m_CycleOffset: 0 + m_HasAdditiveReferencePose: 0 + m_LoopTime: 0 + m_LoopBlend: 0 + m_LoopBlendOrientation: 0 + m_LoopBlendPositionY: 0 + m_LoopBlendPositionXZ: 0 + m_KeepOriginalOrientation: 0 + m_KeepOriginalPositionY: 1 + m_KeepOriginalPositionXZ: 0 + m_HeightFromFeet: 0 + m_Mirror: 0 + m_EditorCurves: [] + m_EulerEditorCurves: [] + m_HasGenericRootTransform: 0 + m_HasMotionFloatCurves: 0 + m_Events: [] diff --git a/UnitTests~/Animation/AnimParameterPathRewrite/clip2.anim.meta b/UnitTests~/Animation/AnimParameterPathRewrite/clip2.anim.meta new file mode 100644 index 00000000..7006ebce --- /dev/null +++ b/UnitTests~/Animation/AnimParameterPathRewrite/clip2.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b6906f5e1ec7713458d5cc3a8b28f0a8 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: