mirror of
https://github.com/bdunderscore/modular-avatar.git
synced 2024-12-29 02:35:06 +08:00
Move animation utility APIs back to Modular Avatar for now
This commit is contained in:
parent
0669c01a91
commit
90806cb300
8
Assets/_ModularAvatar/EditModeTests/Animation.meta
Normal file
8
Assets/_ModularAvatar/EditModeTests/Animation.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b58e8719fe4803c42a95ea6a8f8e3108
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
178
Assets/_ModularAvatar/EditModeTests/Animation/AnimationClip.anim
Normal file
178
Assets/_ModularAvatar/EditModeTests/Animation/AnimationClip.anim
Normal file
@ -0,0 +1,178 @@
|
||||
%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: AnimationClip
|
||||
serializedVersion: 6
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 1
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: {x: 0, y: 1, z: 0}
|
||||
inSlope: {x: 0, y: 0, z: 0}
|
||||
outSlope: {x: 0, y: 0, z: 0}
|
||||
tangentMode: 0
|
||||
weightedMode: 0
|
||||
inWeight: {x: 0, y: 0.33333334, z: 0.33333334}
|
||||
outWeight: {x: 0, y: 0.33333334, z: 0.33333334}
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
path: parent/child
|
||||
m_ScaleCurves: []
|
||||
m_FloatCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_IsTrigger
|
||||
path: parent/child
|
||||
classID: 65
|
||||
script: {fileID: 0}
|
||||
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: 3852520779
|
||||
attribute: 2693561734
|
||||
script: {fileID: 0}
|
||||
typeID: 65
|
||||
customType: 0
|
||||
isPPtrCurve: 0
|
||||
- serializedVersion: 2
|
||||
path: 3852520779
|
||||
attribute: 1
|
||||
script: {fileID: 0}
|
||||
typeID: 4
|
||||
customType: 0
|
||||
isPPtrCurve: 0
|
||||
pptrCurveMapping: []
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 0
|
||||
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:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_LocalPosition.x
|
||||
path: parent/child
|
||||
classID: 4
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_LocalPosition.y
|
||||
path: parent/child
|
||||
classID: 4
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 0
|
||||
inSlope: 0
|
||||
outSlope: 0
|
||||
tangentMode: 136
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_LocalPosition.z
|
||||
path: parent/child
|
||||
classID: 4
|
||||
script: {fileID: 0}
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_IsTrigger
|
||||
path: parent/child
|
||||
classID: 65
|
||||
script: {fileID: 0}
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events: []
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5977900ad3e56e442bc83e80a14ff2c4
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,399 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &271914551725279345
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 3577530327576854121}
|
||||
- component: {fileID: 6327882964168735651}
|
||||
m_Layer: 0
|
||||
m_Name: child
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &3577530327576854121
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 271914551725279345}
|
||||
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: 745080012075344352}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!65 &6327882964168735651
|
||||
BoxCollider:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 271914551725279345}
|
||||
m_Material: {fileID: 0}
|
||||
m_IsTrigger: 0
|
||||
m_Enabled: 1
|
||||
serializedVersion: 2
|
||||
m_Size: {x: 1, y: 1, z: 1}
|
||||
m_Center: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &3009138964498208574
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 6202426740457961026}
|
||||
- component: {fileID: 1135328136970846733}
|
||||
- component: {fileID: 3344975340744285616}
|
||||
- component: {fileID: 1383493159385676019}
|
||||
m_Layer: 0
|
||||
m_Name: BasicObjectReferenceTest
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &6202426740457961026
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3009138964498208574}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -1.3337704, y: 0.13635278, z: 1.4326048}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children:
|
||||
- {fileID: 745080012075344352}
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!95 &1135328136970846733
|
||||
Animator:
|
||||
serializedVersion: 3
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3009138964498208574}
|
||||
m_Enabled: 1
|
||||
m_Avatar: {fileID: 0}
|
||||
m_Controller: {fileID: 0}
|
||||
m_CullingMode: 0
|
||||
m_UpdateMode: 0
|
||||
m_ApplyRootMotion: 0
|
||||
m_LinearVelocityBlending: 0
|
||||
m_WarningMessage:
|
||||
m_HasTransformHierarchy: 1
|
||||
m_AllowConstantClipSamplingOptimization: 1
|
||||
m_KeepAnimatorControllerStateOnDisable: 0
|
||||
--- !u!114 &3344975340744285616
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3009138964498208574}
|
||||
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: 1
|
||||
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: 9100000, guid: 54530ed85eedf574487742e93f56ba26,
|
||||
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: 9100000, guid: 54530ed85eedf574487742e93f56ba26,
|
||||
type: 2}
|
||||
mask: {fileID: 0}
|
||||
isDefault: 0
|
||||
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 &1383493159385676019
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 3009138964498208574}
|
||||
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 &6481973405510051602
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 745080012075344352}
|
||||
m_Layer: 0
|
||||
m_Name: parent
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &745080012075344352
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6481973405510051602}
|
||||
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:
|
||||
- {fileID: 3577530327576854121}
|
||||
m_Father: {fileID: 6202426740457961026}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 672a59e472adcc944a5a04cd1400d49b
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
98
Assets/_ModularAvatar/EditModeTests/Animation/HQ_OFF.anim
Normal file
98
Assets/_ModularAvatar/EditModeTests/Animation/HQ_OFF.anim
Normal file
@ -0,0 +1,98 @@
|
||||
%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: HQ_OFF
|
||||
serializedVersion: 6
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 0
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves: []
|
||||
m_ScaleCurves: []
|
||||
m_FloatCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_Enabled
|
||||
path:
|
||||
classID: 114
|
||||
script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
|
||||
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: 3305885265
|
||||
script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
|
||||
typeID: 114
|
||||
customType: 24
|
||||
isPPtrCurve: 0
|
||||
pptrCurveMapping: []
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 0
|
||||
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:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_Enabled
|
||||
path:
|
||||
classID: 114
|
||||
script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events: []
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2d16d7af2be036d4e9867b4314772f65
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
98
Assets/_ModularAvatar/EditModeTests/Animation/HQ_ON.anim
Normal file
98
Assets/_ModularAvatar/EditModeTests/Animation/HQ_ON.anim
Normal file
@ -0,0 +1,98 @@
|
||||
%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: HQ_ON
|
||||
serializedVersion: 6
|
||||
m_Legacy: 0
|
||||
m_Compressed: 0
|
||||
m_UseHighQualityCurve: 1
|
||||
m_RotationCurves: []
|
||||
m_CompressedRotationCurves: []
|
||||
m_EulerCurves: []
|
||||
m_PositionCurves: []
|
||||
m_ScaleCurves: []
|
||||
m_FloatCurves:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_Enabled
|
||||
path:
|
||||
classID: 114
|
||||
script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
|
||||
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: 3305885265
|
||||
script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
|
||||
typeID: 114
|
||||
customType: 24
|
||||
isPPtrCurve: 0
|
||||
pptrCurveMapping: []
|
||||
m_AnimationClipSettings:
|
||||
serializedVersion: 2
|
||||
m_AdditiveReferencePoseClip: {fileID: 0}
|
||||
m_AdditiveReferencePoseTime: 0
|
||||
m_StartTime: 0
|
||||
m_StopTime: 0
|
||||
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:
|
||||
- curve:
|
||||
serializedVersion: 2
|
||||
m_Curve:
|
||||
- serializedVersion: 3
|
||||
time: 0
|
||||
value: 1
|
||||
inSlope: Infinity
|
||||
outSlope: Infinity
|
||||
tangentMode: 103
|
||||
weightedMode: 0
|
||||
inWeight: 0
|
||||
outWeight: 0
|
||||
m_PreInfinity: 2
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
attribute: m_Enabled
|
||||
path:
|
||||
classID: 114
|
||||
script: {fileID: -1427037861, guid: 4ecd63eff847044b68db9453ce219299, type: 3}
|
||||
m_EulerEditorCurves: []
|
||||
m_HasGenericRootTransform: 0
|
||||
m_HasMotionFloatCurves: 0
|
||||
m_Events: []
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c2179264a332d7e4395b50fd2babf946
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 7400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,101 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1102 &-1614219900459257297
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: HQ_ON
|
||||
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: c2179264a332d7e4395b50fd2babf946, 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: HighQualityCurvesSettingPreserved
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters: []
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
m_StateMachine: {fileID: 5829098483273298939}
|
||||
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 &2527618587943162634
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: HQ_OFF
|
||||
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: 2d16d7af2be036d4e9867b4314772f65, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
||||
--- !u!1107 &5829098483273298939
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Base Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 2527618587943162634}
|
||||
m_Position: {x: 314, y: 287, z: 0}
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: -1614219900459257297}
|
||||
m_Position: {x: 538, y: 388, 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: 2527618587943162634}
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3fabb6b36a3a1d84f9568e3fc9b9eb2a
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,322 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!1 &1779618317021452234
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 1779618317021451318}
|
||||
- component: {fileID: 1779618317021451317}
|
||||
- component: {fileID: 1779618317021451316}
|
||||
- component: {fileID: 1779618317021452235}
|
||||
m_Layer: 0
|
||||
m_Name: HighQualityCurvesSettingPreserved
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!4 &1779618317021451318
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1779618317021452234}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: -0.11551872, y: 0.23841906, z: -2.698598}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_RootOrder: 0
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &1779618317021451317
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1779618317021452234}
|
||||
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: 1
|
||||
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: 9100000, guid: 3fabb6b36a3a1d84f9568e3fc9b9eb2a,
|
||||
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 &1779618317021451316
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1779618317021452234}
|
||||
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!95 &1779618317021452235
|
||||
Animator:
|
||||
serializedVersion: 3
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1779618317021452234}
|
||||
m_Enabled: 1
|
||||
m_Avatar: {fileID: 0}
|
||||
m_Controller: {fileID: 0}
|
||||
m_CullingMode: 0
|
||||
m_UpdateMode: 0
|
||||
m_ApplyRootMotion: 0
|
||||
m_LinearVelocityBlending: 0
|
||||
m_WarningMessage:
|
||||
m_HasTransformHierarchy: 1
|
||||
m_AllowConstantClipSamplingOptimization: 1
|
||||
m_KeepAnimatorControllerStateOnDisable: 0
|
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3acbcc5c8c5020d49a58371ffdbe6b5d
|
||||
PrefabImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,27 @@
|
||||
using nadena.dev.ndmf;
|
||||
using nadena.dev.ndmf.animation;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
|
||||
namespace modular_avatar_tests
|
||||
{
|
||||
public class MiscAnimationTests : TestBase
|
||||
{
|
||||
[Test]
|
||||
public void HighQualityCurvesSettingPreserved()
|
||||
{
|
||||
var prefab = CreatePrefab("HighQualityCurvesSettingPreserved.prefab");
|
||||
var context = new BuildContext(prefab, null);
|
||||
context.ActivateExtensionContext<TrackObjectRenamesContext>();
|
||||
context.DeactivateExtensionContext<TrackObjectRenamesContext>();
|
||||
|
||||
var layer = findFxLayer(prefab, "Base Layer");
|
||||
|
||||
var hq_on = FindStateInLayer(layer, "HQ_ON");
|
||||
var hq_off = FindStateInLayer(layer, "HQ_OFF");
|
||||
|
||||
Assert.True(new SerializedObject(hq_on.motion).FindProperty("m_UseHighQualityCurve").boolValue);
|
||||
Assert.False(new SerializedObject(hq_off.motion).FindProperty("m_UseHighQualityCurve").boolValue);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25fb1ff7b4e425c4ba9d13f0dcc6cfaa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,72 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!91 &9100000
|
||||
AnimatorController:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: ReferencesObject
|
||||
serializedVersion: 5
|
||||
m_AnimatorParameters: []
|
||||
m_AnimatorLayers:
|
||||
- serializedVersion: 5
|
||||
m_Name: Base Layer
|
||||
m_StateMachine: {fileID: 5545365013827754013}
|
||||
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 &5545365013827754013
|
||||
AnimatorStateMachine:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Base Layer
|
||||
m_ChildStates:
|
||||
- serializedVersion: 1
|
||||
m_State: {fileID: 7237879935735861366}
|
||||
m_Position: {x: 340, 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: 7237879935735861366}
|
||||
--- !u!1102 &7237879935735861366
|
||||
AnimatorState:
|
||||
serializedVersion: 6
|
||||
m_ObjectHideFlags: 1
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: AnimationClip
|
||||
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: 5977900ad3e56e442bc83e80a14ff2c4, type: 2}
|
||||
m_Tag:
|
||||
m_SpeedParameter:
|
||||
m_MirrorParameter:
|
||||
m_CycleOffsetParameter:
|
||||
m_TimeParameter:
|
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 54530ed85eedf574487742e93f56ba26
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 9100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,147 @@
|
||||
using System.Linq;
|
||||
using nadena.dev.ndmf.animation;
|
||||
using NUnit.Framework;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
|
||||
namespace modular_avatar_tests
|
||||
{
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
public class TrackObjectRenamesContextTests : TestBase
|
||||
{
|
||||
[Test]
|
||||
public void testBasicContextInitialization()
|
||||
{
|
||||
var av = CreateRoot("root");
|
||||
|
||||
var bc = CreateContext(av);
|
||||
var toc = new TrackObjectRenamesContext();
|
||||
|
||||
toc.OnActivate(bc);
|
||||
toc.OnDeactivate(bc);
|
||||
}
|
||||
|
||||
|
||||
[Test]
|
||||
public void TracksSimpleRenames()
|
||||
{
|
||||
var root = CreateRoot("root");
|
||||
var a = CreateChild(root, "a");
|
||||
|
||||
var toc = new TrackObjectRenamesContext();
|
||||
toc.OnActivate(CreateContext(root));
|
||||
Assert.AreEqual("a", toc.MapPath("a"));
|
||||
a.name = "b";
|
||||
toc.ClearCache();
|
||||
Assert.AreEqual("b", toc.MapPath("a"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TracksObjectMoves()
|
||||
{
|
||||
var root = CreateRoot("root");
|
||||
var a = CreateChild(root, "a");
|
||||
var b = CreateChild(root, "b");
|
||||
|
||||
var toc = new TrackObjectRenamesContext();
|
||||
toc.OnActivate(CreateContext(root));
|
||||
|
||||
Assert.AreEqual("a", toc.MapPath("a"));
|
||||
a.transform.parent = b.transform;
|
||||
toc.ClearCache();
|
||||
Assert.AreEqual("b/a", toc.MapPath("a"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TracksCollapses()
|
||||
{
|
||||
var root = CreateRoot("root");
|
||||
var a = CreateChild(root, "a");
|
||||
var b = CreateChild(a, "b");
|
||||
var c = CreateChild(b, "c");
|
||||
|
||||
var toc = new TrackObjectRenamesContext();
|
||||
toc.OnActivate(CreateContext(root));
|
||||
|
||||
toc.MarkRemoved(b);
|
||||
c.transform.parent = a.transform;
|
||||
UnityObject.DestroyImmediate(b);
|
||||
|
||||
Assert.AreEqual("a/c", toc.MapPath("a/b/c"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TransformLookthrough()
|
||||
{
|
||||
var root = CreateRoot("root");
|
||||
var a = CreateChild(root, "a");
|
||||
var b = CreateChild(a, "b");
|
||||
var c = CreateChild(b, "c");
|
||||
var d = CreateChild(c, "d");
|
||||
|
||||
var toc = new TrackObjectRenamesContext();
|
||||
toc.OnActivate(CreateContext(root));
|
||||
|
||||
toc.MarkTransformLookthrough(b);
|
||||
toc.MarkTransformLookthrough(c);
|
||||
Assert.AreEqual("a/b/c", toc.MapPath("a/b/c"));
|
||||
Assert.AreEqual("a", toc.MapPath("a/b/c", true));
|
||||
Assert.AreEqual("a/b/c/d", toc.MapPath("a/b/c/d", true));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAnimatorControllerUpdates()
|
||||
{
|
||||
var root = CreatePrefab("BasicObjectReferenceTest.prefab");
|
||||
var parent = root.transform.Find("parent").gameObject;
|
||||
var child = parent.transform.Find("child").gameObject;
|
||||
|
||||
var descriptor = root.GetComponent<VRCAvatarDescriptor>();
|
||||
var oldFx = descriptor.baseAnimationLayers.First(l =>
|
||||
l.type == VRCAvatarDescriptor.AnimLayerType.FX);
|
||||
var oldIk = descriptor.specialAnimationLayers.First(l =>
|
||||
l.type == VRCAvatarDescriptor.AnimLayerType.IKPose);
|
||||
|
||||
var toc = new TrackObjectRenamesContext();
|
||||
var buildContext = CreateContext(root);
|
||||
toc.OnActivate(buildContext);
|
||||
toc.MarkTransformLookthrough(child);
|
||||
|
||||
parent.name = "p2";
|
||||
|
||||
toc.OnDeactivate(buildContext);
|
||||
|
||||
var newFx = buildContext.AvatarDescriptor.baseAnimationLayers.First(l =>
|
||||
l.type == VRCAvatarDescriptor.AnimLayerType.FX);
|
||||
var newIk = buildContext.AvatarDescriptor.specialAnimationLayers.First(l =>
|
||||
l.type == VRCAvatarDescriptor.AnimLayerType.IKPose);
|
||||
|
||||
Assert.AreNotEqual(oldFx.animatorController, newFx.animatorController);
|
||||
Assert.AreNotEqual(oldIk.animatorController, newIk.animatorController);
|
||||
|
||||
CheckClips(newFx.animatorController as AnimatorController);
|
||||
CheckClips(newIk.animatorController as AnimatorController);
|
||||
|
||||
void CheckClips(AnimatorController controller)
|
||||
{
|
||||
var clip = controller.layers[0].stateMachine.states[0].state.motion
|
||||
as AnimationClip;
|
||||
|
||||
foreach (var binding in AnimationUtility.GetCurveBindings(clip))
|
||||
{
|
||||
if (binding.type == typeof(Transform))
|
||||
{
|
||||
Assert.AreEqual("p2", binding.path);
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.AreEqual("p2/child", binding.path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e71c9edfe1c94c5c93603ce45a1e2310
|
||||
timeCreated: 1692516261
|
@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using nadena.dev.modular_avatar.core.editor;
|
||||
using nadena.dev.modular_avatar.editor.ErrorReporting;
|
||||
@ -12,12 +13,29 @@ namespace modular_avatar_tests
|
||||
{
|
||||
public class TestBase
|
||||
{
|
||||
private const string TEMP_ASSET_PATH = "Assets/ZZZ_Temp";
|
||||
private static Dictionary<System.Type, string> _scriptToDirectory = null;
|
||||
|
||||
private List<GameObject> objects;
|
||||
private const string MinimalAvatarGuid = "60d3416d1f6af4a47bf9056aefc38333";
|
||||
|
||||
[SetUp]
|
||||
public virtual void Setup()
|
||||
{
|
||||
if (_scriptToDirectory == null)
|
||||
{
|
||||
_scriptToDirectory = new Dictionary<System.Type, string>();
|
||||
foreach (var guid in AssetDatabase.FindAssets("t:MonoScript", new string[] {"Assets/_ModularAvatar"}))
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(guid);
|
||||
var obj = AssetDatabase.LoadAssetAtPath<MonoScript>(path);
|
||||
if (obj != null && obj.GetClass() != null)
|
||||
{
|
||||
_scriptToDirectory.Add(obj.GetClass(), Path.GetDirectoryName(path));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BuildReport.Clear();
|
||||
objects = new List<GameObject>();
|
||||
}
|
||||
@ -33,6 +51,11 @@ namespace modular_avatar_tests
|
||||
Util.DeleteTemporaryAssets();
|
||||
}
|
||||
|
||||
protected nadena.dev.ndmf.BuildContext CreateContext(GameObject root)
|
||||
{
|
||||
return new nadena.dev.ndmf.BuildContext(root, TEMP_ASSET_PATH); // TODO - cleanup
|
||||
}
|
||||
|
||||
protected GameObject CreateRoot(string name)
|
||||
{
|
||||
var path = AssetDatabase.GUIDToAssetPath(MinimalAvatarGuid);
|
||||
@ -59,9 +82,10 @@ namespace modular_avatar_tests
|
||||
return go;
|
||||
}
|
||||
|
||||
|
||||
protected T LoadAsset<T>(string relPath) where T : UnityEngine.Object
|
||||
{
|
||||
var root = "Assets/_ModularAvatar/EditModeTests/" + GetType().Name + "/";
|
||||
var root = _scriptToDirectory[GetType()] + "/";
|
||||
var path = root + relPath;
|
||||
|
||||
var obj = AssetDatabase.LoadAssetAtPath<T>(path);
|
||||
@ -70,7 +94,6 @@ namespace modular_avatar_tests
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
protected static AnimationClip findFxClip(GameObject prefab, string layerName)
|
||||
{
|
||||
var motion = findFxMotion(prefab, layerName) as AnimationClip;
|
||||
|
8
Packages/nadena.dev.modular-avatar/Editor/Animation.meta
Normal file
8
Packages/nadena.dev.modular-avatar/Editor/Animation.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0985d0cf1a434879b3ec7e80a90bc598
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
@ -0,0 +1,212 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
|
||||
namespace nadena.dev.ndmf.animation
|
||||
{
|
||||
public static class AnimationUtil
|
||||
{
|
||||
private const string SAMPLE_PATH_PACKAGE =
|
||||
"Packages/com.vrchat.avatars/Samples/AV3 Demo Assets/Animation/Controllers";
|
||||
|
||||
private const string SAMPLE_PATH_LEGACY = "Assets/VRCSDK/Examples3/Animation/Controllers";
|
||||
|
||||
private const string GUID_GESTURE_HANDSONLY_MASK = "b2b8bad9583e56a46a3e21795e96ad92";
|
||||
|
||||
|
||||
public static AnimatorController DeepCloneAnimator(BuildContext context, RuntimeAnimatorController controller)
|
||||
{
|
||||
if (controller == null) return null;
|
||||
|
||||
var merger = new AnimatorCombiner(controller.name + " (clone)", context.AssetContainer);
|
||||
switch (controller)
|
||||
{
|
||||
case AnimatorController ac:
|
||||
merger.AddController("", ac, null);
|
||||
break;
|
||||
case AnimatorOverrideController oac:
|
||||
merger.AddOverrideController("", oac, null);
|
||||
break;
|
||||
default:
|
||||
throw new Exception("Unknown RuntimeAnimatorContoller type " + controller.GetType());
|
||||
}
|
||||
|
||||
return merger.Finish();
|
||||
}
|
||||
|
||||
internal static void CloneAllControllers(BuildContext context)
|
||||
{
|
||||
// Ensure all of the controllers on the avatar descriptor point to temporary assets.
|
||||
// This helps reduce the risk that we'll accidentally modify the original assets.
|
||||
|
||||
context.AvatarDescriptor.baseAnimationLayers =
|
||||
CloneLayers(context, context.AvatarDescriptor.baseAnimationLayers);
|
||||
context.AvatarDescriptor.specialAnimationLayers =
|
||||
CloneLayers(context, context.AvatarDescriptor.specialAnimationLayers);
|
||||
}
|
||||
|
||||
private static VRCAvatarDescriptor.CustomAnimLayer[] CloneLayers(
|
||||
BuildContext context,
|
||||
VRCAvatarDescriptor.CustomAnimLayer[] layers
|
||||
)
|
||||
{
|
||||
if (layers == null) return null;
|
||||
|
||||
for (int i = 0; i < layers.Length; i++)
|
||||
{
|
||||
var layer = layers[i];
|
||||
if (layer.animatorController != null && !context.IsTemporaryAsset(layer.animatorController))
|
||||
{
|
||||
layer.animatorController = DeepCloneAnimator(context, layer.animatorController);
|
||||
}
|
||||
|
||||
layers[i] = layer;
|
||||
}
|
||||
|
||||
return layers;
|
||||
}
|
||||
|
||||
public static AnimatorController GetOrInitializeController(
|
||||
this BuildContext context,
|
||||
VRCAvatarDescriptor.AnimLayerType type)
|
||||
{
|
||||
return FindLayer(context.AvatarDescriptor.baseAnimationLayers)
|
||||
?? FindLayer(context.AvatarDescriptor.specialAnimationLayers);
|
||||
|
||||
AnimatorController FindLayer(VRCAvatarDescriptor.CustomAnimLayer[] layers)
|
||||
{
|
||||
for (int i = 0; i < layers.Length; i++)
|
||||
{
|
||||
var layer = layers[i];
|
||||
if (layer.type == type)
|
||||
{
|
||||
if (layer.animatorController == null || layer.isDefault)
|
||||
{
|
||||
layer.animatorController = ResolveLayerController(layer);
|
||||
if (type == VRCAvatarDescriptor.AnimLayerType.Gesture)
|
||||
{
|
||||
layer.mask = AssetDatabase.LoadAssetAtPath<AvatarMask>(
|
||||
AssetDatabase.GUIDToAssetPath(GUID_GESTURE_HANDSONLY_MASK)
|
||||
);
|
||||
}
|
||||
|
||||
layers[i] = layer;
|
||||
}
|
||||
|
||||
return layer.animatorController as AnimatorController;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static AnimatorController ResolveLayerController(VRCAvatarDescriptor.CustomAnimLayer layer)
|
||||
{
|
||||
AnimatorController controller = null;
|
||||
|
||||
if (!layer.isDefault && layer.animatorController != null &&
|
||||
layer.animatorController is AnimatorController c)
|
||||
{
|
||||
controller = c;
|
||||
}
|
||||
else
|
||||
{
|
||||
string name;
|
||||
switch (layer.type)
|
||||
{
|
||||
case VRCAvatarDescriptor.AnimLayerType.Action:
|
||||
name = "Action";
|
||||
break;
|
||||
case VRCAvatarDescriptor.AnimLayerType.Additive:
|
||||
name = "Idle";
|
||||
break;
|
||||
case VRCAvatarDescriptor.AnimLayerType.Base:
|
||||
name = "Locomotion";
|
||||
break;
|
||||
case VRCAvatarDescriptor.AnimLayerType.Gesture:
|
||||
name = "Hands";
|
||||
break;
|
||||
case VRCAvatarDescriptor.AnimLayerType.Sitting:
|
||||
name = "Sitting";
|
||||
break;
|
||||
case VRCAvatarDescriptor.AnimLayerType.FX:
|
||||
name = "Face";
|
||||
break;
|
||||
case VRCAvatarDescriptor.AnimLayerType.TPose:
|
||||
name = "UtilityTPose";
|
||||
break;
|
||||
case VRCAvatarDescriptor.AnimLayerType.IKPose:
|
||||
name = "UtilityIKPose";
|
||||
break;
|
||||
default:
|
||||
name = null;
|
||||
break;
|
||||
}
|
||||
|
||||
if (name != null)
|
||||
{
|
||||
name = "/vrc_AvatarV3" + name + "Layer.controller";
|
||||
|
||||
controller = AssetDatabase.LoadAssetAtPath<AnimatorController>(SAMPLE_PATH_PACKAGE + name);
|
||||
if (controller == null)
|
||||
{
|
||||
controller = AssetDatabase.LoadAssetAtPath<AnimatorController>(SAMPLE_PATH_LEGACY + name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return controller;
|
||||
}
|
||||
|
||||
public static bool IsProxyAnimation(this Motion m)
|
||||
{
|
||||
var path = AssetDatabase.GetAssetPath(m);
|
||||
|
||||
// This is a fairly wide condition in order to deal with:
|
||||
// 1. Future additions of proxy animations (so GUIDs are out)
|
||||
// 2. Unitypackage based installations of the VRCSDK
|
||||
// 3. VCC based installations of the VRCSDK
|
||||
// 4. Very old VCC based installations of the VRCSDK where proxy animations were copied into Assets
|
||||
return path.Contains("/AV3 Demo Assets/Animation/ProxyAnim/proxy")
|
||||
|| path.Contains("/VRCSDK/Examples3/Animation/ProxyAnim/proxy");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Enumerates all states in an animator controller
|
||||
/// </summary>
|
||||
/// <param name="ac"></param>
|
||||
/// <returns></returns>
|
||||
internal static IEnumerable<AnimatorState> States(AnimatorController ac)
|
||||
{
|
||||
HashSet<AnimatorStateMachine> visitedStateMachines = new HashSet<AnimatorStateMachine>();
|
||||
Queue<AnimatorStateMachine> pending = new Queue<AnimatorStateMachine>();
|
||||
|
||||
foreach (var layer in ac.layers)
|
||||
{
|
||||
if (layer.stateMachine != null) pending.Enqueue(layer.stateMachine);
|
||||
}
|
||||
|
||||
while (pending.Count > 0)
|
||||
{
|
||||
var next = pending.Dequeue();
|
||||
if (visitedStateMachines.Contains(next)) continue;
|
||||
visitedStateMachines.Add(next);
|
||||
|
||||
foreach (var child in next.stateMachines)
|
||||
{
|
||||
if (child.stateMachine != null) pending.Enqueue(child.stateMachine);
|
||||
}
|
||||
|
||||
foreach (var state in next.states)
|
||||
{
|
||||
yield return state.state;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0ef93cb5a6c4e46bb3318ae8116de77
|
||||
timeCreated: 1691238553
|
@ -0,0 +1,451 @@
|
||||
/*
|
||||
* MIT License
|
||||
*
|
||||
* Copyright (c) 2022-2023 bd_
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in all
|
||||
* copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using nadena.dev.ndmf.util;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace nadena.dev.ndmf.animation
|
||||
{
|
||||
public class AnimatorCombiner
|
||||
{
|
||||
private readonly AnimatorController _combined;
|
||||
private bool isSaved;
|
||||
|
||||
private AnimatorOverrideController _overrideController;
|
||||
|
||||
private List<AnimatorControllerLayer> _layers = new List<AnimatorControllerLayer>();
|
||||
|
||||
private Dictionary<String, AnimatorControllerParameter> _parameters =
|
||||
new Dictionary<string, AnimatorControllerParameter>();
|
||||
|
||||
private Dictionary<KeyValuePair<String, Motion>, Motion> _motions =
|
||||
new Dictionary<KeyValuePair<string, Motion>, Motion>();
|
||||
|
||||
private Dictionary<KeyValuePair<String, AnimatorStateMachine>, AnimatorStateMachine> _stateMachines =
|
||||
new Dictionary<KeyValuePair<string, AnimatorStateMachine>, AnimatorStateMachine>();
|
||||
|
||||
private Dictionary<Object, Object> _cloneMap;
|
||||
|
||||
private int controllerBaseLayer = 0;
|
||||
|
||||
public AnimatorCombiner(String assetName, UnityEngine.Object assetContainer)
|
||||
{
|
||||
_combined = new AnimatorController();
|
||||
if (assetContainer != null)
|
||||
{
|
||||
if (!EditorUtility.IsPersistent(assetContainer) ||
|
||||
string.IsNullOrEmpty(AssetDatabase.GetAssetPath(assetContainer)))
|
||||
{
|
||||
Debug.Log("Nonpersistent asset container: " + assetContainer.name);
|
||||
}
|
||||
else
|
||||
{
|
||||
AssetDatabase.AddObjectToAsset(_combined, assetContainer);
|
||||
}
|
||||
}
|
||||
|
||||
isSaved = assetContainer != null;
|
||||
_combined.name = assetName;
|
||||
}
|
||||
|
||||
public AnimatorController Finish()
|
||||
{
|
||||
_combined.parameters = _parameters.Values.ToArray();
|
||||
_combined.layers = _layers.ToArray();
|
||||
return _combined;
|
||||
}
|
||||
|
||||
public void AddController(string basePath, AnimatorController controller, bool? writeDefaults)
|
||||
{
|
||||
controllerBaseLayer = _layers.Count;
|
||||
_cloneMap = new Dictionary<Object, Object>();
|
||||
|
||||
foreach (var param in controller.parameters)
|
||||
{
|
||||
if (_parameters.TryGetValue(param.name, out var acp))
|
||||
{
|
||||
if (acp.type != param.type)
|
||||
{
|
||||
/*
|
||||
BuildReport.LogFatal("error.merge_animator.param_type_mismatch", new[]
|
||||
{
|
||||
param.name, acp.type.ToString(),
|
||||
param.type.ToString()
|
||||
});
|
||||
*/
|
||||
// TODO: Error reporting
|
||||
throw new Exception("Parameter type mismatch");
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
_parameters.Add(param.name, param);
|
||||
}
|
||||
|
||||
bool first = true;
|
||||
var layers = controller.layers;
|
||||
foreach (var layer in layers)
|
||||
{
|
||||
insertLayer(basePath, layer, first, writeDefaults, layers);
|
||||
first = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void AddOverrideController(string basePath, AnimatorOverrideController overrideController,
|
||||
bool? writeDefaults)
|
||||
{
|
||||
AnimatorController controller = overrideController.runtimeAnimatorController as AnimatorController;
|
||||
if (controller == null) return;
|
||||
_overrideController = overrideController;
|
||||
try
|
||||
{
|
||||
this.AddController(basePath, controller, writeDefaults);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_overrideController = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void insertLayer(
|
||||
string basePath,
|
||||
AnimatorControllerLayer layer,
|
||||
bool first,
|
||||
bool? writeDefaults,
|
||||
AnimatorControllerLayer[] layers
|
||||
)
|
||||
{
|
||||
var newLayer = new AnimatorControllerLayer()
|
||||
{
|
||||
name = layer.name,
|
||||
avatarMask = layer.avatarMask, // TODO map transforms
|
||||
blendingMode = layer.blendingMode,
|
||||
defaultWeight = first ? 1 : layer.defaultWeight,
|
||||
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<Object, Object>());
|
||||
AdjustBehavior(overrideBehaviors[i]);
|
||||
}
|
||||
|
||||
newLayer.SetOverrideBehaviours((AnimatorState) _cloneMap[state], overrideBehaviors);
|
||||
}
|
||||
}
|
||||
|
||||
newLayer.syncedLayerIndex += controllerBaseLayer;
|
||||
}
|
||||
|
||||
_layers.Add(newLayer);
|
||||
}
|
||||
|
||||
IEnumerable<AnimatorState> WalkAllStates(AnimatorStateMachine animatorStateMachine)
|
||||
{
|
||||
HashSet<Object> visited = new HashSet<Object>();
|
||||
|
||||
foreach (var state in VisitStateMachine(animatorStateMachine))
|
||||
{
|
||||
yield return state;
|
||||
}
|
||||
|
||||
IEnumerable<AnimatorState> 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;
|
||||
|
||||
var queue = new Queue<AnimatorStateMachine>();
|
||||
queue.Enqueue(stateMachine);
|
||||
while (queue.Count > 0)
|
||||
{
|
||||
var sm = queue.Dequeue();
|
||||
foreach (var state in sm.states)
|
||||
{
|
||||
state.state.writeDefaultValues = writeDefaults.Value;
|
||||
}
|
||||
|
||||
foreach (var child in sm.stateMachines)
|
||||
{
|
||||
queue.Enqueue(child.stateMachine);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AnimatorStateMachine mapStateMachine(string basePath, AnimatorStateMachine layerStateMachine)
|
||||
{
|
||||
var cacheKey = new KeyValuePair<string, AnimatorStateMachine>(basePath, layerStateMachine);
|
||||
|
||||
if (_stateMachines.TryGetValue(cacheKey, out var asm))
|
||||
{
|
||||
return asm;
|
||||
}
|
||||
|
||||
asm = deepClone(layerStateMachine, (obj) => customClone(obj, basePath), _cloneMap);
|
||||
|
||||
foreach (var state in WalkAllStates(asm))
|
||||
{
|
||||
foreach (var behavior in state.behaviours)
|
||||
{
|
||||
AdjustBehavior(behavior);
|
||||
}
|
||||
}
|
||||
|
||||
_stateMachines[cacheKey] = asm;
|
||||
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 == "")
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
var newPath = binding.path == "" ? basePath : basePath + binding.path;
|
||||
if (newPath.EndsWith("/"))
|
||||
{
|
||||
newPath = newPath.Substring(0, newPath.Length - 1);
|
||||
}
|
||||
|
||||
return newPath;
|
||||
}
|
||||
}
|
||||
|
||||
private Object customClone(Object o, string basePath)
|
||||
{
|
||||
if (o is AnimationClip clip)
|
||||
{
|
||||
if (basePath == "" || clip.IsProxyAnimation()) return clip;
|
||||
|
||||
AnimationClip newClip = new AnimationClip();
|
||||
newClip.name = clip.name;
|
||||
if (isSaved)
|
||||
{
|
||||
AssetDatabase.AddObjectToAsset(newClip, _combined);
|
||||
}
|
||||
|
||||
foreach (var binding in AnimationUtility.GetCurveBindings(clip))
|
||||
{
|
||||
var newBinding = binding;
|
||||
newBinding.path = MapPath(binding, basePath);
|
||||
newClip.SetCurve(newBinding.path, newBinding.type, newBinding.propertyName,
|
||||
AnimationUtility.GetEditorCurve(clip, binding));
|
||||
}
|
||||
|
||||
foreach (var objBinding in AnimationUtility.GetObjectReferenceCurveBindings(clip))
|
||||
{
|
||||
var newBinding = objBinding;
|
||||
newBinding.path = MapPath(objBinding, basePath);
|
||||
AnimationUtility.SetObjectReferenceCurve(newClip, newBinding,
|
||||
AnimationUtility.GetObjectReferenceCurve(clip, objBinding));
|
||||
}
|
||||
|
||||
newClip.wrapMode = clip.wrapMode;
|
||||
newClip.legacy = clip.legacy;
|
||||
newClip.frameRate = clip.frameRate;
|
||||
newClip.localBounds = clip.localBounds;
|
||||
AnimationUtility.SetAnimationClipSettings(newClip, AnimationUtility.GetAnimationClipSettings(clip));
|
||||
|
||||
return newClip;
|
||||
}
|
||||
else if (o is Texture)
|
||||
{
|
||||
return o;
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private T deepClone<T>(T original,
|
||||
Func<Object, Object> visitor,
|
||||
Dictionary<Object, Object> cloneMap
|
||||
) where T : Object
|
||||
{
|
||||
if (original == null) return null;
|
||||
|
||||
// We want to avoid trying to copy assets not part of the animation system (eg - textures, meshes,
|
||||
// MonoScripts...), so check for the types we care about here
|
||||
switch (original)
|
||||
{
|
||||
// Any object referenced by an animator that we intend to mutate needs to be listed here.
|
||||
case Motion _:
|
||||
case AnimatorController _:
|
||||
case AnimatorState _:
|
||||
case AnimatorStateMachine _:
|
||||
case AnimatorTransitionBase _:
|
||||
case StateMachineBehaviour _:
|
||||
break; // We want to clone these types
|
||||
|
||||
// Leave textures, materials, and script definitions alone
|
||||
case Texture2D _:
|
||||
case MonoScript _:
|
||||
case Material _:
|
||||
return original;
|
||||
|
||||
// Also avoid copying unknown scriptable objects.
|
||||
// This ensures compatibility with e.g. avatar remote, which stores state information in a state
|
||||
// behaviour referencing a custom ScriptableObject
|
||||
case ScriptableObject _:
|
||||
return original;
|
||||
|
||||
default:
|
||||
throw new Exception($"Unknown type referenced from animator: {original.GetType()}");
|
||||
}
|
||||
|
||||
// When using AnimatorOverrideController, replace the original AnimationClip based on AnimatorOverrideController.
|
||||
if (_overrideController != null && original is AnimationClip srcClip)
|
||||
{
|
||||
T overrideClip = _overrideController[srcClip] as T;
|
||||
if (overrideClip != null)
|
||||
{
|
||||
original = overrideClip;
|
||||
}
|
||||
}
|
||||
|
||||
if (cloneMap.ContainsKey(original))
|
||||
{
|
||||
return (T) cloneMap[original];
|
||||
}
|
||||
|
||||
var obj = visitor(original);
|
||||
if (obj != null)
|
||||
{
|
||||
cloneMap[original] = obj;
|
||||
return (T) obj;
|
||||
}
|
||||
|
||||
var ctor = original.GetType().GetConstructor(Type.EmptyTypes);
|
||||
if (ctor == null || original is ScriptableObject)
|
||||
{
|
||||
obj = Object.Instantiate(original);
|
||||
}
|
||||
else
|
||||
{
|
||||
obj = (T) ctor.Invoke(Array.Empty<object>());
|
||||
EditorUtility.CopySerialized(original, obj);
|
||||
}
|
||||
|
||||
cloneMap[original] = obj;
|
||||
|
||||
if (isSaved && _combined != null && EditorUtility.IsPersistent(_combined))
|
||||
{
|
||||
AssetDatabase.AddObjectToAsset(obj, _combined);
|
||||
}
|
||||
|
||||
SerializedObject so = new SerializedObject(obj);
|
||||
SerializedProperty prop = so.GetIterator();
|
||||
|
||||
bool enterChildren = true;
|
||||
while (prop.Next(enterChildren))
|
||||
{
|
||||
enterChildren = true;
|
||||
switch (prop.propertyType)
|
||||
{
|
||||
case SerializedPropertyType.ObjectReference:
|
||||
prop.objectReferenceValue = deepClone(prop.objectReferenceValue, visitor, cloneMap);
|
||||
break;
|
||||
// Iterating strings can get super slow...
|
||||
case SerializedPropertyType.String:
|
||||
enterChildren = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
so.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
return (T) obj;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a3369cd20964957920c3fe8b54df521
|
||||
timeCreated: 1691238359
|
@ -0,0 +1,11 @@
|
||||
namespace nadena.dev.ndmf.animation
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface tags components which supply additional animation controllers for merging. They will be given
|
||||
/// an opportunity to apply animation path updates when the TrackObjectRenamesContext is committed.
|
||||
/// </summary>
|
||||
public interface IOnCommitObjectRenames
|
||||
{
|
||||
void OnCommitObjectRenames(BuildContext buildContext, TrackObjectRenamesContext renameContext);
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17002a48bb4b4ea79993e0549faf2d0e
|
||||
timeCreated: 1692511752
|
@ -0,0 +1,350 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Immutable;
|
||||
using System.Linq;
|
||||
using nadena.dev.ndmf.util;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Animations;
|
||||
using UnityEngine;
|
||||
using VRC.Core;
|
||||
using VRC.SDK3.Avatars.Components;
|
||||
|
||||
namespace nadena.dev.ndmf.animation
|
||||
{
|
||||
using UnityObject = UnityEngine.Object;
|
||||
|
||||
/// <summary>
|
||||
/// This extension context tracks when objects are renamed, and updates animations accordingly.
|
||||
/// Users of this context need to be aware that, when creating new curves (or otherwise introducing new motions,
|
||||
/// use context.ObjectPath to obtain a suitable path for the target objects).
|
||||
/// </summary>
|
||||
public sealed class TrackObjectRenamesContext : IExtensionContext
|
||||
{
|
||||
private Dictionary<GameObject, List<string>>
|
||||
_objectToOriginalPaths = new Dictionary<GameObject, List<string>>();
|
||||
|
||||
private HashSet<GameObject> _transformLookthroughObjects = new HashSet<GameObject>();
|
||||
private ImmutableDictionary<string, string> _originalPathToMappedPath = null;
|
||||
private ImmutableDictionary<string, string> _transformOriginalPathToMappedPath = null;
|
||||
|
||||
public void OnActivate(BuildContext context)
|
||||
{
|
||||
_objectToOriginalPaths.Clear();
|
||||
_transformLookthroughObjects.Clear();
|
||||
ClearCache();
|
||||
|
||||
foreach (var xform in context.AvatarRootTransform.GetComponentsInChildren<Transform>(true))
|
||||
{
|
||||
_objectToOriginalPaths.Add(xform.gameObject, new List<string> {xform.gameObject.AvatarRootPath()});
|
||||
}
|
||||
}
|
||||
|
||||
public void ClearCache()
|
||||
{
|
||||
_originalPathToMappedPath = null;
|
||||
_transformOriginalPathToMappedPath = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the "transform lookthrough" flag for an object. Any transform animations on this object will be
|
||||
/// redirected to its parent. This is used in Modular Avatar as part of bone merging logic.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
public void MarkTransformLookthrough(GameObject obj)
|
||||
{
|
||||
_transformLookthroughObjects.Add(obj);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a path for use in dynamically generated animations for a given object. This can include objects not
|
||||
/// present at the time of context activation; in this case, they will be assigned a randomly-generated internal
|
||||
/// path and replaced during path remapping with the true path.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
/// <returns></returns>
|
||||
public string GetObjectIdentifier(GameObject obj)
|
||||
{
|
||||
if (_objectToOriginalPaths.TryGetValue(obj, out var paths))
|
||||
{
|
||||
return paths[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
var internalPath = "_NewlyCreatedObject/" + GUID.Generate() + "/" + obj.AvatarRootPath();
|
||||
_objectToOriginalPaths.Add(obj, new List<string> {internalPath});
|
||||
return internalPath;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Marks an object as having been removed. Its paths will be remapped to its parent.
|
||||
/// </summary>
|
||||
/// <param name="obj"></param>
|
||||
public void MarkRemoved(GameObject obj)
|
||||
{
|
||||
ClearCache();
|
||||
if (_objectToOriginalPaths.TryGetValue(obj, out var paths))
|
||||
{
|
||||
var parent = obj.transform.parent.gameObject;
|
||||
if (_objectToOriginalPaths.TryGetValue(parent, out var parentPaths))
|
||||
{
|
||||
parentPaths.AddRange(paths);
|
||||
}
|
||||
|
||||
_objectToOriginalPaths.Remove(obj);
|
||||
_transformLookthroughObjects.Remove(obj);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Marks an object as having been replaced by another object. All references to the old object will be replaced
|
||||
/// by the new object. References originally to the new object will continue to point to the new object.
|
||||
/// </summary>
|
||||
/// <param name="old"></param>
|
||||
/// <param name="newObject"></param>
|
||||
public void ReplaceObject(GameObject old, GameObject newObject)
|
||||
{
|
||||
ClearCache();
|
||||
|
||||
if (_objectToOriginalPaths.TryGetValue(old, out var paths))
|
||||
{
|
||||
if (!_objectToOriginalPaths.TryGetValue(newObject, out var newObjectPaths))
|
||||
{
|
||||
newObjectPaths = new List<string>();
|
||||
_objectToOriginalPaths.Add(newObject, newObjectPaths);
|
||||
}
|
||||
|
||||
newObjectPaths.AddRange(paths);
|
||||
|
||||
_objectToOriginalPaths.Remove(old);
|
||||
}
|
||||
|
||||
|
||||
if (_transformLookthroughObjects.Contains(old))
|
||||
{
|
||||
_transformLookthroughObjects.Remove(old);
|
||||
_transformLookthroughObjects.Add(newObject);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private ImmutableDictionary<string, string> BuildMapping(ref ImmutableDictionary<string, string> cache,
|
||||
bool transformLookup)
|
||||
{
|
||||
if (cache != null) return cache;
|
||||
|
||||
ImmutableDictionary<string, string> dict = ImmutableDictionary<string, string>.Empty;
|
||||
|
||||
foreach (var kvp in _objectToOriginalPaths)
|
||||
{
|
||||
var obj = kvp.Key;
|
||||
var paths = kvp.Value;
|
||||
|
||||
if (transformLookup)
|
||||
{
|
||||
while (_transformLookthroughObjects.Contains(obj))
|
||||
{
|
||||
obj = obj.transform.parent.gameObject;
|
||||
}
|
||||
}
|
||||
|
||||
var newPath = obj.AvatarRootPath();
|
||||
foreach (var origPath in paths)
|
||||
{
|
||||
if (!dict.ContainsKey(origPath))
|
||||
{
|
||||
dict = dict.Add(origPath, newPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cache = dict;
|
||||
return cache;
|
||||
}
|
||||
|
||||
public string MapPath(string path, bool isTransformMapping = false)
|
||||
{
|
||||
ImmutableDictionary<string, string> mappings;
|
||||
|
||||
if (isTransformMapping)
|
||||
{
|
||||
mappings = BuildMapping(ref _originalPathToMappedPath, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
mappings = BuildMapping(ref _transformOriginalPathToMappedPath, false);
|
||||
}
|
||||
|
||||
if (mappings.TryGetValue(path, out var mappedPath))
|
||||
{
|
||||
return mappedPath;
|
||||
}
|
||||
else
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
public RuntimeAnimatorController ApplyMappingsToAnimator(
|
||||
BuildContext context,
|
||||
RuntimeAnimatorController controller,
|
||||
Dictionary<AnimationClip, AnimationClip> clipCache = null)
|
||||
{
|
||||
if (clipCache == null)
|
||||
{
|
||||
clipCache = new Dictionary<AnimationClip, AnimationClip>();
|
||||
}
|
||||
|
||||
if (controller == null) return null;
|
||||
|
||||
switch (controller)
|
||||
{
|
||||
case AnimatorController ac:
|
||||
if (!context.IsTemporaryAsset(ac))
|
||||
{
|
||||
ac = AnimationUtil.DeepCloneAnimator(context, ac);
|
||||
}
|
||||
|
||||
foreach (var asset in ac.ReferencedAssets())
|
||||
{
|
||||
if (asset is AnimatorState state)
|
||||
{
|
||||
if (state.motion is AnimationClip clip)
|
||||
{
|
||||
state.motion = ApplyMappingsToClip(clip, clipCache);
|
||||
}
|
||||
}
|
||||
else if (asset is BlendTree tree)
|
||||
{
|
||||
var children = tree.children;
|
||||
for (int i = 0; i < children.Length; i++)
|
||||
{
|
||||
var child = children[i];
|
||||
if (child.motion is AnimationClip clip)
|
||||
{
|
||||
child.motion = ApplyMappingsToClip(clip, clipCache);
|
||||
}
|
||||
}
|
||||
|
||||
tree.children = children;
|
||||
}
|
||||
}
|
||||
|
||||
return ac;
|
||||
case AnimatorOverrideController aoc:
|
||||
{
|
||||
AnimatorOverrideController newController = new AnimatorOverrideController();
|
||||
newController.runtimeAnimatorController =
|
||||
ApplyMappingsToAnimator(context, aoc.runtimeAnimatorController);
|
||||
List<KeyValuePair<AnimationClip, AnimationClip>> overrides =
|
||||
new List<KeyValuePair<AnimationClip, AnimationClip>>();
|
||||
|
||||
overrides = overrides.Select(kvp =>
|
||||
new KeyValuePair<AnimationClip, AnimationClip>(kvp.Key,
|
||||
ApplyMappingsToClip(kvp.Value, clipCache)))
|
||||
.ToList();
|
||||
|
||||
newController.ApplyOverrides(overrides);
|
||||
|
||||
return newController;
|
||||
}
|
||||
default:
|
||||
throw new Exception("Unknown animator controller type: " + controller.GetType().Name);
|
||||
}
|
||||
}
|
||||
|
||||
private string MapPath(EditorCurveBinding binding)
|
||||
{
|
||||
if (binding.type == typeof(Animator) && binding.path == "")
|
||||
{
|
||||
return "";
|
||||
}
|
||||
else
|
||||
{
|
||||
return MapPath(binding.path, binding.type == typeof(Transform));
|
||||
}
|
||||
}
|
||||
|
||||
private AnimationClip ApplyMappingsToClip(AnimationClip originalClip,
|
||||
Dictionary<AnimationClip, AnimationClip> clipCache = null)
|
||||
{
|
||||
if (originalClip == null) return null;
|
||||
if (clipCache != null && clipCache.TryGetValue(originalClip, out var cachedClip)) return cachedClip;
|
||||
|
||||
var newClip = new AnimationClip();
|
||||
newClip.name = originalClip.name;
|
||||
|
||||
SerializedObject before = new SerializedObject(originalClip);
|
||||
SerializedObject after = new SerializedObject(newClip);
|
||||
|
||||
var before_hqCurve = before.FindProperty("m_UseHighQualityCurve");
|
||||
var after_hqCurve = after.FindProperty("m_UseHighQualityCurve");
|
||||
|
||||
after_hqCurve.boolValue = before_hqCurve.boolValue;
|
||||
after.ApplyModifiedPropertiesWithoutUndo();
|
||||
|
||||
// TODO - should we use direct SerializedObject manipulation to avoid missing script issues?
|
||||
foreach (var binding in AnimationUtility.GetCurveBindings(originalClip))
|
||||
{
|
||||
var newBinding = binding;
|
||||
newBinding.path = MapPath(binding);
|
||||
newClip.SetCurve(newBinding.path, newBinding.type, newBinding.propertyName,
|
||||
AnimationUtility.GetEditorCurve(originalClip, binding));
|
||||
}
|
||||
|
||||
foreach (var objBinding in AnimationUtility.GetObjectReferenceCurveBindings(originalClip))
|
||||
{
|
||||
var newBinding = objBinding;
|
||||
newBinding.path = MapPath(objBinding);
|
||||
AnimationUtility.SetObjectReferenceCurve(newClip, newBinding,
|
||||
AnimationUtility.GetObjectReferenceCurve(originalClip, objBinding));
|
||||
}
|
||||
|
||||
newClip.wrapMode = newClip.wrapMode;
|
||||
newClip.legacy = newClip.legacy;
|
||||
newClip.frameRate = newClip.frameRate;
|
||||
newClip.localBounds = newClip.localBounds;
|
||||
AnimationUtility.SetAnimationClipSettings(newClip, AnimationUtility.GetAnimationClipSettings(originalClip));
|
||||
|
||||
if (clipCache != null)
|
||||
{
|
||||
clipCache.Add(originalClip, newClip);
|
||||
}
|
||||
|
||||
return newClip;
|
||||
}
|
||||
|
||||
public void OnDeactivate(BuildContext context)
|
||||
{
|
||||
context.AvatarDescriptor.baseAnimationLayers =
|
||||
MapLayers(context, context.AvatarDescriptor.baseAnimationLayers);
|
||||
context.AvatarDescriptor.specialAnimationLayers =
|
||||
MapLayers(context, context.AvatarDescriptor.specialAnimationLayers);
|
||||
|
||||
foreach (var listener in context.AvatarRootObject.GetComponentsInChildren<IOnCommitObjectRenames>())
|
||||
{
|
||||
listener.OnCommitObjectRenames(context, this);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: port test AnimatesAddedBones from MA
|
||||
|
||||
private VRCAvatarDescriptor.CustomAnimLayer[] MapLayers(
|
||||
BuildContext buildContext,
|
||||
VRCAvatarDescriptor.CustomAnimLayer[] layers
|
||||
)
|
||||
{
|
||||
if (layers == null) return null;
|
||||
|
||||
for (int i = 0; i < layers.Length; i++)
|
||||
{
|
||||
var layer = layers[i];
|
||||
layer.animatorController = ApplyMappingsToAnimator(buildContext, layer.animatorController);
|
||||
layers[i] = layer;
|
||||
}
|
||||
|
||||
return layers;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: deb8a666d3af40b0be0ac616cf98a05b
|
||||
timeCreated: 1691237971
|
@ -16,13 +16,15 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
|
||||
{
|
||||
public override string QualifiedName => "nadena.dev.modular-avatar";
|
||||
public override string DisplayName => "Modular Avatar";
|
||||
|
||||
|
||||
protected override void Configure()
|
||||
{
|
||||
InPhase(BuildPhase.Resolving)
|
||||
.Run(ResolveObjectReferences.Instance);
|
||||
Sequence seq = InPhase(BuildPhase.Resolving);
|
||||
seq.Run(ResolveObjectReferences.Instance);
|
||||
// Protect against accidental destructive edits by cloning the input controllers ASAP
|
||||
seq.Run("Clone animators", AnimationUtil.CloneAllControllers);
|
||||
|
||||
Sequence seq = InPhase(BuildPhase.Transforming);
|
||||
seq = InPhase(BuildPhase.Transforming);
|
||||
seq.WithRequiredExtension(typeof(ModularAvatarContext), _s1 =>
|
||||
{
|
||||
seq.Run(ClearEditorOnlyTags.Instance);
|
||||
@ -38,9 +40,10 @@ namespace nadena.dev.modular_avatar.core.editor.plugin
|
||||
seq.Run(ReplaceObjectPluginPass.Instance);
|
||||
});
|
||||
seq.Run(BlendshapeSyncAnimationPluginPass.Instance);
|
||||
seq.Run(PhysbonesBlockerPluginPass.Instance);;
|
||||
seq.Run(PhysbonesBlockerPluginPass.Instance);
|
||||
;
|
||||
});
|
||||
|
||||
|
||||
InPhase(BuildPhase.Optimizing)
|
||||
.WithRequiredExtension(typeof(ModularAvatarContext),
|
||||
s => s.Run(GCGameObjectsPluginPass.Instance));
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit 408fce61cf9810d2ad7f1395015960250e841778
|
||||
Subproject commit 0fbda0b606f2d5172aa6c21d659e94e168c89a8e
|
Loading…
Reference in New Issue
Block a user