From 8ac7217c26abd14231dc1d92b66e78d75d4e5b71 Mon Sep 17 00:00:00 2001 From: bd_ Date: Fri, 27 Jan 2023 21:14:20 +0900 Subject: [PATCH] fix: synced layer motion overrides not preserved over MA processing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reported-By: ぷも --- .../EditModeTests/SyncedLayerHandling.meta | 8 + .../SyncedLayerHandling/AC1.controller | 189 +++++++++ .../SyncedLayerHandling/AC1.controller.meta | 8 + .../SyncedLayerHandling/Base.controller | 43 ++ .../SyncedLayerHandling/Base.controller.meta | 8 + .../SyncedLayerHandling/BaseController.prefab | 355 +++++++++++++++++ .../BaseController.prefab.meta | 7 + .../MergedController.prefab | 373 ++++++++++++++++++ .../MergedController.prefab.meta | 7 + .../SyncedLayerHandling.cs | 97 +++++ .../SyncedLayerHandling.cs.meta | 3 + .../EditModeTests/SyncedLayerHandling/m1.anim | 53 +++ .../SyncedLayerHandling/m1.anim.meta | 8 + .../EditModeTests/SyncedLayerHandling/m2.anim | 53 +++ .../SyncedLayerHandling/m2.anim.meta | 8 + .../EditModeTests/SyncedLayerHandling/m3.anim | 53 +++ .../SyncedLayerHandling/m3.anim.meta | 8 + .../EditModeTests/SyncedLayerHandling/m4.anim | 53 +++ .../SyncedLayerHandling/m4.anim.meta | 8 + .../_ModularAvatar/EditModeTests/TestBase.cs | 10 + .../Editor/AnimatorMerger.cs | 119 +++++- 21 files changed, 1450 insertions(+), 21 deletions(-) create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling.meta create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/AC1.controller create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/AC1.controller.meta create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/Base.controller create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/Base.controller.meta create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/BaseController.prefab create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/BaseController.prefab.meta create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/MergedController.prefab create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/MergedController.prefab.meta create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/SyncedLayerHandling.cs create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/SyncedLayerHandling.cs.meta create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m1.anim create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m1.anim.meta create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m2.anim create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m2.anim.meta create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m3.anim create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m3.anim.meta create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m4.anim create mode 100644 Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m4.anim.meta diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling.meta b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling.meta new file mode 100644 index 00000000..76cb3149 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 9568dd1c9dd90c846a503bc642149068 +folderAsset: yes +DefaultImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/AC1.controller b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/AC1.controller new file mode 100644 index 00000000..77e1dd56 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/AC1.controller @@ -0,0 +1,189 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1107 &-1523926916476422360 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: sync + m_ChildStates: [] + 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: 0} +--- !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_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: 487233783815393512} + 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} + - serializedVersion: 5 + m_Name: main + m_StateMachine: {fileID: 5038666263108125925} + 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} + - serializedVersion: 5 + m_Name: sync + m_StateMachine: {fileID: -1523926916476422360} + m_Mask: {fileID: 0} + m_Motions: + - serializedVersion: 2 + m_State: {fileID: 3457079820388324162} + m_Motion: {fileID: 7400000, guid: bf660ccc19e7d6e45849be7bdb273645, type: 2} + - serializedVersion: 2 + m_State: {fileID: 592244106348618204} + m_Motion: {fileID: 7400000, guid: b4473bdae48543347999d599bcef9efc, type: 2} + m_Behaviours: + - m_State: {fileID: 3457079820388324162} + m_StateMachineBehaviours: + - {fileID: 684586325619030559} + m_BlendingMode: 0 + m_SyncedLayerIndex: 1 + m_DefaultWeight: 0 + m_IKPass: 0 + m_SyncedLayerAffectsTiming: 0 + m_Controller: {fileID: 9100000} +--- !u!1107 &487233783815393512 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + 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: 0} +--- !u!1102 &592244106348618204 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: m2 + 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: 7104638764aea2b4682734684ce18d68, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!114 &684586325619030559 +MonoBehaviour: + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 0} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: -1936262289, guid: 67cc4cb7839cd3741b63733d5adf0442, type: 3} + m_Name: + m_EditorClassIdentifier: + playable: 0 + layer: 1 + goalWeight: 0.5 + blendDuration: 0 + debugString: +--- !u!1102 &3457079820388324162 +AnimatorState: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: m1 + 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: 462fc0905374b744fb7a4ca1110e9c84, type: 2} + m_Tag: + m_SpeedParameter: + m_MirrorParameter: + m_CycleOffsetParameter: + m_TimeParameter: +--- !u!1107 &5038666263108125925 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: main + m_ChildStates: + - serializedVersion: 1 + m_State: {fileID: 3457079820388324162} + m_Position: {x: 360, y: 10, z: 0} + - serializedVersion: 1 + m_State: {fileID: 592244106348618204} + m_Position: {x: 360, y: 120, 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: 3457079820388324162} diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/AC1.controller.meta b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/AC1.controller.meta new file mode 100644 index 00000000..2856a428 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/AC1.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 22f4686ec8638e243854be6fccb38820 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/Base.controller b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/Base.controller new file mode 100644 index 00000000..657b3f7d --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/Base.controller @@ -0,0 +1,43 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1107 &-4918781818902285444 +AnimatorStateMachine: + serializedVersion: 6 + m_ObjectHideFlags: 1 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base Layer + m_ChildStates: [] + 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: 0} +--- !u!91 &9100000 +AnimatorController: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_Name: Base + serializedVersion: 5 + m_AnimatorParameters: [] + m_AnimatorLayers: + - serializedVersion: 5 + m_Name: Base Layer + m_StateMachine: {fileID: -4918781818902285444} + 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} diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/Base.controller.meta b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/Base.controller.meta new file mode 100644 index 00000000..341aa8e6 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/Base.controller.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 91f184d4fc3ff1f49afdd24f69e085f0 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 9100000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/BaseController.prefab b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/BaseController.prefab new file mode 100644 index 00000000..7db74c21 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/BaseController.prefab @@ -0,0 +1,355 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &1975778578549000366 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 4037328974728300479} + - component: {fileID: 8340461531591696378} + - component: {fileID: 2421927005531568573} + m_Layer: 0 + m_Name: BaseController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &4037328974728300479 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1975778578549000366} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.6884441, y: 1.1147345, z: -4.914471} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 5025133549234519620} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8340461531591696378 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1975778578549000366} + 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} + 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: 1 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 2 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 3 + 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: 9100000, guid: 22f4686ec8638e243854be6fccb38820, + type: 2} + mask: {fileID: 0} + isDefault: 0 + 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 &2421927005531568573 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 1975778578549000366} + 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 &8808987784815288588 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 5025133549234519620} + - component: {fileID: 6108217815717348193} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &5025133549234519620 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8808987784815288588} + 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_Children: [] + m_Father: {fileID: 4037328974728300479} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &6108217815717348193 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8808987784815288588} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a5bf908a199a4648845ebe2fd3b5a4bd, type: 3} + m_Name: + m_EditorClassIdentifier: diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/BaseController.prefab.meta b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/BaseController.prefab.meta new file mode 100644 index 00000000..313d3bca --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/BaseController.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: b683b373cd0e4154d8bd69440fc8ab08 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/MergedController.prefab b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/MergedController.prefab new file mode 100644 index 00000000..416153b7 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/MergedController.prefab @@ -0,0 +1,373 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &521542568012153140 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 2616869947308232229} + - component: {fileID: 8063907918941263456} + - component: {fileID: 4452914144664039463} + m_Layer: 0 + m_Name: MergedController + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &2616869947308232229 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 521542568012153140} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: -1.6884441, y: 1.1147345, z: -4.914471} + m_LocalScale: {x: 1, y: 1, z: 1} + m_Children: + - {fileID: 6479369535091914718} + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8063907918941263456 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 521542568012153140} + 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} + 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: 1 + baseAnimationLayers: + - isEnabled: 0 + type: 0 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 2 + animatorController: {fileID: 0} + mask: {fileID: 0} + isDefault: 1 + - isEnabled: 0 + type: 3 + 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: 9100000, guid: 91f184d4fc3ff1f49afdd24f69e085f0, + type: 2} + mask: {fileID: 0} + isDefault: 0 + 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 &4452914144664039463 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 521542568012153140} + 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 &7379231148671166614 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6479369535091914718} + - component: {fileID: 5229589187063892731} + - component: {fileID: 1179508555950567543} + m_Layer: 0 + m_Name: GameObject + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6479369535091914718 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7379231148671166614} + 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_Children: [] + m_Father: {fileID: 2616869947308232229} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &5229589187063892731 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7379231148671166614} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: a5bf908a199a4648845ebe2fd3b5a4bd, type: 3} + m_Name: + m_EditorClassIdentifier: +--- !u!114 &1179508555950567543 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 7379231148671166614} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: 1bb122659f724ebf85fe095ac02dc339, type: 3} + m_Name: + m_EditorClassIdentifier: + animator: {fileID: 9100000, guid: 22f4686ec8638e243854be6fccb38820, type: 2} + layerType: 5 + deleteAttachedAnimator: 0 + pathMode: 0 + matchAvatarWriteDefaults: 0 diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/MergedController.prefab.meta b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/MergedController.prefab.meta new file mode 100644 index 00000000..5995545d --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/MergedController.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 9f7d2c5ec9d8b8b458db8f3982ad86bc +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/SyncedLayerHandling.cs b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/SyncedLayerHandling.cs new file mode 100644 index 00000000..417512ca --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/SyncedLayerHandling.cs @@ -0,0 +1,97 @@ +using nadena.dev.modular_avatar.core.editor; +using NUnit.Framework; +using VRC.SDK3.Avatars.Components; + +namespace modular_avatar_tests.SyncedLayerHandling +{ + public class SyncedLayerHandling : TestBase + { + [Test] + public void WhenSyncedLayerIsOnBaseController_SyncedConfigIsPreserved() + { + var prefab = CreatePrefab("BaseController.prefab"); + AvatarProcessor.ProcessAvatar(prefab); + + var mainLayer = findFxLayer(prefab, "main"); + var syncLayer = findFxLayer(prefab, "sync"); + + Assert.AreEqual(1, syncLayer.syncedLayerIndex); + + var m1State = FindStateInLayer(mainLayer, "m1"); + var m2State = FindStateInLayer(mainLayer, "m2"); + + var m1Override = syncLayer.GetOverrideMotion(m1State); + var m2Override = syncLayer.GetOverrideMotion(m2State); + + Assert.True(m1State.motion.name.Contains("m1")); + Assert.True(m2State.motion.name.Contains("m2")); + Assert.True(m1Override.name.Contains("m3")); + Assert.True(m2Override.name.Contains("m4")); + } + + [Test] + public void WhenSyncedLayerIsOnMergedController_SyncedConfigIsPreserved() + { + var prefab = CreatePrefab("MergedController.prefab"); + AvatarProcessor.ProcessAvatar(prefab); + + var mainLayer = findFxLayer(prefab, "main"); + var syncLayer = findFxLayer(prefab, "sync"); + + Assert.AreEqual(2, syncLayer.syncedLayerIndex); + + var m1State = FindStateInLayer(mainLayer, "m1"); + var m2State = FindStateInLayer(mainLayer, "m2"); + + var m1Override = syncLayer.GetOverrideMotion(m1State); + var m2Override = syncLayer.GetOverrideMotion(m2State); + + Assert.True(m1State.motion.name.Contains("m1")); + Assert.True(m2State.motion.name.Contains("m2")); + Assert.True(m1Override.name.Contains("m3")); + Assert.True(m2Override.name.Contains("m4")); + } + + [Test] + public void WhenSyncedLayerIsOnBaseController_LayerControlBehaviorsArePreserved() + { + var prefab = CreatePrefab("BaseController.prefab"); + AvatarProcessor.ProcessAvatar(prefab); + + var mainLayer = findFxLayer(prefab, "main"); + var syncLayer = findFxLayer(prefab, "sync"); + + Assert.AreEqual(1, syncLayer.syncedLayerIndex); + + var m1State = FindStateInLayer(mainLayer, "m1"); + var overrides = syncLayer.GetOverrideBehaviours(m1State); + Assert.AreEqual(1, overrides.Length); + + var layercontrol = overrides[0] as VRCAnimatorLayerControl; + Assert.NotNull(layercontrol); + + Assert.AreEqual(1, layercontrol.layer); + } + + [Test] + public void WhenSyncedLayerIsOnMergedController_LayerControlBehaviorsAreAdjusted() + { + var prefab = CreatePrefab("MergedController.prefab"); + AvatarProcessor.ProcessAvatar(prefab); + + var mainLayer = findFxLayer(prefab, "main"); + var syncLayer = findFxLayer(prefab, "sync"); + + Assert.AreEqual(2, syncLayer.syncedLayerIndex); + + var m1State = FindStateInLayer(mainLayer, "m1"); + var overrides = syncLayer.GetOverrideBehaviours(m1State); + Assert.AreEqual(1, overrides.Length); + + var layercontrol = overrides[0] as VRCAnimatorLayerControl; + Assert.NotNull(layercontrol); + + Assert.AreEqual(2, layercontrol.layer); + } + } +} \ No newline at end of file diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/SyncedLayerHandling.cs.meta b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/SyncedLayerHandling.cs.meta new file mode 100644 index 00000000..9eeababf --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/SyncedLayerHandling.cs.meta @@ -0,0 +1,3 @@ +fileFormatVersion: 2 +guid: 991954327b9a49c2b87529cd049a4394 +timeCreated: 1674820132 \ No newline at end of file diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m1.anim b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m1.anim new file mode 100644 index 00000000..70a4dc2f --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m1.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: m1 + serializedVersion: 6 + 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/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m1.anim.meta b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m1.anim.meta new file mode 100644 index 00000000..20f60e7d --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m1.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 462fc0905374b744fb7a4ca1110e9c84 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m2.anim b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m2.anim new file mode 100644 index 00000000..931ae8e4 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m2.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: m2 + serializedVersion: 6 + 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/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m2.anim.meta b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m2.anim.meta new file mode 100644 index 00000000..cc2f71a0 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m2.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 7104638764aea2b4682734684ce18d68 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m3.anim b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m3.anim new file mode 100644 index 00000000..eca15c22 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m3.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: m3 + serializedVersion: 6 + 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/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m3.anim.meta b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m3.anim.meta new file mode 100644 index 00000000..5e8e7b76 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m3.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: bf660ccc19e7d6e45849be7bdb273645 +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m4.anim b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m4.anim new file mode 100644 index 00000000..084e6568 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m4.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: m4 + serializedVersion: 6 + 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/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m4.anim.meta b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m4.anim.meta new file mode 100644 index 00000000..483578b9 --- /dev/null +++ b/Assets/_ModularAvatar/EditModeTests/SyncedLayerHandling/m4.anim.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b4473bdae48543347999d599bcef9efc +NativeFormatImporter: + externalObjects: {} + mainObjectFileID: 7400000 + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/_ModularAvatar/EditModeTests/TestBase.cs b/Assets/_ModularAvatar/EditModeTests/TestBase.cs index 88fe1d61..bb20d435 100644 --- a/Assets/_ModularAvatar/EditModeTests/TestBase.cs +++ b/Assets/_ModularAvatar/EditModeTests/TestBase.cs @@ -73,6 +73,16 @@ namespace modular_avatar_tests return motion; } + protected static AnimatorState FindStateInLayer(AnimatorControllerLayer layer, string stateName) + { + foreach (var state in layer.stateMachine.states) + { + if (state.state.name == stateName) return state.state; + } + + return null; + } + protected static AnimatorControllerLayer findFxLayer(GameObject prefab, string layerName) { var fx = prefab.GetComponent().baseAnimationLayers diff --git a/Packages/nadena.dev.modular-avatar/Editor/AnimatorMerger.cs b/Packages/nadena.dev.modular-avatar/Editor/AnimatorMerger.cs index 03bb732f..2710d184 100644 --- a/Packages/nadena.dev.modular-avatar/Editor/AnimatorMerger.cs +++ b/Packages/nadena.dev.modular-avatar/Editor/AnimatorMerger.cs @@ -50,6 +50,8 @@ namespace nadena.dev.modular_avatar.core.editor private Dictionary, AnimatorStateMachine> _stateMachines = new Dictionary, AnimatorStateMachine>(); + private Dictionary _cloneMap; + private int controllerBaseLayer = 0; public AnimatorCombiner(BuildContext context) @@ -67,6 +69,7 @@ namespace nadena.dev.modular_avatar.core.editor public void AddController(string basePath, AnimatorController controller, bool? writeDefaults) { controllerBaseLayer = _layers.Count; + _cloneMap = new Dictionary(); foreach (var param in controller.parameters) { @@ -85,9 +88,10 @@ namespace nadena.dev.modular_avatar.core.editor } bool first = true; - foreach (var layer in controller.layers) + var layers = controller.layers; + foreach (var layer in layers) { - insertLayer(basePath, layer, first, writeDefaults); + insertLayer(basePath, layer, first, writeDefaults, layers); first = false; } } @@ -108,7 +112,13 @@ namespace nadena.dev.modular_avatar.core.editor } } - private void insertLayer(string basePath, AnimatorControllerLayer layer, bool first, bool? writeDefaults) + private void insertLayer( + string basePath, + AnimatorControllerLayer layer, + bool first, + bool? writeDefaults, + AnimatorControllerLayer[] layers + ) { var newLayer = new AnimatorControllerLayer() { @@ -116,17 +126,81 @@ namespace nadena.dev.modular_avatar.core.editor avatarMask = layer.avatarMask, // TODO map transforms blendingMode = layer.blendingMode, defaultWeight = first ? 1 : layer.defaultWeight, - syncedLayerIndex = layer.syncedLayerIndex, // TODO - syncedLayerAffectsTiming = layer.syncedLayerAffectsTiming, // TODO + syncedLayerIndex = layer.syncedLayerIndex, + syncedLayerAffectsTiming = layer.syncedLayerAffectsTiming, iKPass = layer.iKPass, stateMachine = mapStateMachine(basePath, layer.stateMachine), }; UpdateWriteDefaults(newLayer.stateMachine, writeDefaults); + if (newLayer.syncedLayerIndex != -1 && newLayer.syncedLayerIndex >= 0 && + newLayer.syncedLayerIndex < layers.Length) + { + // Transfer any motion overrides onto the new synced layer + var baseLayer = layers[newLayer.syncedLayerIndex]; + foreach (var state in WalkAllStates(baseLayer.stateMachine)) + { + var overrideMotion = layer.GetOverrideMotion(state); + if (overrideMotion != null) + { + newLayer.SetOverrideMotion((AnimatorState) _cloneMap[state], overrideMotion); + } + + var overrideBehaviors = (StateMachineBehaviour[]) layer.GetOverrideBehaviours(state)?.Clone(); + if (overrideBehaviors != null) + { + for (int i = 0; i < overrideBehaviors.Length; i++) + { + overrideBehaviors[i] = deepClone(overrideBehaviors[i], x => x, + new Dictionary()); + AdjustBehavior(overrideBehaviors[i]); + } + + newLayer.SetOverrideBehaviours((AnimatorState) _cloneMap[state], overrideBehaviors); + } + } + + newLayer.syncedLayerIndex += controllerBaseLayer; + } + _layers.Add(newLayer); } + IEnumerable WalkAllStates(AnimatorStateMachine animatorStateMachine) + { + HashSet visited = new HashSet(); + + foreach (var state in VisitStateMachine(animatorStateMachine)) + { + yield return state; + } + + IEnumerable VisitStateMachine(AnimatorStateMachine layerStateMachine) + { + if (!visited.Add(layerStateMachine)) yield break; + + foreach (var state in layerStateMachine.states) + { + if (state.state == null) continue; + + yield return state.state; + } + + foreach (var child in layerStateMachine.stateMachines) + { + if (child.stateMachine == null) continue; + + if (visited.Contains(child.stateMachine)) continue; + visited.Add(child.stateMachine); + foreach (var state in VisitStateMachine(child.stateMachine)) + { + yield return state; + } + } + } + } + private void UpdateWriteDefaults(AnimatorStateMachine stateMachine, bool? writeDefaults) { if (!writeDefaults.HasValue) return; @@ -157,22 +231,13 @@ namespace nadena.dev.modular_avatar.core.editor return asm; } - asm = deepClone(layerStateMachine, (obj) => customClone(obj, basePath)); + asm = deepClone(layerStateMachine, (obj) => customClone(obj, basePath), _cloneMap); - foreach (var state in asm.states) + foreach (var state in WalkAllStates(asm)) { - foreach (var behavior in state.state.behaviours) + foreach (var behavior in state.behaviours) { - switch (behavior) - { - case VRCAnimatorLayerControl layerControl: - { - // TODO - need to figure out how to handle cross-layer references. For now this will handle - // intra-animator cases. - layerControl.layer += controllerBaseLayer; - break; - } - } + AdjustBehavior(behavior); } } @@ -180,6 +245,20 @@ namespace nadena.dev.modular_avatar.core.editor return asm; } + private void AdjustBehavior(StateMachineBehaviour behavior) + { + switch (behavior) + { + case VRCAnimatorLayerControl layerControl: + { + // TODO - need to figure out how to handle cross-layer references. For now this will handle + // intra-animator cases. + layerControl.layer += controllerBaseLayer; + break; + } + } + } + private static string MapPath(EditorCurveBinding binding, string basePath) { if (binding.type == typeof(Animator) && binding.path == "") @@ -244,7 +323,7 @@ namespace nadena.dev.modular_avatar.core.editor private T deepClone(T original, Func visitor, - Dictionary cloneMap = null + Dictionary cloneMap ) where T : Object { if (original == null) return null; @@ -288,8 +367,6 @@ namespace nadena.dev.modular_avatar.core.editor } } - if (cloneMap == null) cloneMap = new Dictionary(); - if (cloneMap.ContainsKey(original)) { return (T) cloneMap[original];