3 Ревизии 99d64b5766 ... 9da107c357

Автор SHA1 Съобщение Дата
  Jidongchen 9da107c357 ui преди 3 години
  Jidongchen e2106b4a25 Merge branch 'master' of http://git.xwxgame.com/qianzhuqing/metaClient преди 3 години
  Jidongchen 40f2798711 animationmaker преди 3 години
променени са 100 файла, в които са добавени 21782 реда и са изтрити 932 реда
  1. BIN
      Assets/GameMain/DataTables/CustomBody.txt
  2. 618 0
      Assets/GameMain/Scenes/AnimationMaker.unity
  3. 7 0
      Assets/GameMain/Scenes/AnimationMaker.unity.meta
  4. 8 0
      Assets/GameMain/Scripts/AnimationMaker.meta
  5. 91 0
      Assets/GameMain/Scripts/AnimationMaker/AniBoneMove.cs
  6. 11 0
      Assets/GameMain/Scripts/AnimationMaker/AniBoneMove.cs.meta
  7. 71 0
      Assets/GameMain/Scripts/AnimationMaker/AniEventArgs.cs
  8. 11 0
      Assets/GameMain/Scripts/AnimationMaker/AniEventArgs.cs.meta
  9. 184 0
      Assets/GameMain/Scripts/AnimationMaker/AniManager.cs
  10. 11 0
      Assets/GameMain/Scripts/AnimationMaker/AniManager.cs.meta
  11. 67 0
      Assets/GameMain/Scripts/AnimationMaker/AniPickOnImage.cs
  12. 11 0
      Assets/GameMain/Scripts/AnimationMaker/AniPickOnImage.cs.meta
  13. 293 0
      Assets/GameMain/Scripts/AnimationMaker/AniRoByTime.cs
  14. 11 0
      Assets/GameMain/Scripts/AnimationMaker/AniRoByTime.cs.meta
  15. 31 0
      Assets/GameMain/Scripts/UI/UIAMLayaoutGrid.cs
  16. 11 0
      Assets/GameMain/Scripts/UI/UIAMLayaoutGrid.cs.meta
  17. 50 4
      Assets/GameMain/Scripts/UI/UIAnimationMaker.cs
  18. 2 1
      Assets/GameMain/Scripts/UI/UICustomBtn.cs
  19. 2217 927
      Assets/GameMain/UI/UIForms/AnimationMaker.prefab
  20. 8 0
      Assets/Plugins.meta
  21. 8 0
      Assets/Plugins/RootMotion.meta
  22. 9 0
      Assets/Plugins/RootMotion/Baker.meta
  23. 9 0
      Assets/Plugins/RootMotion/Baker/Scripts.meta
  24. 498 0
      Assets/Plugins/RootMotion/Baker/Scripts/Baker.cs
  25. 12 0
      Assets/Plugins/RootMotion/Baker/Scripts/Baker.cs.meta
  26. 134 0
      Assets/Plugins/RootMotion/Baker/Scripts/GenericBaker.cs
  27. 12 0
      Assets/Plugins/RootMotion/Baker/Scripts/GenericBaker.cs.meta
  28. 9 0
      Assets/Plugins/RootMotion/Baker/Scripts/Helpers.meta
  29. 90 0
      Assets/Plugins/RootMotion/Baker/Scripts/Helpers/AvatarUtility.cs
  30. 12 0
      Assets/Plugins/RootMotion/Baker/Scripts/Helpers/AvatarUtility.cs.meta
  31. 579 0
      Assets/Plugins/RootMotion/Baker/Scripts/Helpers/BakerUtilities.cs
  32. 12 0
      Assets/Plugins/RootMotion/Baker/Scripts/Helpers/BakerUtilities.cs.meta
  33. 194 0
      Assets/Plugins/RootMotion/Baker/Scripts/HumanoidBaker.cs
  34. 12 0
      Assets/Plugins/RootMotion/Baker/Scripts/HumanoidBaker.cs.meta
  35. 9 0
      Assets/Plugins/RootMotion/Baker/_DEMOS.meta
  36. 8 0
      Assets/Plugins/RootMotion/Baker/_DEMOS/Baked Clips.meta
  37. 11611 0
      Assets/Plugins/RootMotion/Baker/_DEMOS/Baked Clips/Clip 1_Baked.anim
  38. 8 0
      Assets/Plugins/RootMotion/Baker/_DEMOS/Baked Clips/Clip 1_Baked.anim.meta
  39. 69 0
      Assets/Plugins/RootMotion/Baker/_DEMOS/Humanoid Baker Clip Sampler.controller
  40. 8 0
      Assets/Plugins/RootMotion/Baker/_DEMOS/Humanoid Baker Clip Sampler.controller.meta
  41. 2228 0
      Assets/Plugins/RootMotion/Baker/_DEMOS/Humanoid Baker.unity
  42. 8 0
      Assets/Plugins/RootMotion/Baker/_DEMOS/Humanoid Baker.unity.meta
  43. 8 0
      Assets/Plugins/RootMotion/Baker/_DEMOS/Scripts.meta
  44. 53 0
      Assets/Plugins/RootMotion/Baker/_DEMOS/Scripts/FKOffset.cs
  45. 11 0
      Assets/Plugins/RootMotion/Baker/_DEMOS/Scripts/FKOffset.cs.meta
  46. 8 0
      Assets/Plugins/RootMotion/Editor.meta
  47. 9 0
      Assets/Plugins/RootMotion/Editor/Baker.meta
  48. 176 0
      Assets/Plugins/RootMotion/Editor/Baker/BakerInspector.cs
  49. 12 0
      Assets/Plugins/RootMotion/Editor/Baker/BakerInspector.cs.meta
  50. 52 0
      Assets/Plugins/RootMotion/Editor/Baker/GenericBakerInspector.cs
  51. 8 0
      Assets/Plugins/RootMotion/Editor/Baker/GenericBakerInspector.cs.meta
  52. 9 0
      Assets/Plugins/RootMotion/Editor/Baker/Helpers.meta
  53. 38 0
      Assets/Plugins/RootMotion/Editor/Baker/Helpers/AnimationUtilityExtended.cs
  54. 12 0
      Assets/Plugins/RootMotion/Editor/Baker/Helpers/AnimationUtilityExtended.cs.meta
  55. 22 0
      Assets/Plugins/RootMotion/Editor/Baker/Helpers/SaveClipFolderPanel.cs
  56. 11 0
      Assets/Plugins/RootMotion/Editor/Baker/Helpers/SaveClipFolderPanel.cs.meta
  57. 52 0
      Assets/Plugins/RootMotion/Editor/Baker/HumanoidBakerInspector.cs
  58. 12 0
      Assets/Plugins/RootMotion/Editor/Baker/HumanoidBakerInspector.cs.meta
  59. 9 0
      Assets/Plugins/RootMotion/Editor/FinalIK.meta
  60. 38 0
      Assets/Plugins/RootMotion/Editor/FinalIK/AimIKInspector.cs
  61. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/AimIKInspector.cs.meta
  62. 189 0
      Assets/Plugins/RootMotion/Editor/FinalIK/AimPoserInspector.cs
  63. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/AimPoserInspector.cs.meta
  64. 38 0
      Assets/Plugins/RootMotion/Editor/FinalIK/ArmIKInspector.cs
  65. 12 0
      Assets/Plugins/RootMotion/Editor/FinalIK/ArmIKInspector.cs.meta
  66. 115 0
      Assets/Plugins/RootMotion/Editor/FinalIK/BipedIKInspector.cs
  67. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/BipedIKInspector.cs.meta
  68. 120 0
      Assets/Plugins/RootMotion/Editor/FinalIK/BipedIKSolversInspector.cs
  69. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/BipedIKSolversInspector.cs.meta
  70. 38 0
      Assets/Plugins/RootMotion/Editor/FinalIK/CCDIKInspector.cs
  71. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/CCDIKInspector.cs.meta
  72. 67 0
      Assets/Plugins/RootMotion/Editor/FinalIK/ConstraintsInspector.cs
  73. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/ConstraintsInspector.cs.meta
  74. 87 0
      Assets/Plugins/RootMotion/Editor/FinalIK/EditorIKInspector.cs
  75. 11 0
      Assets/Plugins/RootMotion/Editor/FinalIK/EditorIKInspector.cs.meta
  76. 38 0
      Assets/Plugins/RootMotion/Editor/FinalIK/FABRIKInspector.cs
  77. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/FABRIKInspector.cs.meta
  78. 35 0
      Assets/Plugins/RootMotion/Editor/FinalIK/FABRIKRootInspector.cs
  79. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/FABRIKRootInspector.cs.meta
  80. 99 0
      Assets/Plugins/RootMotion/Editor/FinalIK/FingerRigInspector.cs
  81. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/FingerRigInspector.cs.meta
  82. 107 0
      Assets/Plugins/RootMotion/Editor/FinalIK/FullBodyBipedIKInspector.cs
  83. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/FullBodyBipedIKInspector.cs.meta
  84. 13 0
      Assets/Plugins/RootMotion/Editor/FinalIK/GroundingInspector.cs
  85. 12 0
      Assets/Plugins/RootMotion/Editor/FinalIK/GroundingInspector.cs.meta
  86. 106 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKEffectorInspector.cs
  87. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKEffectorInspector.cs.meta
  88. 27 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKExecutionOrderInspector.cs
  89. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKExecutionOrderInspector.cs.meta
  90. 67 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKInspector.cs
  91. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKInspector.cs.meta
  92. 103 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverAimInspector.cs
  93. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverAimInspector.cs.meta
  94. 101 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverArmInspector.cs
  95. 12 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverArmInspector.cs.meta
  96. 94 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverFABRIKRootInspector.cs
  97. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverFABRIKRootInspector.cs.meta
  98. 339 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverFullBodyBipedInspector.cs
  99. 10 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverFullBodyBipedInspector.cs.meta
  100. 0 0
      Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverFullBodyInspector.cs

BIN
Assets/GameMain/DataTables/CustomBody.txt


+ 618 - 0
Assets/GameMain/Scenes/AnimationMaker.unity

@@ -0,0 +1,618 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!29 &1
+OcclusionCullingSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_OcclusionBakeSettings:
+    smallestOccluder: 5
+    smallestHole: 0.25
+    backfaceThreshold: 100
+  m_SceneGUID: 00000000000000000000000000000000
+  m_OcclusionCullingData: {fileID: 0}
+--- !u!104 &2
+RenderSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 9
+  m_Fog: 0
+  m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
+  m_FogMode: 3
+  m_FogDensity: 0.01
+  m_LinearFogStart: 0
+  m_LinearFogEnd: 300
+  m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
+  m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
+  m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
+  m_AmbientIntensity: 1
+  m_AmbientMode: 0
+  m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
+  m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
+  m_HaloStrength: 0.5
+  m_FlareStrength: 1
+  m_FlareFadeSpeed: 3
+  m_HaloTexture: {fileID: 0}
+  m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
+  m_DefaultReflectionMode: 0
+  m_DefaultReflectionResolution: 128
+  m_ReflectionBounces: 1
+  m_ReflectionIntensity: 1
+  m_CustomReflection: {fileID: 0}
+  m_Sun: {fileID: 0}
+  m_IndirectSpecularColor: {r: 0.44657898, g: 0.4964133, b: 0.5748178, a: 1}
+  m_UseRadianceAmbientProbe: 0
+--- !u!157 &3
+LightmapSettings:
+  m_ObjectHideFlags: 0
+  serializedVersion: 11
+  m_GIWorkflowMode: 1
+  m_GISettings:
+    serializedVersion: 2
+    m_BounceScale: 1
+    m_IndirectOutputScale: 1
+    m_AlbedoBoost: 1
+    m_EnvironmentLightingMode: 0
+    m_EnableBakedLightmaps: 1
+    m_EnableRealtimeLightmaps: 0
+  m_LightmapEditorSettings:
+    serializedVersion: 12
+    m_Resolution: 2
+    m_BakeResolution: 40
+    m_AtlasSize: 1024
+    m_AO: 0
+    m_AOMaxDistance: 1
+    m_CompAOExponent: 1
+    m_CompAOExponentDirect: 0
+    m_ExtractAmbientOcclusion: 0
+    m_Padding: 2
+    m_LightmapParameters: {fileID: 0}
+    m_LightmapsBakeMode: 1
+    m_TextureCompression: 1
+    m_FinalGather: 0
+    m_FinalGatherFiltering: 1
+    m_FinalGatherRayCount: 256
+    m_ReflectionCompression: 2
+    m_MixedBakeMode: 2
+    m_BakeBackend: 1
+    m_PVRSampling: 1
+    m_PVRDirectSampleCount: 32
+    m_PVRSampleCount: 512
+    m_PVRBounces: 2
+    m_PVREnvironmentSampleCount: 256
+    m_PVREnvironmentReferencePointCount: 2048
+    m_PVRFilteringMode: 1
+    m_PVRDenoiserTypeDirect: 1
+    m_PVRDenoiserTypeIndirect: 1
+    m_PVRDenoiserTypeAO: 1
+    m_PVRFilterTypeDirect: 0
+    m_PVRFilterTypeIndirect: 0
+    m_PVRFilterTypeAO: 0
+    m_PVREnvironmentMIS: 1
+    m_PVRCulling: 1
+    m_PVRFilteringGaussRadiusDirect: 1
+    m_PVRFilteringGaussRadiusIndirect: 5
+    m_PVRFilteringGaussRadiusAO: 2
+    m_PVRFilteringAtrousPositionSigmaDirect: 0.5
+    m_PVRFilteringAtrousPositionSigmaIndirect: 2
+    m_PVRFilteringAtrousPositionSigmaAO: 1
+    m_ExportTrainingData: 0
+    m_TrainingDataDestination: TrainingData
+    m_LightProbeSampleCountMultiplier: 4
+  m_LightingDataAsset: {fileID: 0}
+  m_UseShadowmask: 1
+--- !u!196 &4
+NavMeshSettings:
+  serializedVersion: 2
+  m_ObjectHideFlags: 0
+  m_BuildSettings:
+    serializedVersion: 2
+    agentTypeID: 0
+    agentRadius: 0.5
+    agentHeight: 2
+    agentSlope: 45
+    agentClimb: 0.4
+    ledgeDropHeight: 0
+    maxJumpAcrossDistance: 0
+    minRegionArea: 2
+    manualCellSize: 0
+    cellSize: 0.16666667
+    manualTileSize: 0
+    tileSize: 256
+    accuratePlacement: 0
+    debug:
+      m_Flags: 0
+  m_NavMeshData: {fileID: 0}
+--- !u!1 &533022344
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 533022347}
+  - component: {fileID: 533022346}
+  - component: {fileID: 533022345}
+  m_Layer: 0
+  m_Name: Main Camera
+  m_TagString: MainCamera
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!81 &533022345
+AudioListener:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 533022344}
+  m_Enabled: 1
+--- !u!20 &533022346
+Camera:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 533022344}
+  m_Enabled: 1
+  serializedVersion: 2
+  m_ClearFlags: 1
+  m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
+  m_projectionMatrixMode: 1
+  m_GateFitMode: 2
+  m_FOVAxisMode: 0
+  m_SensorSize: {x: 36, y: 24}
+  m_LensShift: {x: 0, y: 0}
+  m_FocalLength: 50
+  m_NormalizedViewPortRect:
+    serializedVersion: 2
+    x: 0
+    y: 0
+    width: 1
+    height: 1
+  near clip plane: 0.3
+  far clip plane: 1000
+  field of view: 60
+  orthographic: 0
+  orthographic size: 5
+  m_Depth: -1
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingPath: -1
+  m_TargetTexture: {fileID: 0}
+  m_TargetDisplay: 0
+  m_TargetEye: 3
+  m_HDR: 1
+  m_AllowMSAA: 1
+  m_AllowDynamicResolution: 0
+  m_ForceIntoRT: 0
+  m_OcclusionCulling: 1
+  m_StereoConvergence: 10
+  m_StereoSeparation: 0.022
+--- !u!4 &533022347
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 533022344}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 1, z: -10}
+  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!1001 &769287461
+PrefabInstance:
+  m_ObjectHideFlags: 0
+  serializedVersion: 2
+  m_Modification:
+    m_TransformParent: {fileID: 0}
+    m_Modifications:
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_RootOrder
+      value: 2
+      objectReference: {fileID: 0}
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_LocalPosition.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_LocalPosition.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_LocalPosition.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_LocalRotation.w
+      value: 1
+      objectReference: {fileID: 0}
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_LocalRotation.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_LocalRotation.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_LocalRotation.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.x
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.y
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: -8679921383154817045, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_LocalEulerAnglesHint.z
+      value: 0
+      objectReference: {fileID: 0}
+    - target: {fileID: 919132149155446097, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+        type: 3}
+      propertyPath: m_Name
+      value: 8
+      objectReference: {fileID: 0}
+    m_RemovedComponents: []
+  m_SourcePrefab: {fileID: 100100000, guid: 19bd63a8fb3456e4cb32b1c7f4860f48, type: 3}
+--- !u!1 &786726044
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 786726047}
+  - component: {fileID: 786726046}
+  - component: {fileID: 786726045}
+  m_Layer: 0
+  m_Name: EventSystem
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &786726045
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 786726044}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 4f231c4fb786f3946a6b90b886c48677, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_HorizontalAxis: Horizontal
+  m_VerticalAxis: Vertical
+  m_SubmitButton: Submit
+  m_CancelButton: Cancel
+  m_InputActionsPerSecond: 10
+  m_RepeatDelay: 0.5
+  m_ForceModuleActive: 0
+--- !u!114 &786726046
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 786726044}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 76c392e42b5098c458856cdf6ecaaaa1, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_FirstSelected: {fileID: 0}
+  m_sendNavigationEvents: 1
+  m_DragThreshold: 10
+--- !u!4 &786726047
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 786726044}
+  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: 0}
+  m_RootOrder: 4
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!1 &1431321542 stripped
+GameObject:
+  m_CorrespondingSourceObject: {fileID: 919132149155446097, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+    type: 3}
+  m_PrefabInstance: {fileID: 769287461}
+  m_PrefabAsset: {fileID: 0}
+--- !u!114 &1431321543
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1431321542}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f252e774208d9849ab46bc05249016b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  eIKPickOnButtonStyple: 0
+  cCDIK: {fileID: 0}
+  dis: 0.5
+  picParent: {fileID: 0}
+  bones: []
+  nowAniName: 8
+--- !u!1 &1498059351
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1498059352}
+  - component: {fileID: 1498059353}
+  m_Layer: 0
+  m_Name: AnimationScripts
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!4 &1498059352
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1498059351}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 375, y: 667, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 5
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+--- !u!114 &1498059353
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1498059351}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 5f252e774208d9849ab46bc05249016b, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  eIKPickOnButtonStyple: 0
+  cCDIK: {fileID: 0}
+  dis: 0.5
+  picParent: {fileID: 1516039636}
+  bones:
+  - {fileID: 1865081429}
+  - {fileID: 2092060811}
+  nowAniName: 8
+--- !u!1 &1516039632
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1516039636}
+  - component: {fileID: 1516039635}
+  - component: {fileID: 1516039634}
+  - component: {fileID: 1516039633}
+  m_Layer: 5
+  m_Name: Canvas
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!114 &1516039633
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1516039632}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: dc42784cf147c0c48a680349fa168899, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_IgnoreReversedGraphics: 1
+  m_BlockingObjects: 0
+  m_BlockingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+--- !u!114 &1516039634
+MonoBehaviour:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1516039632}
+  m_Enabled: 1
+  m_EditorHideFlags: 0
+  m_Script: {fileID: 11500000, guid: 0cd44c1031e13a943bb63640046fad76, type: 3}
+  m_Name: 
+  m_EditorClassIdentifier: 
+  m_UiScaleMode: 0
+  m_ReferencePixelsPerUnit: 100
+  m_ScaleFactor: 1
+  m_ReferenceResolution: {x: 800, y: 600}
+  m_ScreenMatchMode: 0
+  m_MatchWidthOrHeight: 0
+  m_PhysicalUnit: 3
+  m_FallbackScreenDPI: 96
+  m_DefaultSpriteDPI: 96
+  m_DynamicPixelsPerUnit: 1
+--- !u!223 &1516039635
+Canvas:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1516039632}
+  m_Enabled: 1
+  serializedVersion: 3
+  m_RenderMode: 0
+  m_Camera: {fileID: 0}
+  m_PlaneDistance: 100
+  m_PixelPerfect: 0
+  m_ReceivesEvents: 1
+  m_OverrideSorting: 0
+  m_OverridePixelPerfect: 0
+  m_SortingBucketNormalizedSize: 0
+  m_AdditionalShaderChannelsFlag: 0
+  m_SortingLayerID: 0
+  m_SortingOrder: 0
+  m_TargetDisplay: 0
+--- !u!224 &1516039636
+RectTransform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1516039632}
+  m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
+  m_LocalPosition: {x: 0, y: 0, z: 0}
+  m_LocalScale: {x: 0, y: 0, z: 0}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 3
+  m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
+  m_AnchorMin: {x: 0, y: 0}
+  m_AnchorMax: {x: 0, y: 0}
+  m_AnchoredPosition: {x: 0, y: 0}
+  m_SizeDelta: {x: 0, y: 0}
+  m_Pivot: {x: 0, y: 0}
+--- !u!1 &1843509978
+GameObject:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  serializedVersion: 6
+  m_Component:
+  - component: {fileID: 1843509980}
+  - component: {fileID: 1843509979}
+  m_Layer: 0
+  m_Name: Directional Light
+  m_TagString: Untagged
+  m_Icon: {fileID: 0}
+  m_NavMeshLayer: 0
+  m_StaticEditorFlags: 0
+  m_IsActive: 1
+--- !u!108 &1843509979
+Light:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1843509978}
+  m_Enabled: 1
+  serializedVersion: 10
+  m_Type: 1
+  m_Shape: 0
+  m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
+  m_Intensity: 1
+  m_Range: 10
+  m_SpotAngle: 30
+  m_InnerSpotAngle: 21.80208
+  m_CookieSize: 10
+  m_Shadows:
+    m_Type: 2
+    m_Resolution: -1
+    m_CustomResolution: -1
+    m_Strength: 1
+    m_Bias: 0.05
+    m_NormalBias: 0.4
+    m_NearPlane: 0.2
+    m_CullingMatrixOverride:
+      e00: 1
+      e01: 0
+      e02: 0
+      e03: 0
+      e10: 0
+      e11: 1
+      e12: 0
+      e13: 0
+      e20: 0
+      e21: 0
+      e22: 1
+      e23: 0
+      e30: 0
+      e31: 0
+      e32: 0
+      e33: 1
+    m_UseCullingMatrixOverride: 0
+  m_Cookie: {fileID: 0}
+  m_DrawHalo: 0
+  m_Flare: {fileID: 0}
+  m_RenderMode: 0
+  m_CullingMask:
+    serializedVersion: 2
+    m_Bits: 4294967295
+  m_RenderingLayerMask: 1
+  m_Lightmapping: 4
+  m_LightShadowCasterMode: 0
+  m_AreaSize: {x: 1, y: 1}
+  m_BounceIntensity: 1
+  m_ColorTemperature: 6570
+  m_UseColorTemperature: 0
+  m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
+  m_UseBoundingSphereOverride: 0
+  m_ShadowRadius: 0
+  m_ShadowAngle: 0
+--- !u!4 &1843509980
+Transform:
+  m_ObjectHideFlags: 0
+  m_CorrespondingSourceObject: {fileID: 0}
+  m_PrefabInstance: {fileID: 0}
+  m_PrefabAsset: {fileID: 0}
+  m_GameObject: {fileID: 1843509978}
+  m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
+  m_LocalPosition: {x: 0, y: 3, z: 0}
+  m_LocalScale: {x: 1, y: 1, z: 1}
+  m_Children: []
+  m_Father: {fileID: 0}
+  m_RootOrder: 1
+  m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
+--- !u!4 &1865081429 stripped
+Transform:
+  m_CorrespondingSourceObject: {fileID: 3314605716580837325, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+    type: 3}
+  m_PrefabInstance: {fileID: 769287461}
+  m_PrefabAsset: {fileID: 0}
+--- !u!4 &2092060811 stripped
+Transform:
+  m_CorrespondingSourceObject: {fileID: 341174793924076435, guid: 19bd63a8fb3456e4cb32b1c7f4860f48,
+    type: 3}
+  m_PrefabInstance: {fileID: 769287461}
+  m_PrefabAsset: {fileID: 0}

+ 7 - 0
Assets/GameMain/Scenes/AnimationMaker.unity.meta

@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: df4600baf57f0af41a9b5aa33a4c37e7
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/GameMain/Scripts/AnimationMaker.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 95c620a42a300764a9d71a416af97d66
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 91 - 0
Assets/GameMain/Scripts/AnimationMaker/AniBoneMove.cs

@@ -0,0 +1,91 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.EventSystems;
+using UnityEngine.UI;
+using RootMotion.FinalIK;
+namespace MetaClient
+{
+    public class AniBoneMove : MonoBehaviour, IDragHandler, IEndDragHandler, IBeginDragHandler
+    {
+        public Transform obj;
+        public Transform target;
+        public float dis;
+        public Transform bone;
+        public AniManager bonePicture;
+        // Start is called before the first frame update
+        public void ChangeDragImage(BonePicTarget _bonePicTarget, float _dis)
+        {
+            //tI = _tI;
+            obj = _bonePicTarget.pic;
+            target = _bonePicTarget.target;
+            dis = _dis;
+            bone = _bonePicTarget.bone;
+        }
+
+        public void OnDrag(PointerEventData eventData)
+        {
+
+
+            Vector3 imagePos = obj.transform.position;
+            Vector3 imagePosNext = new Vector3(imagePos.x + eventData.delta.x, imagePos.y + eventData.delta.y, imagePos.z);
+
+            Vector3 screenPos = Camera.main.ScreenToWorldPoint(imagePosNext);
+
+            var boneParDis = Vector3.Distance(bone.transform.parent.position, screenPos);
+            var boneDis = Vector3.Distance(bone.transform.position, bone.transform.parent.position);
+            if ((boneDis + dis) < boneParDis)
+            {
+                return;
+            }
+            target.position = screenPos;
+            obj.position = imagePosNext;
+
+            //BoneRotateByTime boneRotateByTime = bone.gameObject.GetComponent<BoneRotateByTime>();
+            // boneRotateByTime.NowRo();
+            bonePicture.chooseImage.ForEach(i =>
+            {
+               // BoneRotateByTime boneRotateByTime = i.bone.gameObject.GetComponent<BoneRotateByTime>();
+               // boneRotateByTime.NowRo();
+            });
+
+
+            bonePicture.bonePicTarget.ForEach(
+                i =>
+                {
+                    if (i.pic.gameObject != this.gameObject)
+                    {
+                        i.target.position = i.bone.transform.position;
+                        i.pic.position = Camera.main.WorldToScreenPoint(i.bone.transform.position);
+                    };
+                }
+                );
+        } 
+        public void OnBeginDrag(PointerEventData eventData)
+        {
+            //LimbIK limbIK = target.gameObject.AddComponent<LimbIK>();
+            ////limbIK.enabled = false;
+            //limbIK.solver.bone1.transform = bone.parent.parent.transform;
+            //limbIK.solver.bone2.transform = bone.transform;
+            //limbIK.solver.bone3.transform = bone.GetChild(0).transform;
+            //limbIK.solver.target = target.transform;
+            //limbIK.solver.SetIKPositionWeight(1f);
+            //limbIK.solver.SetIKRotationWeight(0);
+            bonePicture.cCDIK.enabled = true;
+           // bonePicture.MoveFun();
+            Debug.Log("开始拖拽");
+        }
+        public void OnEndDrag(PointerEventData eventData)
+        {
+           // bonePicture.NotMoveFun();
+            //bonePicture.cCDIK.enabled = false;
+            ////Destroy(target.GetComponent<LimbIK>());
+            //Debug.Log("结束拖拽");
+        }
+        // Update is called once per frame
+        void Update()
+        {
+
+        }
+    }
+}

+ 11 - 0
Assets/GameMain/Scripts/AnimationMaker/AniBoneMove.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 942c16c40a4ae17418afa657ebc0c586
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 71 - 0
Assets/GameMain/Scripts/AnimationMaker/AniEventArgs.cs

@@ -0,0 +1,71 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using GameFramework;
+using GameFramework.Event;
+namespace MetaClient
+{
+    public class AniEventArgs : GameEventArgs
+    {
+        /// <summary>
+        /// 打开界面成功事件编号。
+        /// </summary>
+        public static readonly int EventId = typeof(AniEventArgs).GetHashCode();
+        /// <summary>
+        /// 获取打开界面成功事件编号。
+        /// </summary>
+        public override int Id
+        {
+            get
+            {
+                return EventId;
+            }
+        }
+
+        public EAniEventArgsType Type { get; set; }
+        public string Message { get; set; }
+        public string Name { get; set; }
+        public int KTime  { get; set; }
+        public static AniEventArgs Create(EAniEventArgsType type,string name)
+        {
+            AniEventArgs aniEventArgs = ReferencePool.Acquire<AniEventArgs>();
+            aniEventArgs.Type = type;
+            aniEventArgs.Name = name;
+            return aniEventArgs;
+        }
+        public static AniEventArgs Create(EAniEventArgsType type, string name,int ktime,string message)
+        {
+            AniEventArgs aniEventArgs = ReferencePool.Acquire<AniEventArgs>();
+            aniEventArgs.Type = type;
+            aniEventArgs.KTime = ktime;
+            aniEventArgs.Message = message;
+            aniEventArgs.Name = name;
+            return aniEventArgs;
+        }
+        public static AniEventArgs Create(EAniEventArgsType type, string name,string message)
+        {
+            AniEventArgs aniEventArgs = ReferencePool.Acquire<AniEventArgs>();
+            aniEventArgs.Type = type;
+            aniEventArgs.Message = message;
+            aniEventArgs.Name = name;
+            return aniEventArgs;
+        }
+        public override void Clear()
+        {
+
+        }
+    }
+
+    public enum EAniEventArgsType
+    {
+        None,
+        RotateX,
+        RotateY,
+        Move,
+        PlayKTime,
+        MoveKTime,
+        CopyKTime,
+        DelectKTime,
+    }
+
+}

+ 11 - 0
Assets/GameMain/Scripts/AnimationMaker/AniEventArgs.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ec84f464bebb7d9439380fe6d5cfda87
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 184 - 0
Assets/GameMain/Scripts/AnimationMaker/AniManager.cs

@@ -0,0 +1,184 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+using GameFramework.Event;
+using UnityEngine.UI;
+using RootMotion.FinalIK;
+using System.Linq;
+namespace MetaClient
+{
+    public class AniManager : MonoBehaviour
+    {
+        public static AniManager Instance;
+        public Dictionary<string, List<BonePicTarget>> aniBPT = new Dictionary<string, List<BonePicTarget>>();
+        public Dictionary<string, List<BoneData>> bonedata = new Dictionary<string, List<BoneData>>();
+        public EIKPickOnButtonStyple eIKPickOnButtonStyple = EIKPickOnButtonStyple.None;
+        public CCDIK cCDIK = null;
+        public float dis = 0.5f;
+        public Transform picParent;
+        public List<Transform> bones = new List<Transform>();
+        public List<BonePicTarget> chooseImage = new List<BonePicTarget>();
+        public List<BonePicTarget> bonePicTarget = new List<BonePicTarget>();
+        private int nowtime = 0;
+        public string nowAniName = "8";
+        //private 
+        // Start is called before the first frame update
+        //public Dictionary<string,>
+        void Start()
+        {
+           
+            bones.ForEach(i =>
+            {
+                Vector3 worldPos = i.position;
+                Vector3 screenPos = Camera.main.WorldToScreenPoint(worldPos);
+                GameObject imgObj = new GameObject();
+                GameObject target = new GameObject();
+                target.transform.position = i.position;
+                var image = imgObj.AddComponent<Image>();
+                image.color = Color.red;
+                //if (aniBPT.ContainsKey(i.name)||i.name=="8")
+                //{
+                //    i.name = "All";
+                //}
+                //else
+                //{
+                    imgObj.name = i.name;
+                //}
+                imgObj.transform.position = screenPos;
+                imgObj.transform.SetParent(picParent);
+                imgObj.transform.localScale = new Vector3(0.1f, 0.1f, 0.1f);
+                BonePicTarget _bonePicTarget = new BonePicTarget(i, imgObj.transform, target.transform);
+                bonePicTarget.Add(_bonePicTarget);
+                 AniPickOnImage pickOnImage = imgObj.AddComponent<AniPickOnImage>();
+                 pickOnImage.bonePicTarget = _bonePicTarget;
+                 pickOnImage.bonePicture = this;
+                 //BoneRotateByTime boneRotateByTime = i.gameObject.AddComponent<BoneRotateByTime>();
+              //  boneRotateByTimes.Add(boneRotateByTime);
+            });
+        }
+        private void Awake()
+        {
+            Instance = this;
+        }
+        public void Init()
+        {
+            GameEntry.Event.Subscribe(AniEventArgs.EventId, UpdateAni);
+        }
+        public void SaveMove(string boneName)
+        {
+            
+        }
+        private void UpdateAni(object sender, GameEventArgs e)
+        {
+            AniEventArgs crf = (AniEventArgs)e;
+            if (crf != null)
+            {
+
+                switch (crf.Type)
+                {
+                    case EAniEventArgsType.None:
+                        break;
+                    case EAniEventArgsType.RotateX:
+                        break;
+                    case EAniEventArgsType.RotateY:
+                        break;
+                    case EAniEventArgsType.Move:
+                        break;
+                    case EAniEventArgsType.PlayKTime:
+                        break;
+                    case EAniEventArgsType.MoveKTime:
+                        break;
+                    case EAniEventArgsType.CopyKTime:
+                        break;
+                    case EAniEventArgsType.DelectKTime:
+                        break;
+
+                }
+            }
+        }
+        public void SavePart(EAniBodyPart eAniBodyPart,int time)
+        {
+            switch (eAniBodyPart)
+            {
+                case EAniBodyPart.None:
+                    break;
+                case EAniBodyPart.Head:
+                    break;
+                case EAniBodyPart.Node:
+                    
+                    break;
+                case EAniBodyPart.Xiong:
+
+                    break;
+                case EAniBodyPart.Yao:
+                    break;
+                case EAniBodyPart.FuBu:
+                    break;
+                case EAniBodyPart.LefftHand:
+                    break;
+                case EAniBodyPart.RightHand:
+                    break;
+                case EAniBodyPart.LeftArm:
+                    break;
+                case EAniBodyPart.RightArm:
+                    break;
+                case EAniBodyPart.LeftLeg:
+                    break;
+                case EAniBodyPart.RightLeg:
+                    break;
+                case EAniBodyPart.All:
+                    break;
+
+            }
+        }
+        public void Clear() {
+
+            GameEntry.Event.Unsubscribe(AniEventArgs.EventId, UpdateAni);
+        }
+        // Update is called once per frame
+        void Update()
+        {
+
+        }
+    }
+    public class BonePicTarget
+    {
+        public Transform bone;
+        public Transform pic;
+        public Transform target;
+        public BonePicTarget(Transform _bone, Transform _pic, Transform _target)
+        {
+            bone = _bone;
+            pic = _pic;
+            target = _target;
+        }
+    }
+    public enum EIKPickOnButtonStyple
+    {
+        None,
+        Choose,
+        Rotate,
+        Move
+    }
+    public enum EAniBodyPart {
+    None,
+    Head,
+    Node,
+    Xiong,
+    Yao,
+    FuBu,
+    LeftArm,
+    RightArm,
+    LefftHand,
+    RightHand,
+    LeftLeg,
+    RightLeg,
+    All,
+    }
+    public class BoneData {
+        public string Name;
+        public Dictionary<int, Quaternion> Ro;
+        public Dictionary<int, Vector3> Pos;
+    }
+}

+ 11 - 0
Assets/GameMain/Scripts/AnimationMaker/AniManager.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5f252e774208d9849ab46bc05249016b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 67 - 0
Assets/GameMain/Scripts/AnimationMaker/AniPickOnImage.cs

@@ -0,0 +1,67 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+namespace MetaClient
+{
+    public class AniPickOnImage : MonoBehaviour
+    {
+        public AniManager bonePicture;
+        public BonePicTarget bonePicTarget;
+        void Start()
+        {
+            if (this.gameObject.GetComponent<Button>() == null)
+            {
+                Button _button = this.gameObject.AddComponent<Button>();
+                _button.onClick.AddListener(PickOn);
+            }
+        }
+        public void PickOn()
+        {
+            if (bonePicture.eIKPickOnButtonStyple == EIKPickOnButtonStyple.None || bonePicture.eIKPickOnButtonStyple == EIKPickOnButtonStyple.Choose)
+            {
+                Image _image = this.gameObject.GetComponent<Image>();
+                int _index = bonePicture.chooseImage.IndexOf(bonePicTarget);
+                if (_index == -1)
+                {
+                    if (bonePicture.chooseImage.Count == 0)
+                    {
+                        Choose();
+                    }
+                    else
+                    {
+                        Transform _bonePar = bonePicture.chooseImage[bonePicture.chooseImage.Count - 1].bone;
+                        foreach (Transform child in _bonePar)
+                        {
+                            if (child == bonePicTarget.bone)
+                            {
+                                Choose();
+                            }
+                        }
+
+                    }
+                }
+                else
+                {
+                    Cancel();
+                }
+            }
+        }
+
+        public void Choose()
+        {
+            Image _image = this.gameObject.GetComponent<Image>();
+            bonePicture.chooseImage.Add(bonePicTarget);
+            _image.color = Color.blue;
+
+        }
+        public void Cancel()
+        {
+            Image _image = this.gameObject.GetComponent<Image>();
+            int _index = bonePicture.chooseImage.IndexOf(bonePicTarget);
+            bonePicture.chooseImage.RemoveAt(_index);
+            _image.color = Color.red;
+        }
+
+    }
+}

+ 11 - 0
Assets/GameMain/Scripts/AnimationMaker/AniPickOnImage.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: afe1f2b44b55c2840b7934786dfb320d
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 293 - 0
Assets/GameMain/Scripts/AnimationMaker/AniRoByTime.cs

@@ -0,0 +1,293 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System.Linq;
+namespace MetaClient
+{
+    public class AniRoByTime : MonoBehaviour
+    {
+        public Dictionary<int, Quaternion> dicRo = new Dictionary<int, Quaternion>();
+        public Dictionary<int,Vector3> pos = new Dictionary<int,Vector3>();
+        private Quaternion initRo = new Quaternion();
+        private Vector3 initPos = new Vector3();
+        private int startTime = 0;
+        private Vector3 startPos = new Vector3();
+        private Vector3 endPos = new Vector3();
+        private Quaternion startRo = new Quaternion();
+        private int endTime = 0;
+        private Quaternion endRo = new Quaternion();
+        private List<Quaternion> mList = new List<Quaternion>();
+        private int lasttime = 0;
+        public AniManager aniManager;
+        public bool allBody=false;
+        // Start is called before the first frame update
+        void Start()
+        {
+          
+        }
+        public void Init()
+        {
+            if (this.gameObject.name == aniManager.nowAniName)
+            {
+                allBody = true;
+                initRo = this.gameObject.transform.localRotation;
+                initPos = this.gameObject.transform.localPosition;
+            }
+            else
+            {
+                initRo = this.gameObject.transform.parent.localRotation;
+            }
+        }
+        public void DicOrderBy()
+        {
+            Dictionary<int, Quaternion> newdic = dicRo.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value);
+            dicRo = newdic;
+            Dictionary<int,Vector3> newpos=pos.OrderBy(o => o.Key).ToDictionary(o => o.Key, p => p.Value);
+            pos = newpos;
+        }
+
+        public void RoAllBodyChangeFun(int _time)
+        {
+            startTime = 0;
+            startRo = initRo;
+            startPos = initPos;
+            endPos = initPos;
+            endTime = 0;
+            endRo = initRo;
+            lasttime = -1;
+            if (dicRo.Count == 0)
+            {
+                // return;
+                this.gameObject.transform.localRotation = initRo;
+                this.gameObject.transform.localPosition = initPos;
+
+                return;
+            }
+            else if (dicRo.Count == 1)
+            {
+                mList = new List<Quaternion>();
+                var value = dicRo.Values.GetEnumerator();
+                value.MoveNext();
+                var valuePos = pos.Values.GetEnumerator();
+                valuePos.MoveNext();
+                this.gameObject.transform.localRotation = value.Current;
+                this.gameObject.transform.localPosition = valuePos.Current;
+            }
+            else
+            {
+                mList = new List<Quaternion>();
+                var value = dicRo.Keys.GetEnumerator();
+                var valuePos = pos.Values.GetEnumerator();
+                while (value.MoveNext())
+                {
+                    valuePos.MoveNext();
+                    int data = value.Current;
+                    if (_time < data)
+                    {
+                        endTime = data;
+                        endRo = dicRo[endTime];
+                        endPos = pos[endTime];
+                        if (lasttime != -1)
+                        {
+                            startTime = lasttime;
+                            startRo = dicRo[lasttime];
+                            startPos = pos[lasttime];
+                            RoAllBodyChange(_time);
+                        }
+                        else
+                        {
+                            if (dicRo.ContainsKey(lasttime))
+                            {
+                                this.gameObject.transform.localRotation = dicRo[lasttime];
+                                this.gameObject.transform.localPosition = pos[lasttime];
+                            }
+                            else
+                            {
+                                this.gameObject.transform.localPosition = endPos;
+                            }
+                            return;
+                            //startTime = endTime;
+                            //startRo = endRo;
+                        }
+                    }
+                    else
+                    {
+                        lasttime = value.Current;
+
+                    }
+                }
+            }
+        }
+
+
+
+
+
+
+
+
+
+        public void RoChangeFun(int _time)
+        {
+            if (allBody)
+            {
+                RoAllBodyChangeFun(_time);
+                return;
+            }
+            startTime = 0;
+            startRo = initRo;
+            endTime = 0;
+            endRo = initRo;
+            lasttime = -1;
+            if (dicRo.Count == 0)
+            {
+                // return;
+                this.gameObject.transform.parent.localRotation = initRo;
+                return;
+            }
+            else if (dicRo.Count == 1)
+            {
+                //List<Quaternion> mList;
+                mList = new List<Quaternion>();
+                var value = dicRo.Values.GetEnumerator();
+                value.MoveNext();
+                this.gameObject.transform.parent.localRotation = value.Current;
+                //while (value.MoveNext())
+                //{
+                //    Quaternion data = value.Current;
+                //    mList.Add(data);
+                //}
+                //this.gameObject.transform.localEulerAngles = dicRo;
+            }
+            else
+            {
+                mList = new List<Quaternion>();
+                var value = dicRo.Keys.GetEnumerator();
+                while (value.MoveNext())
+                {
+                    int data = value.Current;
+                    if (_time < data)
+                    {
+                        endTime = data;
+                        endRo = dicRo[endTime];
+                        if (lasttime != -1)
+                        {
+                            startTime = lasttime;
+                            startRo = dicRo[lasttime];
+                            RoChange(_time);
+                        }
+                        else
+                        {
+                            if (dicRo.ContainsKey(lasttime))
+                            {
+                                this.gameObject.transform.parent.localRotation = dicRo[lasttime];
+                            }
+                            else
+                            {
+                                this.gameObject.transform.parent.localRotation = endRo;
+                            }
+                            return;
+                            //startTime = endTime;
+                            //startRo = endRo;
+                        }
+                    }
+                    else
+                    {
+                        lasttime = value.Current;
+
+                    }
+                }
+            }
+        }
+
+
+
+
+        public void RoAllBodyChange(int _time)
+        {
+            Quaternion _nextRo = new Quaternion();
+            Vector3 _nextPos = new Vector3();
+            if (endTime <= _time)
+            {
+                this.gameObject.transform.localRotation = endRo;
+                this.gameObject.transform.localPosition = endPos;
+                return;
+            }
+            else if (endTime == startTime)
+            {
+                this.gameObject.transform.localRotation = endRo;
+                this.gameObject.transform.localPosition = endPos;
+                return;
+            }
+            _nextRo = Quaternion.Lerp(endRo, startRo, (endTime - _time) / (endTime - startTime));
+            Debug.Log("结束旋转" + endRo + "");
+            Debug.Log("开始旋转" + startRo + "");
+            this.gameObject.transform.localRotation = _nextRo;
+            _nextPos =Vector3.Lerp(endPos, startPos, (endTime - _time) / (endTime - startTime));
+            Debug.Log("结束距离" + endPos + "");
+            Debug.Log("开始距离" + startPos + "");
+            this.gameObject.transform.localPosition = _nextPos;
+        }
+
+
+
+
+
+
+
+
+
+
+
+        public void RoChange(int _time)
+        {
+            Quaternion _nextRo = new Quaternion();
+            if (endTime <= _time)
+            {
+                this.gameObject.transform.parent.localRotation = endRo;
+                return;
+            }
+            else if (endTime == startTime)
+            {
+                this.gameObject.transform.parent.localRotation = endRo;
+                return;
+            }
+            _nextRo = Quaternion.Lerp(endRo, startRo, (endTime - _time) / (endTime - startTime));
+            Debug.Log("结束距离" + endRo + "");
+            Debug.Log("开始距离" + startRo + "");
+            this.gameObject.transform.parent.localRotation = _nextRo;
+        }
+        public void DicAdd(int _time)
+        {
+            if (allBody)
+            {
+                if (dicRo.ContainsKey(_time))
+                {
+                    dicRo[_time] = this.gameObject.transform.localRotation;
+                    pos[_time] = this.gameObject.transform.localPosition;
+                }
+                else
+                {
+                    dicRo.Add(_time, this.gameObject.transform.localRotation);
+                    pos[_time] = this.gameObject.transform.localPosition;
+                }
+            }
+            else
+            {
+                if (dicRo.ContainsKey(_time))
+                {
+                    dicRo[_time] = this.gameObject.transform.parent.localRotation;
+                }
+                else
+                {
+                    dicRo.Add(_time, this.gameObject.transform.parent.localRotation);
+                }
+            }
+        }
+        // Update is called once per frame
+        void Update()
+        {
+
+        }
+    }
+}

+ 11 - 0
Assets/GameMain/Scripts/AnimationMaker/AniRoByTime.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b61bab7347012824a813529e0d20037b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 31 - 0
Assets/GameMain/Scripts/UI/UIAMLayaoutGrid.cs

@@ -0,0 +1,31 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+namespace MetaClient
+{
+    public class UIAMLayaoutGrid : MonoBehaviour
+    {
+        public int line = 0;
+        public int column = 0;
+        public float childWidth = 10;
+        public float childHeight = 10;
+        public List<int> data = new List<int>();
+        public List<GameObject> objs = new List<GameObject>();
+        public GameObject Item;
+        public float parWidth = 0;
+        public float parHeight = 0;
+
+        // Start is called before the first frame update
+        void Start()
+        {
+
+        }
+
+        // Update is called once per frame
+        void Update()
+        {
+
+        }
+
+    }
+}

+ 11 - 0
Assets/GameMain/Scripts/UI/UIAMLayaoutGrid.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0a093fdfb6e7341499d458042bac5551
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 50 - 4
Assets/GameMain/Scripts/UI/UIAnimationMaker.cs

@@ -17,7 +17,6 @@ namespace MetaClient
         [SerializeField]
         [SerializeField]
         [Header("旋转X或Y")]
         [Header("旋转X或Y")]
         protected List<Transform> rotateXY=new List<Transform>();
         protected List<Transform> rotateXY=new List<Transform>();
-
         protected Transform topView;
         protected Transform topView;
         protected Transform commonBtnView;
         protected Transform commonBtnView;
         protected Transform seniorView;
         protected Transform seniorView;
@@ -30,9 +29,10 @@ namespace MetaClient
         protected Transform zhenBgList;
         protected Transform zhenBgList;
         protected Transform bodyZhenList;
         protected Transform bodyZhenList;
         protected Transform zhenList;
         protected Transform zhenList;
-
+        protected Text zhenTimeText;
         protected float nowTime = 0;//当前帧
         protected float nowTime = 0;//当前帧
         protected float finalTime = 0;//末尾帧
         protected float finalTime = 0;//末尾帧
+        protected float smallBiLi = 1;
         protected override void OnOpen(object userData)
         protected override void OnOpen(object userData)
         {
         {
 
 
@@ -57,14 +57,23 @@ namespace MetaClient
             ButtonFromTransform(commonBtnView.GetChild(1)).onClick.AddListener(MusicBtnFun);
             ButtonFromTransform(commonBtnView.GetChild(1)).onClick.AddListener(MusicBtnFun);
             ButtonFromTransform(commonBtnView.GetChild(2)).onClick.AddListener(FullScreenBtnFun);
             ButtonFromTransform(commonBtnView.GetChild(2)).onClick.AddListener(FullScreenBtnFun);
             ButtonFromTransform(commonBtnView.GetChild(2)).onClick.AddListener(PlayBtnFun);
             ButtonFromTransform(commonBtnView.GetChild(2)).onClick.AddListener(PlayBtnFun);
+            Transform bottomBg = FindChildByName(this.gameObject.transform, "BottomBg");
+            ButtonFromTransform(bottomBg.GetChild(0)).onClick.AddListener(StartKBtnFun);
+            ButtonFromTransform(bottomBg.GetChild(1)).onClick.AddListener(EndKBtnFun);
+            ButtonFromTransform(bottomBg.GetChild(3)).onClick.AddListener(DelectBtnFun);
+            ButtonFromTransform(bottomBg.GetChild(4)).onClick.AddListener(CopyBtnFun);
+            ButtonFromTransform(bottomBg.GetChild(5)).onClick.AddListener(NextKBtnFun);
+            ButtonFromTransform(bottomBg.GetChild(6)).onClick.AddListener(LastKBtnFun);
+            zhenTimeText = bottomBg.GetChild(7).GetChild(0).gameObject.GetComponent<Text>();
+            zhenTimeText.text = nowTime+"";
+            
             //FindButtonByName(this.gameObject.transform, "BackBtn").onClick.AddListener(SaveBtnFun);
             //FindButtonByName(this.gameObject.transform, "BackBtn").onClick.AddListener(SaveBtnFun);
             //FindButtonByName(this.gameObject.transform, "MusicBtn").onClick.AddListener(MusicBtnFun);
             //FindButtonByName(this.gameObject.transform, "MusicBtn").onClick.AddListener(MusicBtnFun);
             //FindButtonByName(this.gameObject.transform, "FullScreenBtn").onClick.AddListener(FullScreenBtnFun);
             //FindButtonByName(this.gameObject.transform, "FullScreenBtn").onClick.AddListener(FullScreenBtnFun);
             //FindButtonByName(this.gameObject.transform, "PlayBtn").onClick.AddListener(PlayBtnFun);
             //FindButtonByName(this.gameObject.transform, "PlayBtn").onClick.AddListener(PlayBtnFun);
-            seniorView= FindChildByName(this.gameObject.transform, "Senior");
+            seniorView = FindChildByName(this.gameObject.transform, "Senior");
             extraView = FindChildByName(this.gameObject.transform, "Extra");
             extraView = FindChildByName(this.gameObject.transform, "Extra");
 
 
-
         }
         }
         protected void SceneDressFun() {
         protected void SceneDressFun() {
         
         
@@ -80,6 +89,16 @@ namespace MetaClient
         {
         {
             
             
         }
         }
+
+        protected void CreateZhenListFun()
+        {
+            
+        }
+
+
+
+
+
         /// <summary>
         /// <summary>
         /// 保存按钮
         /// 保存按钮
         /// </summary>
         /// </summary>
@@ -88,6 +107,11 @@ namespace MetaClient
             
             
 
 
         }
         }
+
+
+
+
+
         /// <summary>
         /// <summary>
         /// 音乐按钮
         /// 音乐按钮
         /// </summary>
         /// </summary>
@@ -124,6 +148,28 @@ namespace MetaClient
         
         
         }
         }
 
 
+        protected void DelectBtnFun()
+        { 
+        }
+        protected void CopyBtnFun()
+        { 
+        }
+
+
+        protected void StartKBtnFun() {
+        
+        }
+
+        protected void EndKBtnFun() {
+        
+        }
+
+
+
+
+
+
+
         /// <summary>
         /// <summary>
         /// 下一帧
         /// 下一帧
         /// </summary>
         /// </summary>

+ 2 - 1
Assets/GameMain/Scripts/UI/UICustomBtn.cs

@@ -65,7 +65,7 @@ namespace MetaClient
                     uICustom.PickOnButton(this.gameObject,id);
                     uICustom.PickOnButton(this.gameObject,id);
                     break;
                     break;
                 case EButtonStyple.TiaoSe:
                 case EButtonStyple.TiaoSe:
-                    uICustom.SetColor(id, eCustomStyple);
+                    //uICustom.SetColor(id, eCustomStyple);
                     TiaoSeFun();
                     TiaoSeFun();
                     break;
                     break;
                 case EButtonStyple.NorButton:
                 case EButtonStyple.NorButton:
@@ -87,6 +87,7 @@ namespace MetaClient
                     break;
                     break;
                 case ETSStyple.ViewOpen:
                 case ETSStyple.ViewOpen:
                    uICustom.TiaoSeViewOpenFun();
                    uICustom.TiaoSeViewOpenFun();
+                    uICustom.SetColor(id, eCustomStyple);
                     break;
                     break;
                 case ETSStyple.Close:
                 case ETSStyple.Close:
                    uICustom.TiaoSeBanOpenStyple(false);
                    uICustom.TiaoSeBanOpenStyple(false);

Файловите разлики са ограничени, защото са твърде много
+ 2217 - 927
Assets/GameMain/UI/UIForms/AnimationMaker.prefab


+ 8 - 0
Assets/Plugins.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 4565851218d89ce48bd7db1dba7df622
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/Plugins/RootMotion.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: dbc1ad9c74684d04a819ae36e2b3bd2a
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Plugins/RootMotion/Baker.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 47bf04154c11c5e45b94b1aec2c0baf6
+folderAsset: yes
+timeCreated: 1516620867
+licenseType: Store
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Plugins/RootMotion/Baker/Scripts.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 8d2079bf8fd63d640a121f8fea6f5c5f
+folderAsset: yes
+timeCreated: 1516620916
+licenseType: Store
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 498 - 0
Assets/Plugins/RootMotion/Baker/Scripts/Baker.cs

@@ -0,0 +1,498 @@
+using UnityEngine;
+using System.Collections;
+using UnityEngine.Playables;
+
+#if UNITY_EDITOR
+using UnityEditor;
+#endif
+
+namespace RootMotion
+{
+    /// <summary>
+    /// Base class for animation bakers, handles timing, keyframing and saving AnimationClips.
+    /// </summary>
+    [HelpURL("http://www.root-motion.com/finalikdox/html/page3.html")]
+    [AddComponentMenu("Scripts/RootMotion/Baker")]
+    public abstract class Baker : MonoBehaviour
+    {
+
+        // Open the User Manual URL
+        [ContextMenu("User Manual")]
+        void OpenUserManual()
+        {
+            Application.OpenURL("http://www.root-motion.com/finalikdox/html/page3.html");
+        }
+
+        // Open the Script Reference URL
+        [ContextMenu("Scrpt Reference")]
+        void OpenScriptReference()
+        {
+            Application.OpenURL("http://www.root-motion.com/finalikdox/html/class_root_motion_1_1_baker.html");
+        }
+
+        // Link to the Final IK Google Group
+        [ContextMenu("Support Group")]
+        void SupportGroup()
+        {
+            Application.OpenURL("https://groups.google.com/forum/#!forum/final-ik");
+        }
+
+        // Link to the Final IK Asset Store thread in the Unity Community
+        [ContextMenu("Asset Store Thread")]
+        void ASThread()
+        {
+            Application.OpenURL("http://forum.unity3d.com/threads/final-ik-full-body-ik-aim-look-at-fabrik-ccd-ik-1-0-released.222685/");
+        }
+
+        [System.Serializable]
+        public enum Mode
+        {
+            AnimationClips = 0,
+            AnimationStates = 1,
+            PlayableDirector = 2,
+            Realtime = 3
+        }
+
+        /// <summary>
+        /// In AnimationClips, AnimationStates or PlayableDirector mode - the frame rate at which the animation clip will be sampled. In Realtime mode - the frame rate at which the pose will be sampled. With the latter, the frame rate is not guaranteed if the player is not able to reach it.
+        /// </summary>
+        [Tooltip("In AnimationClips, AnimationStates or PlayableDirector mode - the frame rate at which the animation clip will be sampled. In Realtime mode - the frame rate at which the pose will be sampled. With the latter, the frame rate is not guaranteed if the player is not able to reach it.")]
+        [Range(1, 90)] public int frameRate = 30;
+
+        /// <summary>
+        /// Maximum allowed error for keyframe reduction.
+        /// </summary>
+        [Tooltip("Maximum allowed error for keyframe reduction.")]
+        [Range(0f, 0.1f)] public float keyReductionError = 0.01f;
+
+        /// <summary>
+        /// AnimationClips mode can be used to bake a batch of AnimationClips directly without the need of setting up an AnimatorController. AnimationStates mode is useful for when you need to set up a more complex rig with layers and AvatarMasks in Mecanim. PlayableDirector mode bakes a Timeline. Realtime mode is for continuous baking of gameplay, ragdoll phsysics or PuppetMaster dynamics.
+        /// </summary>
+        [Tooltip("AnimationClips mode can be used to bake a batch of AnimationClips directly without the need of setting up an AnimatorController. " +
+            "AnimationStates mode is useful for when you need to set up a more complex rig with layers and AvatarMasks in Mecanim. " +
+            "PlayableDirector mode bakes a Timeline. " +
+            "Realtime mode is for continuous baking of gameplay, ragdoll phsysics or PuppetMaster dynamics.")]
+        public Mode mode;
+
+        /// <summary>
+        /// AnimationClips to bake.
+        /// </summary>
+        [Tooltip("AnimationClips to bake.")]
+        public AnimationClip[] animationClips = new AnimationClip[0];
+
+        /// <summary>
+        /// The name of the AnimationStates to bake (must be on the base layer) in the Animator (Right-click on this component header and select 'Find Animation States' to have Baker fill those in automatically, required that state names match with the names of the clips used in them).
+        /// </summary>
+        [Tooltip("The name of the AnimationStates to bake (must be on the base layer) in the Animator above (Right-click on this component header and select 'Find Animation States' to have Baker fill those in automatically, required that state names match with the names of the clips used in them).")]
+        public string[] animationStates = new string[0];
+
+        /// <summary>
+        /// Sets the baked animation clip to loop time and matches the last frame keys with the first. Note that if you are overwriting a previously baked clip, AnimationClipSettings will be copied from the existing clip.
+        /// </summary>
+        [Tooltip("Sets the baked animation clip to loop time and matches the last frame keys with the first. Note that when overwriting a previously baked clip, AnimationClipSettings will be copied from the existing clip.")]
+        public bool loop = true;
+
+        /// <summary>
+        /// The folder to save the baked AnimationClips to.
+        /// </summary>
+        [Tooltip("The folder to save the baked AnimationClips to.")]
+        public string saveToFolder = "Assets";
+
+        /// <summary>
+        /// String that will be added to each clip or animation state name for the saved clip. For example if your animation state/clip names were 'Idle' and 'Walk', then with '_Baked' as Append Name, the Baker will create 'Idle_Baked' and 'Walk_Baked' animation clips.
+        /// </summary>
+        [Tooltip("String that will be added to each clip or animation state name for the saved clip. For example if your animation state/clip names were 'Idle' and 'Walk', then with '_Baked' as Append Name, the Baker will create 'Idle_Baked' and 'Walk_Baked' animation clips.")]
+        public string appendName = "_Baked";
+
+        /// <summary>
+        /// Name of the created AnimationClip file.
+        /// </summary>
+        [Tooltip("Name of the created AnimationClip file.")]
+        public string saveName = "Baked Clip";
+
+        public bool isBaking { get; private set; }
+        public float bakingProgress { get; private set; }
+
+        [HideInInspector] public Animator animator;
+        [HideInInspector] public PlayableDirector director;
+
+        protected abstract Transform GetCharacterRoot();
+        protected abstract void OnStartBaking();
+        protected abstract void OnSetLoopFrame(float time);
+        protected abstract void OnSetCurves(ref AnimationClip clip);
+        protected abstract void OnSetKeyframes(float time, bool lastFrame);
+        protected float clipLength { get; private set; }
+
+#if UNITY_EDITOR
+        private AnimationClip[] bakedClips = new AnimationClip[0];
+
+        private AnimatorStateInfo currentClipStateInfo;
+        private int currentClipIndex;
+
+        private float startBakingTime;
+        private float nextKeyframeTime;
+        private bool firstFrame;
+        private int clipFrames;
+        private int clipFrameNo;
+        private bool setKeyframes;
+
+        private float currentClipTime;
+        private float clipFrameInterval;
+
+        private const bool setLoopFrame = true; // Makes sure first and last keyframes in the baked clip match up if baking a looping clip.
+#endif
+
+        // Start baking an animation state, clip or timeline, also called for each next clip in the baking array
+        public void BakeClip()
+        {
+#if UNITY_EDITOR
+            switch (mode)
+            {
+                case Mode.AnimationClips:
+                    AnimationClipSettings originalSettings = AnimationUtility.GetAnimationClipSettings(animationClips[currentClipIndex]);
+                    loop = originalSettings.loopTime;
+                    break;
+            }
+
+            StartBaking();
+#endif
+        }
+
+        public void StartBaking()
+        {
+#if UNITY_EDITOR
+
+            isBaking = true;
+            nextKeyframeTime = 0f;
+
+            bakingProgress = 0f;
+            clipFrameNo = 0;
+
+            if (bakedClips.Length == 0)
+            {
+                switch (mode)
+                {
+                    case Mode.AnimationClips:
+                        bakedClips = new AnimationClip[animationClips.Length];
+                        break;
+                    case Mode.AnimationStates:
+                        bakedClips = new AnimationClip[animationStates.Length];
+                        break;
+                    default:
+                        bakedClips = new AnimationClip[1];
+                        break;
+                }
+            }
+
+            OnStartBaking();
+
+            firstFrame = true;
+
+#endif
+        }
+
+        public void StopBaking()
+        {
+#if UNITY_EDITOR
+
+            if (!isBaking) return;
+
+            if (mode != Mode.Realtime && loop && setLoopFrame)
+            {
+                OnSetLoopFrame(clipLength);
+            }
+
+            bakedClips[currentClipIndex] = new AnimationClip();
+            bakedClips[currentClipIndex].frameRate = frameRate;
+
+            OnSetCurves(ref bakedClips[currentClipIndex]);
+
+            bakedClips[currentClipIndex].EnsureQuaternionContinuity();
+
+            if (mode == Mode.Realtime)
+            {
+                isBaking = false;
+                SaveClips();
+            }
+
+#endif
+        }
+
+#if UNITY_EDITOR
+
+        [ContextMenu("Find Animation States")]
+        public void FindAnimationStates()
+        {
+            animator = GetComponent<Animator>();
+            if (animator == null)
+            {
+                Debug.LogError("No Animator found on Baker GameObject. Can not find animation states.");
+                return;
+            }
+
+            if (animator.runtimeAnimatorController == null)
+            {
+                Debug.LogError("Animator does not have a valid Controller. Can not find animation states.");
+                return;
+            }
+
+            var clips = animator.runtimeAnimatorController.animationClips;
+            animationStates = new string[clips.Length];
+            for (int i = 0; i < clips.Length; i++)
+            {
+                animationStates[i] = clips[i].name;
+            }
+        }
+
+        void Update()
+        {
+            // Baking procedure
+            if (isBaking)
+            {
+                if (mode != Mode.Realtime)
+                {
+                    if (firstFrame)
+                    {
+                        transform.position = Vector3.zero;
+                        transform.rotation = Quaternion.identity;
+                        GetCharacterRoot().position = Vector3.zero;
+                        GetCharacterRoot().rotation = Quaternion.identity;
+
+                        StartAnimationUpdate();
+
+                        currentClipTime = 0f;
+                        firstFrame = false;
+                    }
+
+                    switch (mode)
+                    {
+                        case Mode.AnimationClips:
+                            clipLength = animationClips[currentClipIndex].length;
+                            bakingProgress = currentClipTime / clipLength;
+                            break;
+                        case Mode.AnimationStates:
+                            currentClipStateInfo = animator.GetCurrentAnimatorStateInfo(0);
+                            bakingProgress = currentClipStateInfo.normalizedTime;
+
+                            if (currentClipStateInfo.speed <= 0f)
+                            {
+                                Debug.LogError("Baker can not bake a clip with 0 speed.");
+                                return;
+                            }
+
+                            clipLength = currentClipStateInfo.length / currentClipStateInfo.speed / animator.speed;
+                            break;
+                        case Mode.PlayableDirector:
+                            clipLength = (float)director.duration;
+                            bakingProgress = (float)director.time / clipLength;
+                            break;
+                    }
+
+                    clipFrames = (int)(clipLength * (frameRate));
+                    clipFrameInterval = clipLength / (float)(clipFrames);
+                    setKeyframes = true;
+
+                    // Stop clip baking if the clip is finished, start baking the next clip if possible
+                    if (clipFrameNo > clipFrames)
+                    {
+                        StopBaking();
+
+                        currentClipIndex++;
+                        if (currentClipIndex >= bakedClips.Length)
+                        {
+                            currentClipIndex = 0;
+                            StopAnimationUpdate();
+                            isBaking = false;
+
+                            SaveClips();
+
+                            return;
+                        }
+                        else
+                        {
+                            BakeClip();
+                            setKeyframes = false;
+                        }
+                    }
+
+                    if (!firstFrame) AnimationUpdate();
+                }
+            }
+        }
+
+        void LateUpdate()
+        {
+            if (!isBaking) return;
+
+            if (mode != Mode.Realtime)
+            {
+                if (setKeyframes)
+                {
+                    OnSetKeyframes(clipFrameNo * clipFrameInterval, clipFrameNo >= clipFrames);
+
+                    clipFrameNo++;
+                    setKeyframes = false;
+                }
+            }
+            else
+            {
+                if (firstFrame)
+                {
+                    startBakingTime = Time.time;
+                    firstFrame = false;
+                }
+
+                if (Time.time < nextKeyframeTime) return;
+
+                OnSetKeyframes(Time.time - startBakingTime, false);
+
+                nextKeyframeTime = Time.time + (1f / (float)frameRate);
+            }
+
+        }
+
+        private void StartAnimationUpdate()
+        {
+            switch (mode)
+            {
+                case Mode.AnimationClips:
+                    if (!AnimationMode.InAnimationMode()) AnimationMode.StartAnimationMode();
+                    AnimationMode.BeginSampling();
+                    AnimationMode.SampleAnimationClip(gameObject, animationClips[currentClipIndex], 0f);
+                    AnimationMode.EndSampling();
+                    break;
+                case Mode.AnimationStates:
+                    animator.enabled = false;
+                    animator.Play(animationStates[currentClipIndex], 0, 0f);
+                    break;
+                case Mode.PlayableDirector:
+                    director.enabled = false;
+                    director.time = 0f;
+                    director.Evaluate();
+                    break;
+            }
+        }
+
+        private void StopAnimationUpdate()
+        {
+            switch (mode)
+            {
+                case Mode.AnimationClips:
+                    if (AnimationMode.InAnimationMode()) AnimationMode.StopAnimationMode();
+                    break;
+                case Mode.AnimationStates:
+                    animator.enabled = true;
+                    break;
+                case Mode.PlayableDirector:
+                    director.enabled = true;
+                    break;
+            }
+        }
+
+        private void AnimationUpdate()
+        {
+            switch (mode)
+            {
+                case Mode.AnimationClips:
+
+                    if (!AnimationMode.InAnimationMode()) AnimationMode.StartAnimationMode();
+                    AnimationMode.BeginSampling();
+                    AnimationMode.SampleAnimationClip(gameObject, animationClips[currentClipIndex], currentClipTime);
+                    AnimationMode.EndSampling();
+                    currentClipTime += clipFrameInterval;
+                    break;
+                case Mode.AnimationStates:
+                    animator.Update(clipFrameInterval);
+                    break;
+                case Mode.PlayableDirector:
+                    director.time = currentClipTime;
+                    director.Evaluate();
+                    currentClipTime += clipFrameInterval;
+                    break;
+            }
+        }
+
+        public void SaveClips()
+        {
+            var clips = GetBakedClips();
+            AnimationClip savedClip = null;
+
+            for (int i = 0; i < clips.Length; i++)
+            {
+                string path = GetFullPath(i);
+
+                switch (mode)
+                {
+                    case Baker.Mode.Realtime: break;
+                    case Baker.Mode.AnimationClips:
+                        AnimationClipSettings originalSettings = AnimationUtility.GetAnimationClipSettings(animationClips[i]);
+                        SetClipSettings(clips[i], originalSettings);
+                        AnimationUtility.SetAnimationClipSettings(clips[i], originalSettings);
+                        break;
+                    default:
+                        AnimationClipSettings settings = AnimationUtility.GetAnimationClipSettings(clips[i]);
+                        settings.loopTime = loop;
+                        SetClipSettings(clips[i], settings);
+                        AnimationUtility.SetAnimationClipSettings(clips[i], settings);
+                        break;
+                }
+
+                var existing = AssetDatabase.LoadAssetAtPath(path, typeof(AnimationClip)) as AnimationClip;
+                if (existing != null)
+                {
+                    // Overwrite with existing settings
+                    AnimationClipSettings existingSettings = AnimationUtility.GetAnimationClipSettings(existing);
+                    existingSettings.stopTime = clips[i].length;
+                    AnimationUtility.SetAnimationClipSettings(clips[i], existingSettings);
+                    EditorUtility.CopySerialized(clips[i], existing);
+                }
+                else
+                {
+                    // Create new asset
+                    AssetDatabase.CreateAsset(clips[i], path);
+                }
+
+                AssetDatabase.SaveAssets();
+                AssetDatabase.Refresh();
+
+                savedClip = AssetDatabase.LoadAssetAtPath(path, typeof(AnimationClip)) as AnimationClip;
+
+                Debug.Log(path + " successfully baked.");
+            }
+
+            Selection.activeObject = savedClip;
+
+            ClearBakedClips();
+        }
+
+        protected virtual void SetClipSettings(AnimationClip clip, AnimationClipSettings settings) {}
+
+        private string GetFullPath(int clipIndex)
+        {
+            switch (mode)
+            {
+                case Baker.Mode.AnimationClips:
+                    return saveToFolder + "/" + animationClips[clipIndex].name + appendName + ".anim";
+                case Baker.Mode.AnimationStates:
+                    return saveToFolder + "/" + animationStates[clipIndex] + appendName + ".anim";
+                case Baker.Mode.PlayableDirector:
+                    return saveToFolder + "/" + saveName + ".anim";
+                default:
+                    return saveToFolder + "/" + saveName + ".anim";
+            }
+        }
+
+        private AnimationClip[] GetBakedClips()
+        {
+            return bakedClips;
+        }
+
+        private void ClearBakedClips()
+        {
+            bakedClips = new AnimationClip[0];
+        }
+
+#endif
+
+    }
+}

+ 12 - 0
Assets/Plugins/RootMotion/Baker/Scripts/Baker.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: ab14efce3fefe4f4982f0fa6911d0cd4
+timeCreated: 1516617114
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 134 - 0
Assets/Plugins/RootMotion/Baker/Scripts/GenericBaker.cs

@@ -0,0 +1,134 @@
+using UnityEngine;
+using System.Collections;
+using System;
+
+namespace RootMotion
+{
+    /// <summary>
+    /// Baker for Generic/Legacy animation.
+    /// </summary>
+    public class GenericBaker : Baker
+    {
+        /// <summary>
+        /// If true, produced AnimationClips will be marked as Legacy and usable with the Legacy animation system.
+        /// </summary>
+        [Tooltip("If true, produced AnimationClips will be marked as Legacy and usable with the Legacy animation system.")]
+        public bool markAsLegacy;
+
+        /// <summary>
+        /// Root Transform of the hierarchy to bake.
+        /// </summary>
+        [Tooltip("Root Transform of the hierarchy to bake.")]
+        public Transform root;
+
+        /// <summary>
+        /// Root Node used for root motion.
+        /// </summary>
+        [Tooltip("Root Node used for root motion.")]
+        public Transform rootNode;
+
+        /// <summary>
+        /// List of Transforms to ignore, rotation curves will not be baked for these Transforms.
+        /// </summary>
+        [Tooltip("List of Transforms to ignore, rotation curves will not be baked for these Transforms.")]
+        public Transform[] ignoreList;
+
+        /// <summary>
+        /// LocalPosition curves will be baked for these Transforms only. If you are baking a character, the pelvis bone should be added to this array.
+        /// </summary>
+        [Tooltip("LocalPosition curves will be baked for these Transforms only. If you are baking a character, the pelvis bone should be added to this array.")]
+        public Transform[] bakePositionList;
+
+        private BakerTransform[] children = new BakerTransform[0];
+        private BakerTransform rootChild;
+        private int rootChildIndex = -1;
+
+        void Awake()
+        {
+            // Find all the child Transforms of the Animator
+            Transform[] childrenAndRoot = (Transform[])root.GetComponentsInChildren<Transform>();
+
+            children = new BakerTransform[0];
+
+            // Exlude the ignore list, construct the children array
+            for (int i = 0; i < childrenAndRoot.Length; i++)
+            {
+                if (!IsIgnored(childrenAndRoot[i]))
+                {
+
+                    Array.Resize(ref children, children.Length + 1);
+
+                    bool isRootNode = childrenAndRoot[i] == rootNode;
+                    if (isRootNode) rootChildIndex = children.Length - 1;
+
+                    children[children.Length - 1] = new BakerTransform(childrenAndRoot[i], root, BakePosition(childrenAndRoot[i]), isRootNode);
+                }
+            }
+        }
+
+        protected override Transform GetCharacterRoot()
+        {
+            return root;
+        }
+
+        protected override void OnStartBaking()
+        {
+            for (int i = 0; i < children.Length; i++)
+            {
+                children[i].Reset();
+
+                if (i == rootChildIndex) children[i].SetRelativeSpace(root.position, root.rotation);
+            }
+        }
+
+        protected override void OnSetLoopFrame(float time)
+        {
+            // TODO Change to SetLoopFrame like in HumanoidBaker
+            for (int i = 0; i < children.Length; i++) children[i].AddLoopFrame(time);
+        }
+
+        protected override void OnSetCurves(ref AnimationClip clip)
+        {
+            // TODO Length Multiplier
+
+            for (int i = 0; i < children.Length; i++) children[i].SetCurves(ref clip);
+        }
+
+        protected override void OnSetKeyframes(float time, bool lastFrame)
+        {
+            for (int i = 0; i < children.Length; i++) children[i].SetKeyframes(time);
+        }
+
+        // Is the specified Transform in the ignore list?
+        private bool IsIgnored(Transform t)
+        {
+            for (int i = 0; i < ignoreList.Length; i++)
+            {
+                if (t == ignoreList[i]) return true;
+            }
+            return false;
+        }
+
+        // Should we record the localPosition channels of the Transform? 
+        private bool BakePosition(Transform t)
+        {
+            for (int i = 0; i < bakePositionList.Length; i++)
+            {
+                if (t == bakePositionList[i]) return true;
+            }
+            return false;
+        }
+
+#if UNITY_EDITOR
+        protected override void SetClipSettings(AnimationClip clip, UnityEditor.AnimationClipSettings settings)
+        {
+            clip.legacy = markAsLegacy;
+
+            if (mode != Baker.Mode.AnimationClips)
+            {
+                clip.wrapMode = loop ? WrapMode.Loop : WrapMode.Default;
+            }
+        }
+#endif
+    }
+}

+ 12 - 0
Assets/Plugins/RootMotion/Baker/Scripts/GenericBaker.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 27b32efee52144c4e934e6c3272ceb2c
+timeCreated: 1516356533
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 15001
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Plugins/RootMotion/Baker/Scripts/Helpers.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: e468ef7e80a87f94588b5eeb3a423b91
+folderAsset: yes
+timeCreated: 1516621025
+licenseType: Store
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 90 - 0
Assets/Plugins/RootMotion/Baker/Scripts/Helpers/AvatarUtility.cs

@@ -0,0 +1,90 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using System;
+using System.Reflection;
+
+namespace RootMotion
+{
+    public class TQ
+    {
+        public TQ(Vector3 translation, Quaternion rotation)
+        {
+            t = translation;
+            q = rotation;
+        }
+
+        public Vector3 t;
+        public Quaternion q;
+    }
+
+    /*
+    Written with the kind help of the one commonly known as Mecanim-Dev.
+    */
+    public class AvatarUtility
+    {
+
+        public static Quaternion GetPostRotation(Avatar avatar, AvatarIKGoal avatarIKGoal)
+        {
+            int humanId = (int)HumanIDFromAvatarIKGoal(avatarIKGoal);
+            if (humanId == (int)HumanBodyBones.LastBone) throw new InvalidOperationException("Invalid human id.");
+
+            MethodInfo methodGetPostRotation = typeof(Avatar).GetMethod("GetPostRotation", BindingFlags.Instance | BindingFlags.NonPublic);
+            if (methodGetPostRotation == null) throw new InvalidOperationException("Cannot find GetPostRotation method.");
+
+            return (Quaternion)methodGetPostRotation.Invoke(avatar, new object[] { humanId });
+        }
+
+        /// <summary>
+        /// Get IK position and rotation for foot/hand bone position/rotation.
+        /// </summary>
+        public static TQ GetIKGoalTQ(Avatar avatar, float humanScale, AvatarIKGoal avatarIKGoal, TQ bodyPositionRotation, TQ boneTQ)
+        {
+            int humanId = (int)HumanIDFromAvatarIKGoal(avatarIKGoal);
+            if (humanId == (int)HumanBodyBones.LastBone) throw new InvalidOperationException("Invalid human id.");
+
+            MethodInfo methodGetAxisLength = typeof(Avatar).GetMethod("GetAxisLength", BindingFlags.Instance | BindingFlags.NonPublic);
+            if (methodGetAxisLength == null) throw new InvalidOperationException("Cannot find GetAxisLength method.");
+
+            MethodInfo methodGetPostRotation = typeof(Avatar).GetMethod("GetPostRotation", BindingFlags.Instance | BindingFlags.NonPublic);
+            if (methodGetPostRotation == null) throw new InvalidOperationException("Cannot find GetPostRotation method.");
+
+            Quaternion postRotation = (Quaternion)methodGetPostRotation.Invoke(avatar, new object[] { humanId });
+
+            var goalTQ = new TQ(boneTQ.t, boneTQ.q * postRotation);
+
+
+            if (avatarIKGoal == AvatarIKGoal.LeftFoot || avatarIKGoal == AvatarIKGoal.RightFoot)
+            {
+                // Here you could use animator.leftFeetBottomHeight or animator.rightFeetBottomHeight rather than GetAxisLenght
+                // Both are equivalent but GetAxisLength is the generic way and work for all human bone
+                float axislength = (float)methodGetAxisLength.Invoke(avatar, new object[] { humanId });
+                Vector3 footBottom = new Vector3(axislength, 0, 0);
+                goalTQ.t += (goalTQ.q * footBottom);
+            }
+
+            // IK goal are in avatar body local space
+            Quaternion invRootQ = Quaternion.Inverse(bodyPositionRotation.q);
+            goalTQ.t = invRootQ * (goalTQ.t - bodyPositionRotation.t);
+            goalTQ.q = invRootQ * goalTQ.q;
+            goalTQ.t /= humanScale;
+
+            goalTQ.q = Quaternion.LookRotation(goalTQ.q * Vector3.forward, goalTQ.q * Vector3.up);
+
+            return goalTQ;
+        }
+
+        public static HumanBodyBones HumanIDFromAvatarIKGoal(AvatarIKGoal avatarIKGoal)
+        {
+            HumanBodyBones humanId = HumanBodyBones.LastBone;
+            switch (avatarIKGoal)
+            {
+                case AvatarIKGoal.LeftFoot: humanId = HumanBodyBones.LeftFoot; break;
+                case AvatarIKGoal.RightFoot: humanId = HumanBodyBones.RightFoot; break;
+                case AvatarIKGoal.LeftHand: humanId = HumanBodyBones.LeftHand; break;
+                case AvatarIKGoal.RightHand: humanId = HumanBodyBones.RightHand; break;
+            }
+            return humanId;
+        }
+    }
+}

+ 12 - 0
Assets/Plugins/RootMotion/Baker/Scripts/Helpers/AvatarUtility.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2f9e403f0f8255c42b90254abc55f528
+timeCreated: 1516435305
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 579 - 0
Assets/Plugins/RootMotion/Baker/Scripts/Helpers/BakerUtilities.cs

@@ -0,0 +1,579 @@
+using UnityEngine;
+using System.Collections;
+
+namespace RootMotion
+{
+    public static class BakerUtilities
+    {
+
+        public static void ReduceKeyframes(AnimationCurve curve, float maxError)
+        {
+            if (maxError <= 0f) return;
+
+            curve.keys = GetReducedKeyframes(curve, maxError);
+
+            // TODO Flatten outTangent for keys that have the next key and testAfter sampled to the same value in the original clip. Same thing for the inTangent
+        }
+
+        public static Keyframe[] GetReducedKeyframes(AnimationCurve curve, float maxError)
+        {
+            Keyframe[] keys = curve.keys;
+
+            int i = 1;
+            while (i < keys.Length - 1 && keys.Length > 2)
+            {
+                Keyframe[] testKeys = new Keyframe[keys.Length - 1];
+                int c = 0;
+                for (int n = 0; n < keys.Length; n++)
+                {
+                    if (i != n)
+                    {
+                        testKeys[c] = new Keyframe(keys[n].time, keys[n].value, keys[n].inTangent, keys[n].outTangent);
+                        c++;
+                    }
+                }
+
+                AnimationCurve testCurve = new AnimationCurve();
+                testCurve.keys = testKeys;
+
+                float test0 = Mathf.Abs(testCurve.Evaluate(keys[i].time) - keys[i].value);
+                float beforeTime = keys[i].time + (keys[i - 1].time - keys[i].time) * 0.5f;
+                float afterTime = keys[i].time + (keys[i + 1].time - keys[i].time) * 0.5f;
+
+                float testBefore = Mathf.Abs(testCurve.Evaluate(beforeTime) - curve.Evaluate(beforeTime));
+                float testAfter = Mathf.Abs(testCurve.Evaluate(afterTime) - curve.Evaluate(afterTime));
+
+                if (test0 < maxError && testBefore < maxError && testAfter < maxError)
+                {
+                    keys = testKeys;
+                }
+                else
+                {
+                    i++;
+                }
+            }
+
+            return keys;
+        }
+
+        public static void SetLoopFrame(float time, AnimationCurve curve)
+        {
+            Keyframe[] keys = curve.keys;
+            keys[keys.Length - 1].value = keys[0].value;
+
+            float inTangent = Mathf.Lerp(keys[0].inTangent, keys[keys.Length - 1].inTangent, 0.5f);
+            keys[0].inTangent = inTangent;
+            keys[keys.Length - 1].inTangent = inTangent;
+
+            float outTangent = Mathf.Lerp(keys[0].outTangent, keys[keys.Length - 1].outTangent, 0.5f);
+            keys[0].outTangent = outTangent;
+            keys[keys.Length - 1].outTangent = outTangent;
+
+            keys[keys.Length - 1].time = time;
+            curve.keys = keys;
+        }
+
+        public static void SetTangentMode(AnimationCurve curve)
+        {
+#if UNITY_EDITOR
+
+            if (curve.length < 2) return;
+
+            for (int i = 1; i < curve.length - 1; i++)
+            {
+                UnityEditor.AnimationUtility.SetKeyLeftTangentMode(curve, i, UnityEditor.AnimationUtility.TangentMode.ClampedAuto);
+                UnityEditor.AnimationUtility.SetKeyRightTangentMode(curve, i, UnityEditor.AnimationUtility.TangentMode.ClampedAuto);
+            }
+
+#endif
+        }
+
+        // Realigns quaternion keys to ensure shortest interpolation paths.
+        public static Quaternion EnsureQuaternionContinuity(Quaternion lastQ, Quaternion q)
+        {
+            Quaternion flipped = new Quaternion(-q.x, -q.y, -q.z, -q.w);
+
+            Quaternion midQ = new Quaternion(
+                Mathf.Lerp(lastQ.x, q.x, 0.5f),
+                Mathf.Lerp(lastQ.y, q.y, 0.5f),
+                Mathf.Lerp(lastQ.z, q.z, 0.5f),
+                Mathf.Lerp(lastQ.w, q.w, 0.5f)
+                );
+
+            Quaternion midQFlipped = new Quaternion(
+                Mathf.Lerp(lastQ.x, flipped.x, 0.5f),
+                Mathf.Lerp(lastQ.y, flipped.y, 0.5f),
+                Mathf.Lerp(lastQ.z, flipped.z, 0.5f),
+                Mathf.Lerp(lastQ.w, flipped.w, 0.5f)
+                );
+
+            float angle = Quaternion.Angle(lastQ, midQ);
+            float angleFlipped = Quaternion.Angle(lastQ, midQFlipped);
+
+            return angleFlipped < angle ? flipped : q;
+        }
+    }
+
+    //Manages the Animation Curves for Humanoid Q/T channels.
+    [System.Serializable]
+    public class BakerHumanoidQT
+    {
+
+        private Transform transform;
+        private string Qx, Qy, Qz, Qw;
+        private string Tx, Ty, Tz;
+
+        // Animation curves for each channel of the Transform
+        public AnimationCurve rotX, rotY, rotZ, rotW;
+        public AnimationCurve posX, posY, posZ;
+
+        private AvatarIKGoal goal;
+        private Quaternion lastQ;
+        private bool lastQSet;
+
+        // The custom constructor
+        public BakerHumanoidQT(string name)
+        {
+            Qx = name + "Q.x";
+            Qy = name + "Q.y";
+            Qz = name + "Q.z";
+            Qw = name + "Q.w";
+
+            Tx = name + "T.x";
+            Ty = name + "T.y";
+            Tz = name + "T.z";
+
+            Reset();
+        }
+
+        public BakerHumanoidQT(Transform transform, AvatarIKGoal goal, string name)
+        {
+            this.transform = transform;
+            this.goal = goal;
+
+            Qx = name + "Q.x";
+            Qy = name + "Q.y";
+            Qz = name + "Q.z";
+            Qw = name + "Q.w";
+
+            Tx = name + "T.x";
+            Ty = name + "T.y";
+            Tz = name + "T.z";
+
+            Reset();
+        }
+
+        // Clear all curves
+        public void Reset()
+        {
+            rotX = new AnimationCurve();
+            rotY = new AnimationCurve();
+            rotZ = new AnimationCurve();
+            rotW = new AnimationCurve();
+
+            posX = new AnimationCurve();
+            posY = new AnimationCurve();
+            posZ = new AnimationCurve();
+
+            lastQ = Quaternion.identity;
+            lastQSet = false;
+        }
+
+        public void SetIKKeyframes(float time, Avatar avatar, Transform root, float humanScale, Vector3 bodyPosition, Quaternion bodyRotation)
+        {
+            Vector3 bonePos = transform.position;
+            Quaternion boneRot = transform.rotation;
+
+            if (root.parent != null)
+            {
+                bonePos = root.parent.InverseTransformPoint(bonePos);
+                boneRot = Quaternion.Inverse(root.parent.rotation) * boneRot;
+            }
+
+            TQ IKTQ = AvatarUtility.GetIKGoalTQ(avatar, humanScale, goal, new TQ(bodyPosition, bodyRotation), new TQ(bonePos, boneRot));
+
+            Quaternion rot = IKTQ.q;
+            if (lastQSet) rot = BakerUtilities.EnsureQuaternionContinuity(lastQ, IKTQ.q);
+
+            //rot.Normalize();
+            
+            lastQ = rot;
+            lastQSet = true;
+
+            rotX.AddKey(time, rot.x);
+            rotY.AddKey(time, rot.y);
+            rotZ.AddKey(time, rot.z);
+            rotW.AddKey(time, rot.w);
+
+            Vector3 pos = IKTQ.t;
+            posX.AddKey(time, pos.x);
+            posY.AddKey(time, pos.y);
+            posZ.AddKey(time, pos.z);
+        }
+
+        public void SetKeyframes(float time, Vector3 pos, Quaternion rot)
+        {
+            // Rotation flipping already prevented in HumanoidBaker.UpdateHumanPose().
+            rotX.AddKey(time, rot.x);
+            rotY.AddKey(time, rot.y);
+            rotZ.AddKey(time, rot.z);
+            rotW.AddKey(time, rot.w);
+
+            posX.AddKey(time, pos.x);
+            posY.AddKey(time, pos.y);
+            posZ.AddKey(time, pos.z);
+        }
+
+        public void MoveLastKeyframes(float time)
+        {
+            MoveLastKeyframe(time, rotX);
+            MoveLastKeyframe(time, rotY);
+            MoveLastKeyframe(time, rotZ);
+            MoveLastKeyframe(time, rotW);
+
+            MoveLastKeyframe(time, posX);
+            MoveLastKeyframe(time, posY);
+            MoveLastKeyframe(time, posZ);
+        }
+
+        // Add a copy of the first frame to the specified time
+        public void SetLoopFrame(float time)
+        {
+            BakerUtilities.SetLoopFrame(time, rotX);
+            BakerUtilities.SetLoopFrame(time, rotY);
+            BakerUtilities.SetLoopFrame(time, rotZ);
+            BakerUtilities.SetLoopFrame(time, rotW);
+
+            BakerUtilities.SetLoopFrame(time, posX);
+            BakerUtilities.SetLoopFrame(time, posY);
+            BakerUtilities.SetLoopFrame(time, posZ);
+        }
+
+        private void MoveLastKeyframe(float time, AnimationCurve curve)
+        {
+            Keyframe[] keys = curve.keys;
+            keys[keys.Length - 1].time = time;
+            curve.keys = keys;
+        }
+
+        public void MultiplyLength(AnimationCurve curve, float mlp)
+        {
+            Keyframe[] keys = curve.keys;
+            for (int i = 0; i < keys.Length; i++)
+            {
+                keys[i].time *= mlp;
+            }
+            curve.keys = keys;
+        }
+
+        // Add curves to the AnimationClip for each channel
+        public void SetCurves(ref AnimationClip clip, float maxError, float lengthMlp)
+        {
+            MultiplyLength(rotX, lengthMlp);
+            MultiplyLength(rotY, lengthMlp);
+            MultiplyLength(rotZ, lengthMlp);
+            MultiplyLength(rotW, lengthMlp);
+
+            MultiplyLength(posX, lengthMlp);
+            MultiplyLength(posY, lengthMlp);
+            MultiplyLength(posZ, lengthMlp);
+
+            BakerUtilities.ReduceKeyframes(rotX, maxError);
+            BakerUtilities.ReduceKeyframes(rotY, maxError);
+            BakerUtilities.ReduceKeyframes(rotZ, maxError);
+            BakerUtilities.ReduceKeyframes(rotW, maxError);
+
+            BakerUtilities.ReduceKeyframes(posX, maxError);
+            BakerUtilities.ReduceKeyframes(posY, maxError);
+            BakerUtilities.ReduceKeyframes(posZ, maxError);
+
+            BakerUtilities.SetTangentMode(rotX);
+            BakerUtilities.SetTangentMode(rotY);
+            BakerUtilities.SetTangentMode(rotZ);
+            BakerUtilities.SetTangentMode(rotW);
+
+            /*
+            BakerUtilities.SetTangentMode(posX);
+            BakerUtilities.SetTangentMode(posY);
+            BakerUtilities.SetTangentMode(posZ);
+            */
+
+            clip.SetCurve(string.Empty, typeof(Animator), Qx, rotX);
+            clip.SetCurve(string.Empty, typeof(Animator), Qy, rotY);
+            clip.SetCurve(string.Empty, typeof(Animator), Qz, rotZ);
+            clip.SetCurve(string.Empty, typeof(Animator), Qw, rotW);
+
+            clip.SetCurve(string.Empty, typeof(Animator), Tx, posX);
+            clip.SetCurve(string.Empty, typeof(Animator), Ty, posY);
+            clip.SetCurve(string.Empty, typeof(Animator), Tz, posZ);
+        }
+    }
+
+    // Manages the Animation Curves for a single Transform that is a child of the root Transform.
+    [System.Serializable]
+    public class BakerMuscle
+    {
+
+        // Animation curves for each channel of the Transform
+        public AnimationCurve curve;
+
+        private int muscleIndex = -1;
+        private string propertyName;
+
+        // The custom constructor
+        public BakerMuscle(int muscleIndex)
+        {
+            this.muscleIndex = muscleIndex;
+            this.propertyName = MuscleNameToPropertyName(HumanTrait.MuscleName[muscleIndex]);
+
+            Reset();
+        }
+
+        private string MuscleNameToPropertyName(string n)
+        {
+            // Left fingers
+            if (n == "Left Index 1 Stretched") return "LeftHand.Index.1 Stretched";
+            if (n == "Left Index 2 Stretched") return "LeftHand.Index.2 Stretched";
+            if (n == "Left Index 3 Stretched") return "LeftHand.Index.3 Stretched";
+
+            if (n == "Left Middle 1 Stretched") return "LeftHand.Middle.1 Stretched";
+            if (n == "Left Middle 2 Stretched") return "LeftHand.Middle.2 Stretched";
+            if (n == "Left Middle 3 Stretched") return "LeftHand.Middle.3 Stretched";
+
+            if (n == "Left Ring 1 Stretched") return "LeftHand.Ring.1 Stretched";
+            if (n == "Left Ring 2 Stretched") return "LeftHand.Ring.2 Stretched";
+            if (n == "Left Ring 3 Stretched") return "LeftHand.Ring.3 Stretched";
+
+            if (n == "Left Little 1 Stretched") return "LeftHand.Little.1 Stretched";
+            if (n == "Left Little 2 Stretched") return "LeftHand.Little.2 Stretched";
+            if (n == "Left Little 3 Stretched") return "LeftHand.Little.3 Stretched";
+
+            if (n == "Left Thumb 1 Stretched") return "LeftHand.Thumb.1 Stretched";
+            if (n == "Left Thumb 2 Stretched") return "LeftHand.Thumb.2 Stretched";
+            if (n == "Left Thumb 3 Stretched") return "LeftHand.Thumb.3 Stretched";
+
+            if (n == "Left Index Spread") return "LeftHand.Index.Spread";
+            if (n == "Left Middle Spread") return "LeftHand.Middle.Spread";
+            if (n == "Left Ring Spread") return "LeftHand.Ring.Spread";
+            if (n == "Left Little Spread") return "LeftHand.Little.Spread";
+            if (n == "Left Thumb Spread") return "LeftHand.Thumb.Spread";
+
+            // Right fingers
+            if (n == "Right Index 1 Stretched") return "RightHand.Index.1 Stretched";
+            if (n == "Right Index 2 Stretched") return "RightHand.Index.2 Stretched";
+            if (n == "Right Index 3 Stretched") return "RightHand.Index.3 Stretched";
+
+            if (n == "Right Middle 1 Stretched") return "RightHand.Middle.1 Stretched";
+            if (n == "Right Middle 2 Stretched") return "RightHand.Middle.2 Stretched";
+            if (n == "Right Middle 3 Stretched") return "RightHand.Middle.3 Stretched";
+
+            if (n == "Right Ring 1 Stretched") return "RightHand.Ring.1 Stretched";
+            if (n == "Right Ring 2 Stretched") return "RightHand.Ring.2 Stretched";
+            if (n == "Right Ring 3 Stretched") return "RightHand.Ring.3 Stretched";
+
+            if (n == "Right Little 1 Stretched") return "RightHand.Little.1 Stretched";
+            if (n == "Right Little 2 Stretched") return "RightHand.Little.2 Stretched";
+            if (n == "Right Little 3 Stretched") return "RightHand.Little.3 Stretched";
+
+            if (n == "Right Thumb 1 Stretched") return "RightHand.Thumb.1 Stretched";
+            if (n == "Right Thumb 2 Stretched") return "RightHand.Thumb.2 Stretched";
+            if (n == "Right Thumb 3 Stretched") return "RightHand.Thumb.3 Stretched";
+
+            if (n == "Right Index Spread") return "RightHand.Index.Spread";
+            if (n == "Right Middle Spread") return "RightHand.Middle.Spread";
+            if (n == "Right Ring Spread") return "RightHand.Ring.Spread";
+            if (n == "Right Little Spread") return "RightHand.Little.Spread";
+            if (n == "Right Thumb Spread") return "RightHand.Thumb.Spread";
+
+            return n;
+        }
+
+        public void MultiplyLength(AnimationCurve curve, float mlp)
+        {
+            Keyframe[] keys = curve.keys;
+            for (int i = 0; i < keys.Length; i++)
+            {
+                keys[i].time *= mlp;
+            }
+            curve.keys = keys;
+        }
+
+        // Add curves to the AnimationClip for each channel
+        public void SetCurves(ref AnimationClip clip, float maxError, float lengthMlp)
+        {
+            MultiplyLength(curve, lengthMlp);
+            BakerUtilities.ReduceKeyframes(curve, maxError);
+
+            // BakerUtilities.SetTangentMode(curve);
+
+            clip.SetCurve(string.Empty, typeof(Animator), propertyName, curve);
+        }
+
+        // Clear all curves
+        public void Reset()
+        {
+            curve = new AnimationCurve();
+        }
+
+        // Record a keyframe for each channel
+        public void SetKeyframe(float time, float[] muscles)
+        {
+            curve.AddKey(time, muscles[muscleIndex]);
+        }
+
+        // Add a copy of the first frame to the specified time
+        public void SetLoopFrame(float time)
+        {
+            BakerUtilities.SetLoopFrame(time, curve);
+        }
+    }
+
+    //Manages the Animation Curves for a single Transform that is a child of the root Transform.
+    [System.Serializable]
+    public class BakerTransform
+    {
+
+        public Transform transform; // The Transform component to record
+
+        // Animation curves for each channel of the Transform
+        public AnimationCurve
+            posX, posY, posZ,
+            rotX, rotY, rotZ, rotW;
+
+        private string relativePath; // Path relative to the root
+        private bool recordPosition; // Should we record the localPosition if the transform?
+        private Vector3 relativePosition;
+        private bool isRootNode;
+        private Quaternion relativeRotation;
+
+        // The custom constructor
+        public BakerTransform(Transform transform, Transform root, bool recordPosition, bool isRootNode)
+        {
+            this.transform = transform;
+            this.recordPosition = recordPosition || isRootNode;
+            this.isRootNode = isRootNode;
+
+            relativePath = string.Empty;
+#if UNITY_EDITOR
+            relativePath = UnityEditor.AnimationUtility.CalculateTransformPath(transform, root);
+#endif
+
+            Reset();
+        }
+
+        public void SetRelativeSpace(Vector3 position, Quaternion rotation)
+        {
+            relativePosition = position;
+            relativeRotation = rotation;
+        }
+
+        // Add curves to the AnimationClip for each channel
+        public void SetCurves(ref AnimationClip clip)
+        {
+            if (recordPosition)
+            {
+                clip.SetCurve(relativePath, typeof(Transform), "localPosition.x", posX);
+                clip.SetCurve(relativePath, typeof(Transform), "localPosition.y", posY);
+                clip.SetCurve(relativePath, typeof(Transform), "localPosition.z", posZ);
+            }
+
+            clip.SetCurve(relativePath, typeof(Transform), "localRotation.x", rotX);
+            clip.SetCurve(relativePath, typeof(Transform), "localRotation.y", rotY);
+            clip.SetCurve(relativePath, typeof(Transform), "localRotation.z", rotZ);
+            clip.SetCurve(relativePath, typeof(Transform), "localRotation.w", rotW);
+
+            if (isRootNode) AddRootMotionCurves(ref clip);
+
+            // @todo probably only need to do it once for the clip
+            clip.EnsureQuaternionContinuity(); // DOH!
+        }
+
+        private void AddRootMotionCurves(ref AnimationClip clip)
+        {
+            if (recordPosition)
+            {
+                clip.SetCurve("", typeof(Animator), "MotionT.x", posX);
+                clip.SetCurve("", typeof(Animator), "MotionT.y", posY);
+                clip.SetCurve("", typeof(Animator), "MotionT.z", posZ);
+            }
+
+            clip.SetCurve("", typeof(Animator), "MotionQ.x", rotX);
+            clip.SetCurve("", typeof(Animator), "MotionQ.y", rotY);
+            clip.SetCurve("", typeof(Animator), "MotionQ.z", rotZ);
+            clip.SetCurve("", typeof(Animator), "MotionQ.w", rotW);
+        }
+
+        // Clear all curves
+        public void Reset()
+        {
+            posX = new AnimationCurve();
+            posY = new AnimationCurve();
+            posZ = new AnimationCurve();
+
+            rotX = new AnimationCurve();
+            rotY = new AnimationCurve();
+            rotZ = new AnimationCurve();
+            rotW = new AnimationCurve();
+        }
+
+        public void ReduceKeyframes(float maxError)
+        {
+            BakerUtilities.ReduceKeyframes(rotX, maxError);
+            BakerUtilities.ReduceKeyframes(rotY, maxError);
+            BakerUtilities.ReduceKeyframes(rotZ, maxError);
+            BakerUtilities.ReduceKeyframes(rotW, maxError);
+
+            BakerUtilities.ReduceKeyframes(posX, maxError);
+            BakerUtilities.ReduceKeyframes(posY, maxError);
+            BakerUtilities.ReduceKeyframes(posZ, maxError);
+        }
+
+        // Record a keyframe for each channel
+        public void SetKeyframes(float time)
+        {
+            if (recordPosition)
+            {
+                Vector3 pos = transform.localPosition;
+
+                if (isRootNode)
+                {
+                    pos = transform.position - relativePosition;
+                }
+
+                posX.AddKey(time, pos.x);
+                posY.AddKey(time, pos.y);
+                posZ.AddKey(time, pos.z);
+            }
+
+            Quaternion rot = transform.localRotation;
+
+            if (isRootNode)
+            {
+                rot = Quaternion.Inverse(relativeRotation) * transform.rotation;
+            }
+
+            rotX.AddKey(time, rot.x);
+            rotY.AddKey(time, rot.y);
+            rotZ.AddKey(time, rot.z);
+            rotW.AddKey(time, rot.w);
+        }
+
+        // Add a copy of the first frame to the specified time
+        public void AddLoopFrame(float time)
+        {
+            // TODO change to SetLoopFrame
+            if (recordPosition && !isRootNode)
+            {
+                posX.AddKey(time, posX.keys[0].value);
+                posY.AddKey(time, posY.keys[0].value);
+                posZ.AddKey(time, posZ.keys[0].value);
+            }
+
+            rotX.AddKey(time, rotX.keys[0].value);
+            rotY.AddKey(time, rotY.keys[0].value);
+            rotZ.AddKey(time, rotZ.keys[0].value);
+            rotW.AddKey(time, rotW.keys[0].value);
+        }
+    }
+}
+

+ 12 - 0
Assets/Plugins/RootMotion/Baker/Scripts/Helpers/BakerUtilities.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 582052db0a6096149a7b2b75914ef3a6
+timeCreated: 1516263395
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 194 - 0
Assets/Plugins/RootMotion/Baker/Scripts/HumanoidBaker.cs

@@ -0,0 +1,194 @@
+using UnityEngine;
+using System.Collections;
+using UnityEngine.Playables;
+
+namespace RootMotion
+{
+    /// <summary>
+    /// Baker for Humanoid animation.
+    /// </summary>
+    public class HumanoidBaker : Baker
+    {
+        /// <summary>
+        /// Should the hand IK curves be added to the animation? Disable this if the original hand positions are not important when using the clip on another character via Humanoid retargeting.
+        /// </summary>
+        [Tooltip("Should the hand IK curves be added to the animation? Disable this if the original hand positions are not important when using the clip on another character via Humanoid retargeting.")]
+        public bool bakeHandIK = true;
+
+        /// <summary>
+        /// Max keyframe reduction error for the Root.Q/T, LeftFoot IK and RightFoot IK channels. Having a larger error value for 'Key Reduction Error' and a smaller one for this enables you to optimize clip data size without the floating feet effect by enabling 'Foot IK' in the Animator.
+        /// </summary>
+        [Tooltip("Max keyframe reduction error for the Root.Q/T, LeftFoot IK and RightFoot IK channels. Having a larger error value for 'Key Reduction Error' and a smaller one for this enables you to optimize clip data size without the floating feet effect by enabling 'Foot IK' in the Animator.")]
+        [Range(0f, 0.1f)] public float IKKeyReductionError;
+
+        /// <summary>
+        /// Frame rate divider for the muscle curves. If you had 'Frame Rate' set to 30, and this value set to 3, the muscle curves will be baked at 10 fps. Only the Root Q/T and Hand and Foot IK curves will be baked at 30. This enables you to optimize clip data size without the floating feet effect by enabling 'Foot IK' in the Animator.
+        /// </summary>
+        [Tooltip("Frame rate divider for the muscle curves. If you have 'Frame Rate' set to 30, and this value set to 3, the muscle curves will be baked at 10 fps. Only the Root Q/T and Hand and Foot IK curves will be baked at 30. This enables you to optimize clip data size without the floating feet effect by enabling 'Foot IK' in the Animator.")]
+        [Range(1, 9)] public int muscleFrameRateDiv = 1;
+
+        private BakerMuscle[] bakerMuscles;
+        private BakerHumanoidQT rootQT;
+        private BakerHumanoidQT leftFootQT;
+        private BakerHumanoidQT rightFootQT;
+        private BakerHumanoidQT leftHandQT;
+        private BakerHumanoidQT rightHandQT;
+
+        private float[] muscles = new float[0];
+        private HumanPose pose = new HumanPose();
+        private HumanPoseHandler handler;
+        private Vector3 bodyPosition;
+        private Quaternion bodyRotation = Quaternion.identity;
+        private int mN = 0;
+        private Quaternion lastBodyRotation = Quaternion.identity;
+
+        void Awake()
+        {
+            animator = GetComponent<Animator>();
+            director = GetComponent<PlayableDirector>();
+
+            if (mode == Mode.AnimationStates || mode == Mode.AnimationClips)
+            {
+                if (animator == null || !animator.isHuman)
+                {
+                    Debug.LogError("HumanoidBaker GameObject does not have a Humanoid Animator component, can not bake.");
+                    enabled = false;
+                    return;
+                }
+
+                animator.cullingMode = AnimatorCullingMode.AlwaysAnimate;
+            }
+            else if (mode == Mode.PlayableDirector)
+            {
+                if (director == null)
+                {
+                    Debug.LogError("HumanoidBaker GameObject does not have a PlayableDirector component, can not bake.");
+                }
+            }
+
+            muscles = new float[HumanTrait.MuscleCount];
+            bakerMuscles = new BakerMuscle[HumanTrait.MuscleCount];
+            for (int i = 0; i < bakerMuscles.Length; i++)
+            {
+                bakerMuscles[i] = new BakerMuscle(i);
+            }
+
+            rootQT = new BakerHumanoidQT("Root");
+
+            leftFootQT = new BakerHumanoidQT(animator.GetBoneTransform(HumanBodyBones.LeftFoot), AvatarIKGoal.LeftFoot, "LeftFoot");
+            rightFootQT = new BakerHumanoidQT(animator.GetBoneTransform(HumanBodyBones.RightFoot), AvatarIKGoal.RightFoot, "RightFoot");
+            leftHandQT = new BakerHumanoidQT(animator.GetBoneTransform(HumanBodyBones.LeftHand), AvatarIKGoal.LeftHand, "LeftHand");
+            rightHandQT = new BakerHumanoidQT(animator.GetBoneTransform(HumanBodyBones.RightHand), AvatarIKGoal.RightHand, "RightHand");
+
+            handler = new HumanPoseHandler(animator.avatar, animator.transform);
+        }
+
+        protected override Transform GetCharacterRoot()
+        {
+            return animator.transform;
+        }
+
+        protected override void OnStartBaking()
+        {
+
+            rootQT.Reset();
+            leftFootQT.Reset();
+            rightFootQT.Reset();
+            leftHandQT.Reset();
+            rightHandQT.Reset();
+
+            for (int i = 0; i < bakerMuscles.Length; i++)
+            {
+                bakerMuscles[i].Reset();
+            }
+
+            mN = muscleFrameRateDiv;
+
+            lastBodyRotation = Quaternion.identity;
+        }
+
+        protected override void OnSetLoopFrame(float time)
+        {
+            for (int i = 0; i < bakerMuscles.Length; i++) bakerMuscles[i].SetLoopFrame(time);
+
+            rootQT.MoveLastKeyframes(time);
+
+            leftFootQT.SetLoopFrame(time);
+            rightFootQT.SetLoopFrame(time);
+            leftHandQT.SetLoopFrame(time);
+            rightHandQT.SetLoopFrame(time);
+        }
+
+        protected override void OnSetCurves(ref AnimationClip clip)
+        {
+            float length = bakerMuscles[0].curve.keys[bakerMuscles[0].curve.keys.Length - 1].time;
+            float lengthMlp = mode != Mode.Realtime ? clipLength / length : 1f;
+
+            for (int i = 0; i < bakerMuscles.Length; i++) bakerMuscles[i].SetCurves(ref clip, keyReductionError, lengthMlp);
+
+            rootQT.SetCurves(ref clip, IKKeyReductionError, lengthMlp);
+            leftFootQT.SetCurves(ref clip, IKKeyReductionError, lengthMlp);
+            rightFootQT.SetCurves(ref clip, IKKeyReductionError, lengthMlp);
+
+            if (bakeHandIK)
+            {
+                leftHandQT.SetCurves(ref clip, IKKeyReductionError, lengthMlp);
+                rightHandQT.SetCurves(ref clip, IKKeyReductionError, lengthMlp);
+            }
+        }
+
+        protected override void OnSetKeyframes(float time, bool lastFrame)
+        {
+            // Skip muscle frames
+            mN++;
+            bool updateMuscles = true;
+            if (mN < muscleFrameRateDiv && !lastFrame)
+            {
+                updateMuscles = false;
+            }
+            if (mN >= muscleFrameRateDiv) mN = 0;
+
+            UpdateHumanPose();
+
+            if (updateMuscles)
+            {
+                for (int i = 0; i < bakerMuscles.Length; i++) bakerMuscles[i].SetKeyframe(time, muscles);
+            }
+
+            rootQT.SetKeyframes(time, bodyPosition, bodyRotation);
+
+            Vector3 bodyPositionScaled = bodyPosition * animator.humanScale;
+            leftFootQT.SetIKKeyframes(time, animator.avatar, animator.transform, animator.humanScale, bodyPositionScaled, bodyRotation);
+            rightFootQT.SetIKKeyframes(time, animator.avatar, animator.transform, animator.humanScale, bodyPositionScaled, bodyRotation);
+
+            leftHandQT.SetIKKeyframes(time, animator.avatar, animator.transform, animator.humanScale, bodyPositionScaled, bodyRotation);
+            rightHandQT.SetIKKeyframes(time, animator.avatar, animator.transform, animator.humanScale, bodyPositionScaled, bodyRotation);
+        }
+
+        private void UpdateHumanPose()
+        {
+            handler.GetHumanPose(ref pose);
+
+            bodyPosition = pose.bodyPosition;
+            bodyRotation = pose.bodyRotation;
+
+            bodyRotation = BakerUtilities.EnsureQuaternionContinuity(lastBodyRotation, bodyRotation);
+            lastBodyRotation = bodyRotation;
+
+            for (int i = 0; i < pose.muscles.Length; i++)
+            {
+                muscles[i] = pose.muscles[i];
+            }
+        }
+
+#if UNITY_EDITOR
+        protected override void SetClipSettings(AnimationClip clip, UnityEditor.AnimationClipSettings settings)
+        {
+            settings.loopBlendOrientation = true;
+            settings.loopBlendPositionY = true;
+            settings.keepOriginalOrientation = true;
+            settings.keepOriginalPositionY = true;
+        }
+#endif
+    }
+}

+ 12 - 0
Assets/Plugins/RootMotion/Baker/Scripts/HumanoidBaker.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: efcc0ec5ed265a340a1412edb9110337
+timeCreated: 1516287616
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 15000
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: c41cf13236c01a747b3dfb963402b3a0
+folderAsset: yes
+timeCreated: 1516620909
+licenseType: Store
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS/Baked Clips.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a4b02f60233a6cf4eb1c424f90323213
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

Файловите разлики са ограничени, защото са твърде много
+ 11611 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS/Baked Clips/Clip 1_Baked.anim


+ 8 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS/Baked Clips/Clip 1_Baked.anim.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3451f091c656bfc429396cc701ac5b8d
+NativeFormatImporter:
+  externalObjects: {}
+  mainObjectFileID: 7400000
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 69 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS/Humanoid Baker Clip Sampler.controller

@@ -0,0 +1,69 @@
+%YAML 1.1
+%TAG !u! tag:unity3d.com,2011:
+--- !u!91 &9100000
+AnimatorController:
+  m_ObjectHideFlags: 0
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_Name: Humanoid Baker Clip Sampler
+  serializedVersion: 5
+  m_AnimatorParameters: []
+  m_AnimatorLayers:
+  - serializedVersion: 5
+    m_Name: Base Layer
+    m_StateMachine: {fileID: 110737558}
+    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 &110235224
+AnimatorState:
+  serializedVersion: 5
+  m_ObjectHideFlags: 1
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_Name: Clip 1
+  m_Speed: 1
+  m_CycleOffset: 0
+  m_Transitions: []
+  m_StateMachineBehaviours: []
+  m_Position: {x: 50, y: 50, z: 0}
+  m_IKOnFeet: 1
+  m_WriteDefaultValues: 1
+  m_Mirror: 0
+  m_SpeedParameterActive: 0
+  m_MirrorParameterActive: 0
+  m_CycleOffsetParameterActive: 0
+  m_TimeParameterActive: 0
+  m_Motion: {fileID: 7400000, guid: 739b2627204c24240aa40c4f67f59d0e, type: 3}
+  m_Tag: 
+  m_SpeedParameter: 
+  m_MirrorParameter: 
+  m_CycleOffsetParameter: 
+  m_TimeParameter: 
+--- !u!1107 &110737558
+AnimatorStateMachine:
+  serializedVersion: 5
+  m_ObjectHideFlags: 1
+  m_PrefabParentObject: {fileID: 0}
+  m_PrefabInternal: {fileID: 0}
+  m_Name: Base Layer
+  m_ChildStates:
+  - serializedVersion: 1
+    m_State: {fileID: 110235224}
+    m_Position: {x: 300, y: 36, 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: 110235224}

+ 8 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS/Humanoid Baker Clip Sampler.controller.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 24d41cb619dc9dc42bf10705eb128c97
+timeCreated: 1516284817
+licenseType: Store
+NativeFormatImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

Файловите разлики са ограничени, защото са твърде много
+ 2228 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS/Humanoid Baker.unity


+ 8 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS/Humanoid Baker.unity.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 0bd8d9a8cbacde343967c95c4458318e
+timeCreated: 1517387718
+licenseType: Store
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS/Scripts.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 3349a7526568cf042bf8609694db3327
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 53 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS/Scripts/FKOffset.cs

@@ -0,0 +1,53 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+
+namespace RootMotion.Demos
+{
+    // Adds simple FK rotation offset to bones.
+    public class FKOffset : MonoBehaviour
+    {
+        [System.Serializable]
+        public class Offset
+        {
+            [HideInInspector] public string name;
+            public HumanBodyBones bone;
+            public Vector3 rotationOffset;
+
+            private Transform t;
+
+            public void Apply(Animator animator)
+            {
+                if (t == null) t = animator.GetBoneTransform(bone);
+                if (t == null) return;
+
+                t.localRotation *= Quaternion.Euler(rotationOffset);
+            }
+        }
+
+        public Offset[] offsets;
+
+        private Animator animator;
+
+        private void Start()
+        {
+            animator = GetComponent<Animator>();
+        }
+
+        private void LateUpdate()
+        {
+            foreach (Offset offset in offsets)
+            {
+                offset.Apply(animator);
+            }
+        }
+
+        private void OnDrawGizmosSelected()
+        {
+            foreach (Offset offset in offsets)
+            {
+                offset.name = offset.bone.ToString();
+            }
+        }
+    }
+}

+ 11 - 0
Assets/Plugins/RootMotion/Baker/_DEMOS/Scripts/FKOffset.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ea198996b9a58624b82f921e56faf4ba
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 8 - 0
Assets/Plugins/RootMotion/Editor.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 5059b61e5885d6945ad3de1923d051de
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Plugins/RootMotion/Editor/Baker.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: fe88a087b0795174f9c8ec2369f4ccb2
+folderAsset: yes
+timeCreated: 1516620937
+licenseType: Store
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 176 - 0
Assets/Plugins/RootMotion/Editor/Baker/BakerInspector.cs

@@ -0,0 +1,176 @@
+using UnityEngine;
+using System.Collections;
+using UnityEditor;
+using UnityEngine.Playables;
+using System;
+
+namespace RootMotion
+{
+    public class BakerInspector : Editor
+    {
+
+        protected void DrawKeyframeSettings(Baker script)
+        {
+            if (script.isBaking) return;
+            EditorGUILayout.Space();
+
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("frameRate"));
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("keyReductionError"));
+        }
+
+        protected void DrawModeSettings(Baker script)
+        {
+            if (script.isBaking) return;
+
+            EditorGUILayout.Space();
+
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("mode"));
+
+            switch (script.mode)
+            {
+                case Baker.Mode.AnimationClips:
+                    EditorGUILayout.PropertyField(serializedObject.FindProperty("animationClips"), true);
+                    EditorGUILayout.PropertyField(serializedObject.FindProperty("appendName"));
+                    break;
+                case Baker.Mode.AnimationStates:
+                    EditorGUILayout.PropertyField(serializedObject.FindProperty("loop"));
+                    EditorGUILayout.PropertyField(serializedObject.FindProperty("animationStates"), true);
+                    EditorGUILayout.PropertyField(serializedObject.FindProperty("appendName"));
+                    break;
+                case Baker.Mode.PlayableDirector:
+                    EditorGUILayout.PropertyField(serializedObject.FindProperty("loop"));
+                    EditorGUILayout.PropertyField(serializedObject.FindProperty("saveName"));
+                    break;
+                default:
+                    EditorGUILayout.PropertyField(serializedObject.FindProperty("saveName"));
+                    break;
+            }
+
+            //EditorGUILayout.BeginHorizontal();
+            EditorGUILayout.Space();
+            EditorGUILayout.LabelField(new GUIContent("Save To Folder"));
+
+            if (EditorGUILayout.DropdownButton(new GUIContent(serializedObject.FindProperty("saveToFolder").stringValue, "The folder to save the baked AnimationClips to."), FocusType.Passive, GUILayout.MaxWidth(400)))
+            {
+                serializedObject.FindProperty("saveToFolder").stringValue = SaveClipFolderPanel.Apply(serializedObject.FindProperty("saveToFolder").stringValue);
+            }
+            //EditorGUILayout.EndHorizontal();
+        }
+
+        private void TryBake(Baker script)
+        {
+            switch (script.mode)
+            {
+                case Baker.Mode.AnimationClips:
+                    if (script.animator == null)
+                    {
+                        EditorGUILayout.LabelField("No Animator found on Baker GameObject", EditorStyles.helpBox);
+                        return;
+                    }
+
+                    if (script.animator.isHuman && script.animator.runtimeAnimatorController == null)
+                    {
+                        EditorGUILayout.LabelField("Humanoid Animator needs to have a valid Controller assigned for clip baking (Unity crash bug)", EditorStyles.helpBox);
+                        return;
+                    }
+
+                    if (script.animationClips.Length == 0)
+                    {
+                        EditorGUILayout.LabelField("Please add AnimationClips to bake", EditorStyles.helpBox);
+                        return;
+                    }
+
+                    foreach (AnimationClip clip in script.animationClips)
+                    {
+                        if (clip == null)
+                        {
+                            EditorGUILayout.LabelField("One of the AnimationClips is null, can not bake.", EditorStyles.helpBox);
+                            return;
+                        }
+                    }
+
+                    if (GUILayout.Button("Bake Animation Clips")) script.BakeClip();
+                    return;
+                case Baker.Mode.AnimationStates:
+                    if (script.animator == null)
+                    {
+                        EditorGUILayout.LabelField("No Animator found on Baker GameObject", EditorStyles.helpBox);
+                        return;
+                    }
+
+                    if (script.animationStates.Length == 0)
+                    {
+                        EditorGUILayout.LabelField("Please add Animation State names to bake. The Animator must contain AnimationStates with matching names. If AnimationState names match with clip names used in them, you can have the Baker fill the names in automatically by right-clicking on the component header and selecting 'Find Animation States'.", EditorStyles.helpBox);
+                        return;
+                    }
+
+                    for (int i = 0; i < script.animationStates.Length; i++)
+                    {
+                        if (script.animationStates[i] == string.Empty || script.animationStates[i] == "")
+                        {
+                            EditorGUILayout.LabelField("One of the animation state names in 'Animation States' is empty, can not bake.", EditorStyles.helpBox);
+                            return;
+                        }
+                    }
+
+                    if (GUILayout.Button("Bake Animation States")) script.BakeClip();
+                    return;
+                case Baker.Mode.PlayableDirector:
+                    if (script.director == null)
+                    {
+                        EditorGUILayout.LabelField("No PlayableDirector found on Baker GameObject", EditorStyles.helpBox);
+                        return;
+                    }
+
+                    if (GUILayout.Button("Bake Timeline")) script.BakeClip();
+                    break;
+                case Baker.Mode.Realtime:
+                    if (GUILayout.Button("Start Baking")) script.StartBaking();
+                    return;
+            }
+        }
+
+        protected void DrawButtons(Baker script)
+        {
+            if (!script.enabled) return;
+
+            if (script.animator == null)
+            {
+                serializedObject.FindProperty("animator").objectReferenceValue = script.GetComponent<Animator>();
+            }
+
+            if (script.director == null)
+            {
+                serializedObject.FindProperty("director").objectReferenceValue = script.GetComponent<PlayableDirector>();
+            }
+
+            if (!Application.isPlaying)
+            {
+                EditorGUILayout.LabelField("Enter Play Mode to bake.", EditorStyles.helpBox);
+                return;
+            }
+
+            if (!script.isBaking)
+            {
+                TryBake(script);
+            }
+            else
+            {
+                GUI.color = Color.red;
+
+                switch (script.mode)
+                {
+                    case Baker.Mode.Realtime:
+                        if (GUILayout.Button("Stop Baking")) script.StopBaking();
+                        break;
+                    default:
+                        GUILayout.Label("Baking Progress: " + System.Math.Round(script.bakingProgress, 2));
+                        break;
+                }
+
+                GUI.color = Color.white;
+                EditorUtility.SetDirty(script);
+            }
+        }
+    }
+}

+ 12 - 0
Assets/Plugins/RootMotion/Editor/Baker/BakerInspector.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: dcf5801ad3ff7fa43b06824f09d82160
+timeCreated: 1516619065
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 52 - 0
Assets/Plugins/RootMotion/Editor/Baker/GenericBakerInspector.cs

@@ -0,0 +1,52 @@
+using UnityEngine;
+using System.Collections;
+using UnityEditor;
+
+namespace RootMotion
+{
+    [CustomEditor(typeof(GenericBaker))]
+    public class GenericBakerInspector : BakerInspector
+    {
+        private GenericBaker script { get { return target as GenericBaker; } }
+
+        private MonoScript monoScript;
+
+        void OnEnable()
+        {
+            // Changing the script execution order
+            if (!Application.isPlaying)
+            {
+                monoScript = MonoScript.FromMonoBehaviour(script);
+                int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
+                if (currentExecutionOrder != 15001) MonoImporter.SetExecutionOrder(monoScript, 15001);
+            }
+        }
+
+        public override void OnInspectorGUI()
+        {
+            serializedObject.Update();
+
+            DrawKeyframeSettings(script as Baker);
+            DrawGenericKeyframeSettings(script);
+            DrawModeSettings(script as Baker);
+            DrawButtons(script as Baker);
+
+            if (serializedObject.ApplyModifiedProperties())
+            {
+                EditorUtility.SetDirty(script);
+            }
+        }
+
+        private void DrawGenericKeyframeSettings(GenericBaker script)
+        {
+            if (script.isBaking) return;
+
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("markAsLegacy"));
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("root"));
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("rootNode"));
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("ignoreList"), true);
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("bakePositionList"), true);
+        }
+    }
+}
+

+ 8 - 0
Assets/Plugins/RootMotion/Editor/Baker/GenericBakerInspector.cs.meta

@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: 8f544a5bc87054e74ac2e415889ba75a
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 

+ 9 - 0
Assets/Plugins/RootMotion/Editor/Baker/Helpers.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 73b96cf8495867d429c9c5b31ff6d6da
+folderAsset: yes
+timeCreated: 1516621014
+licenseType: Store
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 38 - 0
Assets/Plugins/RootMotion/Editor/Baker/Helpers/AnimationUtilityExtended.cs

@@ -0,0 +1,38 @@
+using UnityEngine;
+using System.Collections;
+using UnityEditor;
+
+namespace RootMotion
+{
+    public static class AnimationUtilityExtended
+    {
+
+        /// <summary>
+        /// Copies the curves with the specified property names from clipFrom to clipTo.
+        /// </summary>
+        /// <param name="fromClip">copy from clip.</param>
+        /// <param name="toClip">paste to clip</param>
+        /// <param name="propertyNames">Property names ("Root.T", "Root.Q", "LeftFoot.T"...).</param>
+        public static void CopyCurves(AnimationClip fromClip, AnimationClip toClip, string[] propertyNames)
+        {
+            EditorCurveBinding[] bindings = AnimationUtility.GetCurveBindings(fromClip);
+
+            for (int i = 0; i < bindings.Length; i++)
+            {
+                for (int n = 0; n < propertyNames.Length; n++)
+                {
+                    if (bindings[i].propertyName == propertyNames[n])
+                    {
+                        CopyCurve(fromClip, toClip, bindings[i]);
+                    }
+                }
+            }
+        }
+
+        public static void CopyCurve(AnimationClip fromClip, AnimationClip toClip, EditorCurveBinding binding)
+        {
+            AnimationCurve curve = AnimationUtility.GetEditorCurve(fromClip, binding);
+            toClip.SetCurve(string.Empty, typeof(Animator), binding.propertyName, curve);
+        }
+    }
+}

+ 12 - 0
Assets/Plugins/RootMotion/Editor/Baker/Helpers/AnimationUtilityExtended.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 054c55a0c5c10dc4fafcfd81aeaaec56
+timeCreated: 1516620625
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 22 - 0
Assets/Plugins/RootMotion/Editor/Baker/Helpers/SaveClipFolderPanel.cs

@@ -0,0 +1,22 @@
+using UnityEngine;
+using UnityEditor;
+using System.IO;
+using System;
+
+namespace RootMotion
+{
+    public class SaveClipFolderPanel : EditorWindow
+    {
+        public static string Apply(string currentPath)
+        {
+            string path = EditorUtility.SaveFolderPanel("Save clip(s) to folder", currentPath, "");
+
+            if (path.Length != 0)
+            {
+                return path.Substring(path.IndexOf("Assets/"));
+            }
+
+            return currentPath;
+        }
+    }
+}

+ 11 - 0
Assets/Plugins/RootMotion/Editor/Baker/Helpers/SaveClipFolderPanel.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7edb6cbf0a3b9924d8f631c4c00fd38a
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 52 - 0
Assets/Plugins/RootMotion/Editor/Baker/HumanoidBakerInspector.cs

@@ -0,0 +1,52 @@
+using UnityEngine;
+using System.Collections;
+using UnityEditor;
+
+namespace RootMotion
+{
+    [CustomEditor(typeof(HumanoidBaker))]
+    public class HumanoidBakerInspector : BakerInspector
+    {
+
+        private HumanoidBaker script { get { return target as HumanoidBaker; } }
+
+        private MonoScript monoScript;
+
+        void OnEnable()
+        {
+            // Changing the script execution order
+            if (!Application.isPlaying)
+            {
+                monoScript = MonoScript.FromMonoBehaviour(script);
+                int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
+                if (currentExecutionOrder != 15000) MonoImporter.SetExecutionOrder(monoScript, 15000);
+            }
+        }
+
+        // TODO Move this to BakerInspector.cs
+        public override void OnInspectorGUI()
+        {
+            serializedObject.Update();
+
+            DrawKeyframeSettings(script as Baker);
+            DrawHumanoidKeyframeSettings(script);
+            DrawModeSettings(script as Baker);
+            DrawButtons(script as Baker);
+
+            if (serializedObject.ApplyModifiedProperties())
+            {
+                EditorUtility.SetDirty(script);
+            }
+        }
+
+        protected void DrawHumanoidKeyframeSettings(HumanoidBaker script)
+        {
+            if (script.isBaking) return;
+
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("IKKeyReductionError"));
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("muscleFrameRateDiv"));
+            EditorGUILayout.PropertyField(serializedObject.FindProperty("bakeHandIK"));
+        }
+    }
+}
+

+ 12 - 0
Assets/Plugins/RootMotion/Editor/Baker/HumanoidBakerInspector.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: f8139af98945e154885b65eedbb102cc
+timeCreated: 1516265598
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 9 - 0
Assets/Plugins/RootMotion/Editor/FinalIK.meta

@@ -0,0 +1,9 @@
+fileFormatVersion: 2
+guid: 403e73ed4eb874619a26a7b37fbb9c35
+folderAsset: yes
+timeCreated: 1436186156
+licenseType: Store
+DefaultImporter:
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 38 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/AimIKInspector.cs

@@ -0,0 +1,38 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector for AimIK.
+	 * */
+	[CustomEditor(typeof(AimIK))]
+	public class AimIKInspector : IKInspector {
+		
+		private AimIK script { get { return target as AimIK; }}
+
+		protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
+			executionOrder = 9997;
+			return script;
+		}
+		
+		protected override void OnApplyModifiedProperties() {
+			if (!Application.isPlaying) script.solver.Initiate(script.transform);
+		}
+		
+		protected override void AddInspector() {
+			// Draw the inspector for IKSolverAim
+			IKSolverAimInspector.AddInspector(solver, !Application.isPlaying);
+
+			// Warning box
+			string message = string.Empty;
+			if (!script.solver.IsValid(ref message)) AddWarningBox(message);
+		}	
+		
+		void OnSceneGUI() {
+			// Draw the scene veiw helpers
+			IKSolverAimInspector.AddScene(script.solver, new Color(1f, 0f, 0.5f, 1f), true);
+		}
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/AimIKInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 4a8f3f357746148a98faf7ccd416a2a6
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 189 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/AimPoserInspector.cs

@@ -0,0 +1,189 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+using RootMotion;
+
+namespace RootMotion.FinalIK {
+
+	/// <summary>
+	/// Custom inspector for the Aim Poser for visualizing pose range
+	/// </summary>
+	[CustomEditor(typeof(AimPoser))]
+	public class AimPoserInspector : Editor {
+
+		[System.Serializable]
+		public struct ColorDirection {
+			public Vector3 direction;
+			public Vector3 color;
+			public float dot;
+			
+			public ColorDirection(Vector3 direction, Vector3 color) {
+				this.direction = direction.normalized;
+				this.color = color;
+				this.dot = 0;
+			}
+		}
+
+		private AimPoser script { get { return target as AimPoser; }}
+		private ColorDirection[] colorDirections;
+		private static Vector3[] poly = new Vector3[36];
+
+		void OnSceneGUI() {
+			for (int i = 0; i < script.poses.Length; i++) {
+				script.poses[i].yaw = Mathf.Clamp(script.poses[i].yaw, 0, 180);
+				script.poses[i].pitch = Mathf.Clamp(script.poses[i].pitch, 0, 180);
+			}
+
+			if (colorDirections == null) {
+				colorDirections = new ColorDirection[6] {
+					new ColorDirection(Vector3.right, Vector3.right),
+					new ColorDirection(Vector3.up, Vector3.up),
+					new ColorDirection(Vector3.forward, Vector3.forward),
+					new ColorDirection(Vector3.left, new Vector3(0f, 1f, 1f)),
+					new ColorDirection(Vector3.down, new Vector3(1f, 0f, 1f)),
+					new ColorDirection(Vector3.back, new Vector3(1f, 1f, 0f))
+				};
+			}
+
+			for (int i = 0; i < script.poses.Length; i++) {
+				if (script.poses[i].visualize) {
+					DrawPose(script.poses[i], script.transform.position, script.transform.rotation, GetDirectionColor(script.poses[i].direction));
+				}
+			}
+		}
+
+		private Color GetDirectionColor(Vector3 localDirection) {
+			localDirection = localDirection.normalized;
+
+			// Calculating dot products for all AxisDirections
+			for (int i = 0; i < colorDirections.Length; i++) {
+				colorDirections[i].dot = Mathf.Clamp(Vector3.Dot(colorDirections[i].direction, localDirection), 0f, 1f);
+			}
+			
+			// Summing up the arm bend axis
+			Vector3 sum = Vector3.zero;
+			
+			for (int i = 0; i < colorDirections.Length; i++) {
+				sum = Vector3.Lerp(sum, colorDirections[i].color, colorDirections[i].dot * colorDirections[i].dot);
+			}
+
+			return new Color(sum.x, sum.y, sum.z);
+		}
+
+		private static void DrawPose(AimPoser.Pose pose, Vector3 position, Quaternion rotation, Color color) {
+			if (pose.pitch <= 0f || pose.yaw <= 0f) return;
+			if (pose.direction == Vector3.zero) return;
+
+			Handles.color = color;
+			GUI.color = color;
+
+			Vector3 up = rotation * Vector3.up;
+			Vector3 normalizedPoseDirection = pose.direction.normalized;
+			Vector3 direction = rotation * normalizedPoseDirection;
+			
+			// Direction and label
+			Handles.DrawLine(position, position + direction);
+			Inspector.ConeCap(0, position + direction, Quaternion.LookRotation(direction), 0.05f);
+			Handles.Label(position + direction.normalized * 1.1f, pose.name);
+
+			if (pose.yaw >= 180f && pose.pitch >= 180f) {
+				Handles.color = Color.white;
+				GUI.color = Color.white;
+				return;
+			}
+		
+			Quaternion halfYaw = Quaternion.AngleAxis(pose.yaw, up);
+
+			float directionPitch = Vector3.Angle(up, direction);
+			Vector3 crossRight = halfYaw * Vector3.Cross(up, direction);
+			Vector3 crossLeft = Quaternion.Inverse(halfYaw) * Vector3.Cross(up, direction);
+
+			bool isVertical = normalizedPoseDirection == Vector3.up || normalizedPoseDirection == Vector3.down;
+
+			if (isVertical) {
+				crossRight = halfYaw * Vector3.right;
+				crossLeft = Quaternion.Inverse(halfYaw) * Vector3.right;
+			}
+
+			float minPitch = Mathf.Clamp(directionPitch - pose.pitch, 0f, 180f);
+			float maxPitch = Mathf.Clamp(directionPitch + pose.pitch, 0f, 180f);
+
+			Quaternion upToCornerUpperRight = Quaternion.AngleAxis(minPitch, crossRight);
+			Quaternion upToCornerLowerRight = Quaternion.AngleAxis(maxPitch, crossRight);
+			Quaternion upToCornerUpperLeft = Quaternion.AngleAxis(minPitch, crossLeft);
+			Quaternion upToCornerLowerLeft = Quaternion.AngleAxis(maxPitch, crossLeft);
+
+			Vector3 toCornerUpperRight = upToCornerUpperRight * up;
+			Vector3 toCornerLowerRight = upToCornerLowerRight * up;
+			Vector3 toCornerUpperLeft = upToCornerUpperLeft * up;
+			Vector3 toCornerLowerLeft = upToCornerLowerLeft * up;
+
+			if (pose.yaw < 180f) {
+				Handles.DrawLine(position, position + toCornerUpperRight);
+				Handles.DrawLine(position, position + toCornerUpperLeft);
+
+				Handles.DrawLine(position, position + toCornerLowerRight);
+				Handles.DrawLine(position, position + toCornerLowerLeft);
+			}
+
+			Vector3 d = direction;
+			if (isVertical) d = Vector3.forward;
+
+			if (pose.pitch < 180f) {
+				DrawPolyLineOnSphere(position, toCornerUpperLeft, toCornerUpperRight, d, Vector3.up, color);
+				DrawPolyLineOnSphere(position, toCornerLowerLeft, toCornerLowerRight, d, Vector3.up, color);
+			}
+
+			if (pose.yaw < 180f) {
+				DrawPolyLineOnSphere(position, toCornerUpperLeft, toCornerLowerLeft, Quaternion.Inverse(halfYaw) * d, crossLeft, color);
+				DrawPolyLineOnSphere(position, toCornerUpperRight, toCornerLowerRight, halfYaw * d, crossRight, color);
+			}
+
+			Handles.color = Color.white;
+			GUI.color = Color.white;
+		}
+
+		private static void DrawPolyLineOnSphere(Vector3 center, Vector3 d1, Vector3 d2, Vector3 direction, Vector3 axis, Color color) {
+			Handles.color = color;
+
+			Vector3 normal = axis;
+			Vector3 d1Ortho = d1;
+			Vector3.OrthoNormalize(ref normal, ref d1Ortho);
+
+			normal = axis;
+			Vector3 d2Ortho = d2;
+			Vector3.OrthoNormalize(ref normal, ref d2Ortho);
+
+			normal = axis;
+			Vector3 directionOrtho = direction;
+			Vector3.OrthoNormalize(ref normal, ref directionOrtho);
+
+			float angle = Vector3.Angle(d1Ortho, d2Ortho);
+
+			float dot = Vector3.Dot(directionOrtho, d1Ortho);
+			if (dot < 0) {
+				angle = 180 + (180 - angle);
+			}
+
+			int segments = Mathf.Clamp(Mathf.RoundToInt(angle / 36f) * 5, 3, 36);
+
+			float segmentF = angle / (float)(segments - 1);
+
+			for (int i = 0; i < segments; i++) {
+				poly[i] = center + Quaternion.AngleAxis(i * segmentF, axis) * d1;
+			}
+
+			Handles.color = new Color(color.r, color.g, color.b, color.a * 0.1f);
+
+			for (int i = 0; i < segments; i++) {
+				Handles.DrawLine(center, poly[i]);
+			}
+
+			Handles.color = color;
+
+			for (int i = 0; i < segments - 1; i++) {
+				Handles.DrawLine(poly[i], poly[i + 1]);
+			}
+		}
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/AimPoserInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 079587d3635eb48c3a5c0d57f8c3cc6f
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 38 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/ArmIKInspector.cs

@@ -0,0 +1,38 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+	
+	/*
+	 * Custom inspector for ArmIK.
+	 * */
+	[CustomEditor(typeof(ArmIK))]
+	public class ArmIKInspector : IKInspector {
+		
+		private ArmIK script { get { return target as ArmIK; }}
+		
+		protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
+			executionOrder = 9997;
+			return script;
+		}
+		
+		protected override void OnApplyModifiedProperties() {
+			if (!Application.isPlaying) script.solver.Initiate(script.transform);
+		}
+		
+		protected override void AddInspector() {
+			// Draw the inspector for IKSolverTrigonometric
+			IKSolverArmInspector.AddInspector(solver, !Application.isPlaying, true);
+			
+			// Warning box
+			string message = string.Empty;
+			if (!script.solver.IsValid(ref message)) AddWarningBox(message);
+		}
+		
+		void OnSceneGUI() {
+			// Draw the scene veiw helpers
+			IKSolverArmInspector.AddScene(script.solver, new Color(0f, 1f, 1f, 1f), true);
+		}
+	}
+}

+ 12 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/ArmIKInspector.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 07bc62a41db738b488fc9430a0a20772
+timeCreated: 1528379362
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 115 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/BipedIKInspector.cs

@@ -0,0 +1,115 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections;
+using System;
+
+namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector for Biped IK.
+	 * */
+	[CustomEditor(typeof(BipedIK))]
+	public class BipedIKInspector : Editor {
+		
+		private BipedIK script { get { return target as BipedIK; }}
+		
+		private int selectedSolver = -1;
+		
+		private SerializedProperty references, solvers;
+		private SerializedProperty[] solversProps;
+		private SerializedContent fixTransforms;
+
+		public void OnEnable() {
+			if (serializedObject == null) return;
+
+			// Store the MonoScript for changing script execution order
+			if (!Application.isPlaying) {
+				MonoScript monoScript = MonoScript.FromMonoBehaviour(script);
+
+				// Changing the script execution order to make sure BipedIK always executes after any other script except FullBodyBipedIK
+				int executionOrder = MonoImporter.GetExecutionOrder(monoScript);
+				if (executionOrder != 9998) MonoImporter.SetExecutionOrder(monoScript, 9998);
+			}
+
+			references = serializedObject.FindProperty("references");
+			solvers = serializedObject.FindProperty("solvers");
+			solversProps = BipedIKSolversInspector.FindProperties(solvers);
+			fixTransforms = new SerializedContent(serializedObject.FindProperty("fixTransforms"), new GUIContent("Fix Transforms", "If true, will fix all the Transforms used by the solver to their initial state in each Update. This prevents potential problems with unanimated bones and animator culling with a small cost of performance."));
+			
+			// Automatically detecting references
+			if (!Application.isPlaying) {
+				if (script.references.isEmpty) {
+					BipedReferences.AutoDetectReferences(ref script.references, script.transform, new BipedReferences.AutoDetectParams(false, true));
+					
+					references.isExpanded = true;
+					solvers.isExpanded = false;
+					for (int i = 0; i < solversProps.Length; i++) solversProps[i].isExpanded = false;
+					
+					// Setting default values and initiating
+					script.InitiateBipedIK();
+					script.SetToDefaults();
+					EditorUtility.SetDirty(script);
+				} else script.InitiateBipedIK();
+				
+				Warning.logged = false;
+
+				string message = string.Empty;
+				if (Application.isPlaying) {
+					if (BipedReferences.SetupError(script.references, ref message) || BipedReferences.SetupWarning(script.references, ref message)) {
+						Warning.Log(message, script.references.root, false);
+					}
+				}
+			}
+		}
+
+		// Override the default warning box
+		private void AddWarningBox(string message) {
+			EditorGUILayout.Space();
+
+			EditorGUILayout.LabelField("Invalid/incomplete setup, can't initiate solver. " + message, EditorStyles.helpBox);
+			
+			EditorGUILayout.Space();
+		}
+
+		public override void OnInspectorGUI() {
+			serializedObject.Update();
+
+			EditorGUILayout.Space();
+
+			Inspector.AddContent(fixTransforms);
+			string message = string.Empty;
+
+			// Editing References
+			if (BipedReferencesInspector.AddModifiedInspector(references)) {
+				if (!Application.isPlaying) {
+					Warning.logged = false;
+
+					if (!BipedReferences.SetupError(script.references, ref message)) {
+						script.InitiateBipedIK();
+					}
+				}
+			}
+
+			if (BipedReferences.SetupError(script.references, ref message)) {
+				// Warning box
+				AddWarningBox(message);
+				Warning.Log(message, script.transform, false);
+			} else {
+				// Editing Solvers
+				BipedIKSolversInspector.AddInspector(solvers, solversProps);
+			}
+
+			EditorGUILayout.Space();
+			
+			serializedObject.ApplyModifiedProperties();
+		}
+		
+		void OnSceneGUI() {
+			if (!script.enabled) return;
+
+			// Draw the scene view helpers for the solvers
+			BipedIKSolversInspector.AddScene(script.solvers, ref selectedSolver);
+		}
+	}
+}
+	

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/BipedIKInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: f5864bb0a05eb491697063685c4d6cb3
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 120 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/BipedIKSolversInspector.cs

@@ -0,0 +1,120 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector and scene view tools for Biped IK Solvers.
+	 * */
+	public class BipedIKSolversInspector: IKSolverInspector {
+		
+		/*
+		 * Returns all solvers SeiralizedProperties
+		 * */
+		public static SerializedProperty[] FindProperties(SerializedProperty prop) {
+			SerializedProperty[] props = new SerializedProperty[8] {
+				prop.FindPropertyRelative("leftFoot"),
+				prop.FindPropertyRelative("rightFoot"),
+				prop.FindPropertyRelative("leftHand"),
+				prop.FindPropertyRelative("rightHand"),
+				prop.FindPropertyRelative("spine"),
+				prop.FindPropertyRelative("aim"),
+				prop.FindPropertyRelative("lookAt"),
+				prop.FindPropertyRelative("pelvis"),
+			};
+			
+			return props;
+		}
+		
+		/*
+		 * Draws the custom inspector for BipedIK.Solvers
+		 * */
+		public static void AddInspector(SerializedProperty prop, SerializedProperty[] props) {
+			EditorGUILayout.PropertyField(prop);
+			
+			if (prop.isExpanded) {
+				for (int i = 0; i < props.Length; i++) {
+					BeginProperty(props[i]);
+					if (props[i].isExpanded) {
+						if (i <= 3) IKSolverLimbInspector.AddInspector(props[i], false, false);
+						else if (i == 4) IKSolverHeuristicInspector.AddInspector(props[i], false, false);
+						else if (i == 5) IKSolverAimInspector.AddInspector(props[i], false);
+						else if (i == 6) IKSolverLookAtInspector.AddInspector(props[i], false, false);
+						else if (i == 7) ConstraintsInspector.AddInspector(props[i]);
+					}
+					EndProperty(props[i]);
+				}
+			}
+		}
+		
+		/*
+		 * Draws the scene view helpers for BipedIK.Solvers
+		 * */
+		public static void AddScene(BipedIKSolvers solvers, ref int selected) {
+			// Draw limbs
+			for (int i = 0; i < solvers.limbs.Length; i++) {
+				IKSolverLimbInspector.AddScene(solvers.limbs[i] as IKSolverLimb, GetSolverColor(i), selected == i);
+			}
+			
+			// Draw spine
+			IKSolverHeuristicInspector.AddScene(solvers.spine, GetSolverColor(4), selected == 4);
+			
+			// Draw look at
+			IKSolverLookAtInspector.AddScene(solvers.lookAt, GetSolverColor(5), selected == 5);
+			
+			// Draw aim
+			IKSolverAimInspector.AddScene(solvers.aim, GetSolverColor(6), selected == 6);
+			
+			// Draw constraints
+			ConstraintsInspector.AddScene(solvers.pelvis, GetSolverColor(7), selected == 7);
+
+			// Selecting solvers
+			if (Application.isPlaying) {
+				for (int i = 0; i < solvers.ikSolvers.Length; i++) {
+					Handles.color = GetSolverColor(i);
+					if (solvers.ikSolvers[i].GetIKPositionWeight() > 0 && selected != i && solvers.ikSolvers[i].initiated) {
+						if (Inspector.DotButton(solvers.ikSolvers[i].GetIKPosition(), Quaternion.identity, GetHandleSize(solvers.ikSolvers[i].GetIKPosition()), GetHandleSize(solvers.ikSolvers[i].GetIKPosition()))) selected = i;
+					}
+				}
+				
+				if ((solvers.pelvis.positionWeight > 0 || solvers.pelvis.rotationWeight > 0) && selected != solvers.ikSolvers.Length) {
+					Handles.color = GetSolverColor(7);
+					if (Inspector.DotButton(solvers.pelvis.position, Quaternion.identity, GetHandleSize(solvers.pelvis.position),  GetHandleSize(solvers.pelvis.position))) selected = solvers.ikSolvers.Length;
+				}
+			}
+		}
+		
+		/*
+		 * Gets the color of the solver at index.
+		 * */
+		private static Color GetSolverColor(int index) {
+			if (index == 0 || index == 2) return new Color(0f, 0.8f, 1f, 1f); // Left limb
+			if (index == 1 || index == 3) return new Color(0.3f, 1f, 0.3f, 1f); // Right limb
+			if (index == 4) return new Color(1f, 0.5f, 0.5f, 1f); // Spine
+			if (index == 5) return new Color(0.2f, 0.5f, 1f, 1f); // Look At
+			if (index == 6) return new Color(1f, 0f, 0.5f, 1f); // Aim
+			if (index == 7) return new Color(0.9f, 0.9f, 0.9f, 1f); // Pelvis
+			return Color.white;
+		}
+		
+		/*
+		 * Begin property box
+		 * */
+		private static void BeginProperty(SerializedProperty prop) {
+			EditorGUI.indentLevel = 1;
+			EditorGUILayout.BeginVertical("Box");
+			
+			EditorGUILayout.PropertyField(prop);
+		}
+		
+		/*
+		 * End Property box
+		 * */
+		private static void EndProperty(SerializedProperty prop) {
+			EditorGUILayout.EndVertical();
+			if (prop.isExpanded) EditorGUILayout.Space();
+			EditorGUI.indentLevel = 1;
+		}
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/BipedIKSolversInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 0569aef68e5c24672b37607a948d3c92
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 38 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/CCDIKInspector.cs

@@ -0,0 +1,38 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector for CCDIK.
+	 * */
+	[CustomEditor(typeof(CCDIK))]
+	public class CCDIKInspector : IKInspector {
+
+		private CCDIK script { get { return target as CCDIK; }}
+
+		protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
+			executionOrder = 9997;
+			return script;
+		}
+
+		protected override void OnApplyModifiedProperties() {
+			if (!Application.isPlaying) script.solver.Initiate(script.transform);
+		}
+		
+		protected override void AddInspector() {
+			// Draw the inspector for IKSolverCCD
+			IKSolverHeuristicInspector.AddInspector(solver, !Application.isPlaying, true);
+
+			// Warning box
+			string message = string.Empty;
+			if (!script.solver.IsValid(ref message)) AddWarningBox(message);
+		}
+		
+		void OnSceneGUI() {
+			// Draw the scene veiw helpers
+			IKSolverHeuristicInspector.AddScene(script.solver, Color.cyan, true);
+		}
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/CCDIKInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 90fdc724098474c78a5ae764777a5008
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 67 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/ConstraintsInspector.cs

@@ -0,0 +1,67 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector and scene view tools for Constraints
+	 * */
+	public class ConstraintsInspector: IKSolverInspector {
+		
+		#region Public methods
+
+		/*
+		 * Draws the custom inspector for Constraints
+		 * */
+		public static void AddInspector(SerializedProperty prop) {
+			if (!prop.isExpanded) return;
+			
+			// Main properties
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("target"), new GUIContent("Target", "Target transform for the pelvis (optional). If assigned, will overwrite pelvis.position in each update."));
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("positionOffset"), new GUIContent("Pos Offset", "Pelvis offset from animation. If there is no animation playing and Fix Transforms is unchecked, it will make the character fly away."));
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("positionWeight"), new GUIContent("Pos Weight", "The weight of lerping the pelvis to bipedIK.solvers.pelvis.position."));
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("rotationOffset"), new GUIContent("Rot Offset", "Pelvis rotation offset from animation. If there is no animation playing and Fix Transforms is unchecked, it will make the character spin."));
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("rotationWeight"), new GUIContent("Rot Weight", "The weiight of slerping the pelvis to bipedIK.solver.pelvis.rotation."));
+
+			EditorGUILayout.Space();
+		}
+		
+		/*
+		 * Draws the scene view helpers for Constraints
+		 * */
+		public static void AddScene(Constraints constraints, Color color, bool modifiable) {
+			if (!constraints.IsValid()) return;
+			
+			Handles.color = color;
+			GUI.color = color;
+			
+			// Transform
+			Inspector.SphereCap(0, constraints.transform.position, Quaternion.identity, GetHandleSize(constraints.transform.position));
+
+			// Target
+			Handles.color = new Color(color.r, color.g, color.b, color.a * constraints.positionWeight);
+			Handles.DrawLine(constraints.transform.position, constraints.position);
+			Handles.color = color;
+			
+			if (Application.isPlaying && modifiable && (constraints.positionWeight > 0 || constraints.rotationWeight > 0)) {
+				Inspector.CubeCap(0, constraints.position, Quaternion.Euler(constraints.rotation), GetHandleSize(constraints.transform.position));
+					
+				// Manipulating position and rotation
+				switch(Tools.current) {
+				case Tool.Move:
+					constraints.position = Handles.PositionHandle(constraints.position, Quaternion.Euler(constraints.rotation));
+					break;
+				case Tool.Rotate:
+					constraints.rotation = Handles.RotationHandle(Quaternion.Euler(constraints.rotation), constraints.position).eulerAngles;
+					break;
+				}
+			}
+			
+			Handles.color = Color.white;
+			GUI.color = Color.white;
+		}
+
+		#endregion Public methods
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/ConstraintsInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: b9903cbc6483347caadff80dc461c23f
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 87 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/EditorIKInspector.cs

@@ -0,0 +1,87 @@
+using System.Collections;
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEditor;
+using UnityEditor.SceneManagement;
+
+namespace RootMotion.FinalIK
+{
+    [CustomEditor(typeof(EditorIK))]
+    public class EditorIKInspector : Editor
+    {
+        private EditorIK script { get { return target as EditorIK; } }
+
+        public override void OnInspectorGUI()
+        {
+            base.OnInspectorGUI();
+
+            if (Application.isPlaying) return;
+            if (!script.enabled) return;
+
+            EditorGUILayout.Space();
+
+            if (script.defaultPose != null && script.ik != null && !script.ik.GetIKSolver().executedInEditor)
+            {
+                if (GUILayout.Button("Store Default Pose"))
+                {
+                    script.StoreDefaultPose();
+                    serializedObject.ApplyModifiedProperties();
+
+                    EditorUtility.SetDirty(script.defaultPose);
+                    AssetDatabase.SaveAssets();
+                    AssetDatabase.Refresh();
+                }
+
+                if (script.defaultPose.poseStored && script.defaultPose.localPositions.Length == script.bones.Length)
+                {
+                    if (GUILayout.Button("Reset To Default Pose"))
+                    {
+                        script.defaultPose.Restore(script.bones);
+
+                        EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
+                    }
+                }
+            }
+
+            EditorGUILayout.Space();
+
+            if (script.defaultPose != null && script.defaultPose.poseStored && script.ik != null)
+            {
+                if (!script.ik.GetIKSolver().executedInEditor)
+                {
+                    bool isValid = script.ik.GetIKSolver().IsValid();
+                    EditorGUI.BeginDisabledGroup(!isValid);
+                    if (GUILayout.Button(isValid? "Start Solver": "'Start Solver' disabled for invalid solver setup"))
+                    {
+                        bool initiated = script.Initiate();
+                        serializedObject.ApplyModifiedProperties();
+
+                        EditorUtility.SetDirty(script.defaultPose);
+                        AssetDatabase.SaveAssets();
+                        AssetDatabase.Refresh();
+
+                        var ikS = new SerializedObject(script.ik);
+                        ikS.FindProperty("solver").FindPropertyRelative("executedInEditor").boolValue = initiated;
+                        ikS.ApplyModifiedProperties();
+
+                        script.Update();
+
+                        EditorSceneManager.MarkSceneDirty(EditorSceneManager.GetActiveScene());
+                    }
+                    EditorGUI.EndDisabledGroup();
+                }
+
+                if (script.ik.GetIKSolver().executedInEditor)
+                {
+                    if (GUILayout.Button("Stop"))
+                    {
+                        var ikS = new SerializedObject(script.ik);
+                        ikS.FindProperty("solver").FindPropertyRelative("executedInEditor").boolValue = false;
+                        ikS.ApplyModifiedProperties();
+                    }
+                }
+            }
+        }
+
+    }
+}

+ 11 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/EditorIKInspector.cs.meta

@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4bdb775e141709e40972e0ed29aecc04
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 38 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/FABRIKInspector.cs

@@ -0,0 +1,38 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector for FABRIK.
+	 * */
+	[CustomEditor(typeof(FABRIK))]
+	public class FABRIKInspector : IKInspector {
+
+		private FABRIK script { get { return target as FABRIK; }}
+
+		protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
+			executionOrder = 9997;
+			return script;
+		}
+		
+		protected override void OnApplyModifiedProperties() {
+			if (!Application.isPlaying) script.solver.Initiate(script.transform);
+		}
+		
+		protected override void AddInspector() {
+			// Draw the inspector for IKSolverFABRIK
+			IKSolverHeuristicInspector.AddInspector(solver, !Application.isPlaying, false);
+
+			// Warning box
+			string message = string.Empty;
+			if (!script.solver.IsValid(ref message)) AddWarningBox(message);
+		}
+		
+		void OnSceneGUI() {
+			// Draw the scene veiw helpers
+			IKSolverHeuristicInspector.AddScene(script.solver, Color.cyan, true);
+		}
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/FABRIKInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 35028d751824a4378ab31047db78a4ac
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 35 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/FABRIKRootInspector.cs

@@ -0,0 +1,35 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector for FABRIKRoot.
+	 * */
+	[CustomEditor(typeof(FABRIKRoot))]
+	public class FABRIKRootInspector : IKInspector {
+
+		private FABRIKRoot script { get { return target as FABRIKRoot; }}
+		private FABRIKChain selectedChain;
+
+		protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
+			executionOrder = 9997;
+			return script;
+		}
+		
+		protected override void AddInspector() {
+			// Draw the inspector for IKSolverFABRIKRoot
+			IKSolverFABRIKRootInspector.AddInspector(solver, !Application.isPlaying);
+
+			// Warning box
+			string message = string.Empty;
+			if (!script.solver.IsValid(ref message)) AddWarningBox(message);
+		}
+		
+		void OnSceneGUI() {
+			// Draw the scene veiw helpers
+			IKSolverFABRIKRootInspector.AddScene(script.solver, Color.cyan, true, ref selectedChain);
+		}
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/FABRIKRootInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 97f4f303b23be42ddabd838850dd9c03
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 99 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/FingerRigInspector.cs

@@ -0,0 +1,99 @@
+using UnityEngine;
+using System.Collections;
+using UnityEditor;
+
+namespace RootMotion.FinalIK {
+
+	// Custom Scene View handles for the FingerRig.
+	[CustomEditor(typeof(FingerRig))]
+	public class FingerRigInspector : Editor {
+
+		private FingerRig script { get { return target as FingerRig; }}
+		
+		private int selected = -1;
+		private MonoScript monoScript;
+
+		void OnEnable() {
+			if (serializedObject == null) return;
+			
+			// Changing the script execution order
+			if (!Application.isPlaying) {
+				monoScript = MonoScript.FromMonoBehaviour(script);
+				int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
+				if (currentExecutionOrder != 10000) MonoImporter.SetExecutionOrder(monoScript, 10000);
+			}
+		}
+
+		void OnSceneGUI() {
+			if (!script.enabled) return;
+			string message = string.Empty;
+			if (!script.IsValid(ref message)) return;
+			if (Application.isPlaying && !script.initiated) return;
+
+			Color color = Color.cyan;
+			color.a = script.weight;
+
+			Handles.color = color;
+			GUI.color = color;
+
+			// Display the bones
+			if (!Application.isPlaying) {
+				for (int i = 0; i < script.fingers.Length; i++) {
+					Handles.DrawLine(script.fingers[i].bone1.position, script.fingers[i].bone2.position);
+					Inspector.SphereCap(0, script.fingers[i].bone1.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].bone1.position) * 0.5f);
+					Inspector.SphereCap(0, script.fingers[i].bone2.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].bone2.position) * 0.5f);
+
+					if (script.fingers[i].bone3 != null) {
+						Handles.DrawLine(script.fingers[i].bone2.position, script.fingers[i].bone3.position);
+						Handles.DrawLine(script.fingers[i].bone3.position, script.fingers[i].tip.position);
+						Inspector.SphereCap(0, script.fingers[i].bone3.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].bone3.position) * 0.5f);
+					} else {
+						Handles.DrawLine(script.fingers[i].bone2.position, script.fingers[i].tip.position);
+					}
+
+					Inspector.SphereCap(0, script.fingers[i].tip.position, Quaternion.identity, IKSolverInspector.GetHandleSize(script.fingers[i].tip.position) * 0.5f);
+				}
+			}
+
+			// Selecting solvers
+			if (Application.isPlaying) {
+				if (selected >= 0 && selected < script.fingers.Length) {
+					if (script.fingers[selected].weight > 0f) {
+						color.a = script.weight * script.fingers[selected].weight;
+						Handles.color = color;
+
+						float size = IKSolverInspector.GetHandleSize(script.fingers[selected].IKPosition);
+
+						Inspector.CubeCap(0, script.fingers[selected].IKPosition, script.fingers[selected].IKRotation, size);
+
+						if (script.fingers[selected].target == null) {
+							switch(Tools.current) {
+							case Tool.Move:
+								script.fingers[selected].IKPosition = Handles.PositionHandle(script.fingers[selected].IKPosition, Tools.pivotRotation == PivotRotation.Local? script.fingers[selected].IKRotation: Quaternion.identity);
+								break;
+							case Tool.Rotate:
+								script.fingers[selected].IKRotation = Handles.RotationHandle(script.fingers[selected].IKRotation, script.fingers[selected].IKPosition);
+								break;
+							}
+						}
+					}
+				}
+
+				for (int i = 0; i < script.fingers.Length; i++) {
+					color.a = script.weight * script.fingers[i].weight;
+					Handles.color = color;
+					Handles.DrawLine(script.fingers[i].tip.position, script.fingers[i].IKPosition);
+
+					if (script.fingers[i].weight > 0 && selected != i && script.fingers[i].initiated) {
+						float size = IKSolverInspector.GetHandleSize(script.fingers[i].IKPosition) * 0.5f;
+
+						if (Inspector.DotButton(script.fingers[i].IKPosition, Quaternion.identity, size, size)) selected = i;
+					}
+				}
+			}
+
+			Handles.color = Color.white;
+			GUI.color = Color.white;
+		}
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/FingerRigInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: aa6fa0b5b780d4401b031336dd86cfa4
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 107 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/FullBodyBipedIKInspector.cs

@@ -0,0 +1,107 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections;
+
+	namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector for FullBodyBipedIK.
+	 * */
+	[CustomEditor(typeof(FullBodyBipedIK))]
+	public class FullBodyBipedIKInspector : IKInspector {
+
+		private FullBodyBipedIK script { get { return target as FullBodyBipedIK; }}
+		private int selectedEffector;
+		private SerializedProperty references;
+		private bool autodetected;
+
+		private static Color color {
+			get {
+				return new Color(0f, 0.75f, 1f);
+			}
+		}
+
+		protected override MonoBehaviour GetMonoBehaviour(out int executionOrder) {
+			executionOrder = 9999;
+			return script;
+		}
+
+		protected override void OnEnableVirtual() {
+			references = serializedObject.FindProperty("references");
+
+			// Autodetecting References
+			if (script.references.IsEmpty(false) && script.enabled) {
+				BipedReferences.AutoDetectReferences(ref script.references, script.transform, new BipedReferences.AutoDetectParams(true, false));
+
+				script.solver.rootNode = IKSolverFullBodyBiped.DetectRootNodeBone(script.references);
+
+				Initiate();
+
+				if (Application.isPlaying) Warning.Log("Biped references were auto-detected on a FullBodyBipedIK component that was added in runtime. Note that this only happens in the Editor and if the GameObject is selected (for quick and convenient debugging). If you want to add FullBodyBipedIK dynamically in runtime via script, you will have to use BipedReferences.AutodetectReferences() for automatic biped detection.", script.transform);
+				
+				references.isExpanded = !script.references.isFilled;
+			}
+		}
+
+		protected override void AddInspector() {
+			// While in editor
+			if (!Application.isPlaying) {
+				// Editing References, if they have changed, reinitiate.
+				if (BipedReferencesInspector.AddModifiedInspector(references)) {
+					Initiate();
+					return; // Don't draw immediatelly to avoid errors
+				}
+				// Root Node
+				IKSolverFullBodyBipedInspector.AddReferences(true, solver);
+
+				// Reinitiate if rootNode has changed
+				if (serializedObject.ApplyModifiedProperties()) {
+					Initiate();
+					return; // Don't draw immediatelly to avoid errors
+				}
+			} else {
+				// While in play mode
+
+				// Draw the references and the root node for UMA
+				BipedReferencesInspector.AddModifiedInspector(references);	
+				IKSolverFullBodyBipedInspector.AddReferences(true, solver);
+			}
+
+			string errorMessage = string.Empty;
+			if (script.ReferencesError(ref errorMessage) || !script.solver.IsValid(ref errorMessage)) {
+				AddWarningBox(errorMessage);
+				Warning.Log(errorMessage, script.transform, false);
+			} else {
+				// Draw the inspector for IKSolverFullBody
+				IKSolverFullBodyBipedInspector.AddInspector(solver, false);
+			}
+
+			EditorGUILayout.Space();
+		}
+
+		private void Initiate() {
+			Warning.logged = false;
+
+			// Check for possible errors, if found, do not initiate
+			string message = "";
+			if (script.ReferencesError(ref message)) {
+				Warning.Log(message, script.transform, false);
+				return;
+			}
+
+			// Notify of possible problems, but still initiate
+			if (script.ReferencesWarning(ref message)) Warning.Log(message, script.transform, false);
+
+			// Initiate
+			script.solver.SetToReferences(script.references, script.solver.rootNode);
+		}
+
+		// Draw the scene view handles
+		void OnSceneGUI() {
+			// Draw the scene veiw helpers
+			if (!script.references.isFilled) return;
+
+			IKSolverFullBodyBipedInspector.AddScene(target, script.solver, color, ref selectedEffector, script.transform);
+		}
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/FullBodyBipedIKInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: a1af94c10682a46c0849b487ad86dd40
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 13 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/GroundingInspector.cs

@@ -0,0 +1,13 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+
+	public class GroundingInspector : Editor {
+
+		public static void Visualize(Grounding grounding, Transform root, Transform foot) {
+			Inspector.SphereCap (0, foot.position + root.forward * grounding.footCenterOffset, root.rotation, grounding.footRadius * 2f);
+		}
+	}
+}

+ 12 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/GroundingInspector.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 43cffbb650ededd4bbfb46bf19a74782
+timeCreated: 1487065127
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 106 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKEffectorInspector.cs

@@ -0,0 +1,106 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector and scene view tools for IKEffector
+	 * */
+	public class IKEffectorInspector: IKSolverInspector {
+		
+		#region Public methods
+		
+		public static void DrawArrayElementEffector(SerializedProperty effector, bool editHierarchy) {
+			if (!editHierarchy) return;
+			
+			if (effector.FindPropertyRelative("bones").arraySize > 1) {
+				GUILayout.BeginHorizontal();
+				GUILayout.Space(indent);
+				AddClampedFloat(effector.FindPropertyRelative("falloff"), new GUIContent("Distance Falloff", string.Empty), 0f, Mathf.Infinity);
+				GUILayout.EndHorizontal();
+			}
+			
+			AddArray(effector.FindPropertyRelative("bones"), new GUIContent("Bones", string.Empty), editHierarchy, false, null, OnAddToArrayBone, DrawArrayElementLabelBone, false);
+			
+			if (effector.isExpanded) EditorGUILayout.Space();
+		}
+		
+		public static void OnAddToArrayEffector(SerializedProperty effector) {
+			effector.FindPropertyRelative("positionWeight").floatValue = 0f;
+			effector.FindPropertyRelative("rotationWeight").floatValue = 0f;
+			effector.FindPropertyRelative("falloff").floatValue = 0.5f;
+			effector.FindPropertyRelative("position").vector3Value = Vector3.zero;
+			effector.FindPropertyRelative("positionOffset").vector3Value = Vector3.zero;
+		}
+		
+		public static void DrawArrayElementLabelEffector(SerializedProperty effector, bool editHierarchy) {
+			GUILayout.Space(Inspector.indent);
+			if (editHierarchy) {
+				EditorGUILayout.PropertyField(effector, new GUIContent(GetArrayName(effector.FindPropertyRelative("bones"), "Effector"), string.Empty), false, GUILayout.Width(100));
+			} else {
+				EditorGUILayout.LabelField(new GUIContent(GetArrayName(effector.FindPropertyRelative("bones"), "Effector"), string.Empty), GUILayout.Width(100));
+			}
+			
+			GUILayout.Space(10);
+			
+			GUILayout.Label("Position", GUILayout.Width(50));
+			effector.FindPropertyRelative("positionWeight").floatValue = GUILayout.HorizontalSlider(effector.FindPropertyRelative("positionWeight").floatValue, 0f, 1f, GUILayout.Width(50));
+			
+			GUILayout.Space(5);
+				
+			GUILayout.Label("Rotation", GUILayout.Width(50));
+			effector.FindPropertyRelative("rotationWeight").floatValue = GUILayout.HorizontalSlider(effector.FindPropertyRelative("rotationWeight").floatValue, 0f, 1f, GUILayout.Width(50));
+			
+			if (!editHierarchy && effector.FindPropertyRelative("bones").arraySize > 1) {
+				EditorGUILayout.LabelField(new GUIContent("Falloff", string.Empty), GUILayout.Width(50));
+				EditorGUILayout.PropertyField(effector.FindPropertyRelative("falloff"), GUIContent.none);
+				effector.FindPropertyRelative("falloff").floatValue = Mathf.Clamp(effector.FindPropertyRelative("falloff").floatValue, 0f, Mathf.Infinity);
+			}
+			
+		}
+		
+		public static void AddScene(IKEffector e, Color color, bool modifiable, float size) {
+			if (!modifiable) return;
+			
+			// Draw effectors
+			bool rotate = e.isEndEffector;
+			float weight = rotate? Mathf.Max(e.positionWeight, e.rotationWeight): e.positionWeight;
+			
+			if (e.bone != null && weight > 0) {
+					
+				//if (Application.isPlaying) {
+					Handles.color = new Color(color.r, color.g, color.b, weight);
+
+					Handles.DrawLine(e.position, e.bone.position);
+					Inspector.SphereCap(0, e.bone.position, Quaternion.identity, size * 0.5f);
+
+					// Manipulating position and rotation
+					if (e.target == null) {
+						switch(Tools.current) {
+						case Tool.Move:
+							e.position = Handles.PositionHandle(e.position, Quaternion.identity);
+							break;
+						case Tool.Rotate:
+							if (rotate) e.rotation = Handles.RotationHandle(e.rotation, e.position);
+							break;
+						}
+					}
+					
+					if (rotate) Inspector.CubeCap(0, e.position, e.rotation, size);
+					else Inspector.SphereCap(0, e.position, Quaternion.identity, size);
+				//}
+			}
+		}
+		
+		#endregion Public methods
+		
+		private static void DrawArrayElementLabelBone(SerializedProperty bone, bool editHierarchy) {
+			AddObjectReference(bone, GUIContent.none, editHierarchy, 0, 300);
+		}
+		
+		private static void OnAddToArrayBone(SerializedProperty bone) {
+			bone.objectReferenceValue = null;
+		}
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKEffectorInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: f11a75612fdb244758156ae2d26a95ec
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 27 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKExecutionOrderInspector.cs

@@ -0,0 +1,27 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+
+	// Custom inspector for IKExecutionOrder
+	[CustomEditor(typeof(IKExecutionOrder))]
+	public class IKExecutionOrderInspector : Editor {
+
+		private IKExecutionOrder script { get { return target as IKExecutionOrder; }}
+
+		private MonoScript monoScript;
+
+		void OnEnable() {
+			if (serializedObject == null) return;
+			
+			// Changing the script execution order
+			if (!Application.isPlaying) {
+				int executionOrder = 9996;
+				monoScript = MonoScript.FromMonoBehaviour(script);
+				int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
+				if (currentExecutionOrder != executionOrder) MonoImporter.SetExecutionOrder(monoScript, executionOrder);
+			}
+		}
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKExecutionOrderInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: e2d73247f9c4b4190a30f8e4cc054bc5
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 67 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKInspector.cs

@@ -0,0 +1,67 @@
+using UnityEditor;
+using UnityEngine;
+using System.Collections;
+
+namespace RootMotion.FinalIK {
+
+	/*
+	 * Base abstract class for IK component inspectors.
+	 * */
+	public abstract class IKInspector : Editor {
+		
+		protected abstract void AddInspector();
+		protected abstract MonoBehaviour GetMonoBehaviour(out int executionOrder);
+
+		protected SerializedProperty solver;
+		protected SerializedContent fixTransforms;
+		protected SerializedContent[] content;
+		protected virtual void OnApplyModifiedProperties() {}
+		protected virtual void OnEnableVirtual() {}
+
+		private MonoScript monoScript;
+
+		void OnEnable() {
+			if (serializedObject == null) return;
+
+			// Changing the script execution order
+			if (!Application.isPlaying) {
+				int executionOrder = 0;
+				monoScript = MonoScript.FromMonoBehaviour(GetMonoBehaviour(out executionOrder));
+				int currentExecutionOrder = MonoImporter.GetExecutionOrder(monoScript);
+				if (currentExecutionOrder != executionOrder) MonoImporter.SetExecutionOrder(monoScript, executionOrder);
+			}
+
+			solver = serializedObject.FindProperty("solver");
+			fixTransforms = new SerializedContent(serializedObject.FindProperty("fixTransforms"), new GUIContent("Fix Transforms", "If true, will fix all the Transforms used by the solver to their initial state in each Update. This prevents potential problems with unanimated bones and animator culling with a small cost of performance. Not recommended for CCD and FABRIK solvers."));
+
+			OnEnableVirtual();
+		}
+
+		// Override the default warning box
+		protected virtual void AddWarningBox(string message) {
+			EditorGUILayout.Space();
+			
+			EditorGUILayout.LabelField("Invalid/incomplete setup, can not initiate the solver. " + message, EditorStyles.helpBox);
+			
+			EditorGUILayout.Space();
+		}
+
+		#region Inspector
+		
+		public override void OnInspectorGUI() {
+			if (serializedObject == null) return;
+
+			serializedObject.Update();
+			
+			Inspector.AddContent(fixTransforms);
+			
+			AddInspector();
+
+			if (serializedObject.ApplyModifiedProperties()) {
+				OnApplyModifiedProperties();
+			}
+		}
+
+		#endregion Inspector
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 00e26cb6b10c641c49833ea4316e25cf
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 103 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverAimInspector.cs

@@ -0,0 +1,103 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+using System;
+
+	namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector and scene view tools for IKSolverAim
+	 * */
+	public class IKSolverAimInspector: IKSolverInspector {
+
+		#region Public methods
+		
+		/// <summary>
+		/// Draws the custom inspector for IKSolverAim
+		/// </summary>
+		public static void AddInspector(SerializedProperty prop, bool editHierarchy) {
+			IKSolverHeuristicInspector.AddTarget(prop);
+			if (!prop.FindPropertyRelative("XY").boolValue) EditorGUILayout.PropertyField(prop.FindPropertyRelative("poleTarget"), new GUIContent("Pole Target", "If assigned, will automatically set polePosition to the position of this Transform."));
+
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("transform"), new GUIContent("Aim Transform", "The transform that you want to be aimed at the target. Needs to be a lineal descendant of the bone hierarchy. For example, if you wish to aim a gun, it should be the gun, one of it's children or the hand bone."));
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("axis"), new GUIContent("Axis", "The local axis of the Transform that you want to be aimed at IKPosition."));
+			if (!prop.FindPropertyRelative("XY").boolValue) EditorGUILayout.PropertyField(prop.FindPropertyRelative("poleAxis"), new GUIContent("Pole Axis", "Keeps that axis of the Aim Transform directed at the polePosition."));
+
+			EditorGUILayout.Space();
+			IKSolverHeuristicInspector.AddIKPositionWeight(prop);
+
+			if (!prop.FindPropertyRelative("XY").boolValue) EditorGUILayout.PropertyField(prop.FindPropertyRelative("poleWeight"), new GUIContent("Pole Weight", "The weight of the Pole."));
+
+			IKSolverHeuristicInspector.AddProps(prop);
+
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("clampWeight"), new GUIContent("Clamp Weight", "Clamping rotation of the solver. 0 is free rotation, 1 is completely clamped to transform axis."));
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("clampSmoothing"), new GUIContent("Clamp Smoothing", "Number of sine smoothing iterations applied on clamping to make the clamping point smoother."));
+
+			IKSolverHeuristicInspector.AddBones(prop, editHierarchy, true);
+		}
+		
+		/// <summary>
+		/// Draws the scene view helpers for IKSolverAim
+		/// </summary>
+		public static void AddScene(IKSolverAim solver, Color color, bool modifiable) {
+			// Protect from null reference errors
+			if (solver.transform == null) return;
+			if (Application.isPlaying && !solver.initiated) return;
+
+			if (!Application.isPlaying) {
+				string message = string.Empty;
+				if (!solver.IsValid(ref message)) return;
+			}
+			
+			Handles.color = color;
+			GUI.color = color;
+			
+			// Display the bones
+			for (int i = 0; i < solver.bones.Length; i++) {
+				IKSolver.Bone bone = solver.bones[i];
+
+				if (i < solver.bones.Length - 1) Handles.DrawLine(bone.transform.position, solver.bones[i + 1].transform.position);
+				Inspector.SphereCap(0, solver.bones[i].transform.position, Quaternion.identity, GetHandleSize(solver.bones[i].transform.position));
+			}
+			
+			if (solver.axis != Vector3.zero) Inspector.ConeCap(0, solver.transform.position, Quaternion.LookRotation(solver.transform.rotation * solver.axis), GetHandleSize(solver.transform.position) * 2f);
+			
+			// Selecting joint and manipulating IKPosition
+			if (Application.isPlaying && solver.IKPositionWeight > 0) {
+				if (modifiable) {
+					Inspector.SphereCap(0, solver.IKPosition, Quaternion.identity, GetHandleSize(solver.IKPosition));
+						
+					// Manipulating position
+					solver.IKPosition = Handles.PositionHandle(solver.IKPosition, Quaternion.identity);
+				}
+				
+				// Draw a transparent line from transform to IKPosition
+				Handles.color = new Color(color.r, color.g, color.b, color.a * solver.IKPositionWeight);
+				Handles.DrawLine(solver.bones[solver.bones.Length - 1].transform.position, solver.transform.position);
+				Handles.DrawLine(solver.transform.position, solver.IKPosition);
+			}
+
+			Handles.color = color;
+
+			// Pole
+			if (Application.isPlaying && solver.poleWeight > 0f) {
+				if (modifiable) {
+					Inspector.SphereCap(0, solver.polePosition, Quaternion.identity, GetHandleSize(solver.IKPosition) * 0.5f);
+					
+					// Manipulating position
+					solver.polePosition = Handles.PositionHandle(solver.polePosition, Quaternion.identity);
+				}
+
+				// Draw a transparent line from transform to polePosition
+				Handles.color = new Color(color.r, color.g, color.b, color.a * solver.poleWeight);
+				Handles.DrawLine(solver.transform.position, solver.polePosition);
+			}
+			
+			Handles.color = Color.white;
+			GUI.color = Color.white;
+		}
+		
+		#endregion Public methods
+
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverAimInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 13082609a38964d0486119efce14e42c
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

Файловите разлики са ограничени, защото са твърде много
+ 101 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverArmInspector.cs


+ 12 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverArmInspector.cs.meta

@@ -0,0 +1,12 @@
+fileFormatVersion: 2
+guid: 2096c71e8e55def4bafe5d7f1604ea55
+timeCreated: 1528379406
+licenseType: Store
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 94 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverFABRIKRootInspector.cs

@@ -0,0 +1,94 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+
+	namespace RootMotion.FinalIK {
+
+	/*
+	 * Custom inspector and scene view tools for IKSolverFABRIKRoot
+	 * */
+	public class IKSolverFABRIKRootInspector : IKSolverInspector {
+		
+		#region Public methods
+		
+		/*
+		 * Draws the custom inspector for IKSolverFABRIKRoot
+		 * */
+		public static void AddInspector(SerializedProperty prop, bool editHierarchy) {
+			AddClampedInt(prop.FindPropertyRelative("iterations"), new GUIContent("Iterations", "Solver iterations."), 0, int.MaxValue);
+
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("IKPositionWeight"), new GUIContent("Weight", "Solver weight."));
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("rootPin"), new GUIContent("Root Pin", "Weight of keeping all FABRIK Trees pinned to the root position."));
+			
+			EditorGUILayout.Space();
+
+			EditorGUI.indentLevel = 0;
+			EditorGUILayout.PropertyField(prop.FindPropertyRelative("chains"), new GUIContent("Chains", "FABRIK chains."), true);
+			
+			EditorGUILayout.Space();
+		}
+		
+		/*
+		 * Draws the scene view helpers for IKSolverFABRIKRoot
+		 * */
+		public static void AddScene(IKSolverFABRIKRoot solver, Color color, bool modifiable, ref FABRIKChain selected) {
+			// Protect from null reference errors
+			if (Application.isPlaying && !solver.initiated) return;
+			if (!Application.isPlaying) {
+				string message = string.Empty;
+				if (!solver.IsValid(ref message)) return;
+			}
+			Handles.color = color;
+			
+			// Selecting solvers
+			if (Application.isPlaying) {
+				SelectChain(solver.chains, ref selected, color);
+			}
+			
+			AddSceneChain(solver.chains, color, selected);
+			
+			// Root pin
+			Handles.color = new Color(Mathf.Lerp(1f, color.r, solver.rootPin), Mathf.Lerp(1f, color.g, solver.rootPin), Mathf.Lerp(1f, color.b, solver.rootPin), Mathf.Lerp(0.5f, 1f, solver.rootPin));
+			if (solver.GetRoot() != null) {
+				Handles.DrawLine(solver.chains[0].ik.solver.bones[0].transform.position, solver.GetRoot().position);
+				Inspector.CubeCap(0, solver.GetRoot().position, Quaternion.identity, GetHandleSize(solver.GetRoot().position));
+			}
+		}
+		
+		#endregion Public methods
+		
+		private static Color col, midColor, endColor;
+		
+		private static void SelectChain(FABRIKChain[] chain, ref FABRIKChain selected, Color color) {
+			foreach (FABRIKChain c in chain) {
+				if (c.ik.solver.IKPositionWeight > 0 && selected != c) {
+					Handles.color = GetChainColor(c, color);
+
+					if (Inspector.DotButton(c.ik.solver.GetIKPosition(), Quaternion.identity, GetHandleSize(c.ik.solver.GetIKPosition()), GetHandleSize(c.ik.solver.GetIKPosition()))) {
+						selected = c;
+						return;
+					}
+				}
+			}
+		}
+		
+		private static Color GetChainColor(FABRIKChain chain, Color color) {
+			float midWeight = chain.pin;
+			midColor = new Color(Mathf.Lerp(1f, color.r, midWeight), Mathf.Lerp(1f, color.g, midWeight), Mathf.Lerp(1f, color.b, midWeight), Mathf.Lerp(0.5f, 1f, midWeight));
+			
+			float endWeight = chain.pull;
+			endColor = new Color(Mathf.Lerp(1f, color.r, endWeight), Mathf.Lerp(0f, color.g, endWeight), Mathf.Lerp(0f, color.b, endWeight), Mathf.Lerp(0.5f, 1f, endWeight));
+			
+			return chain.children.Length == 0? endColor: midColor;
+		}
+		
+		private static void AddSceneChain(FABRIKChain[] chain, Color color, FABRIKChain selected) {
+			foreach (FABRIKChain c in chain) {
+				col = GetChainColor(c, color);
+				
+				IKSolverHeuristicInspector.AddScene(c.ik.solver as IKSolverHeuristic, col, selected == c);
+			}
+		}
+	}
+}
+

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverFABRIKRootInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 47b6cc68611af428d82361a2eb3d8505
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 339 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverFullBodyBipedInspector.cs

@@ -0,0 +1,339 @@
+using UnityEngine;
+using UnityEditor;
+using System.Collections;
+using System;
+
+namespace RootMotion.FinalIK {
+
+	// Custom inspector and scene view tools for IKSolverFullBodyBiped
+	public class IKSolverFullBodyBipedInspector : IKSolverInspector {
+		
+		#region Public methods
+		
+		public static void AddReferences(bool editHierarchy, SerializedProperty prop) {
+			// RootNode
+			if (editHierarchy) {
+				EditorGUILayout.PropertyField(prop.FindPropertyRelative("rootNode"), new GUIContent("Root Node", "Select one of the bones in the (lower) spine."));
+			}
+		}
+		
+		// Draws the custom inspector for IKSolverFullBodybiped
+		public static void AddInspector(SerializedProperty prop, bool editWeights) {
+			IKSolverFullBodyInspector.AddInspector(prop, editWeights);
+			
+			EditorGUILayout.Space();
+			EditorGUI.indentLevel = 0;
+
+			AddSolver(prop);
+		}
+
+
+		// Draws the scene view helpers for IKSolverFullBodyBiped
+		public static void AddScene(UnityEngine.Object target, IKSolverFullBodyBiped solver, Color color, ref int selectedEffector, Transform root) {
+			if (Application.isPlaying && !solver.initiated) return;
+			if (!Application.isPlaying && !solver.IsValid()) return;
+
+			bool modifiable = solver.initiated;
+
+			float heightF = Vector3.Distance(solver.chain[1].nodes[0].transform.position, solver.chain[1].nodes[1].transform.position) + 
+				Vector3.Distance(solver.chain[3].nodes[0].transform.position, solver.chain[3].nodes[1].transform.position);
+
+			float size = Mathf.Clamp(heightF * 0.075f, 0.001f, Mathf.Infinity);
+
+			// Bend goals
+			for (int i = 0; i < solver.chain.Length; i++) {
+				if (solver.chain[i].nodes.Length == 3 && solver.chain[i].bendConstraint.bendGoal != null && solver.chain[i].bendConstraint.weight > 0f) {
+					Color c = color;
+					c.a = solver.chain[i].bendConstraint.weight;
+					Handles.color = c;
+					
+					Handles.DrawLine(solver.chain[i].nodes[1].transform.position, solver.chain[i].bendConstraint.bendGoal.position);
+					Inspector.SphereCap(0, solver.chain[i].nodes[1].transform.position, Quaternion.identity, size * 0.5f);
+					Inspector.SphereCap(0, solver.chain[i].bendConstraint.bendGoal.position, Quaternion.identity, size * 0.5f);
+					
+					Handles.color = Color.white;
+				}
+			}
+
+			// Chain
+			if (!modifiable) {
+				for (int i = 0; i < solver.chain.Length; i++) {
+					IKSolverFullBodyInspector.AddChain(solver.chain, i, color, size);
+				}
+
+				Handles.DrawLine(solver.chain[1].nodes[0].transform.position, solver.chain[2].nodes[0].transform.position);
+				Handles.DrawLine(solver.chain[3].nodes[0].transform.position, solver.chain[4].nodes[0].transform.position);
+
+				AddLimbHelper(solver.chain[1], size);
+				AddLimbHelper(solver.chain[2], size);
+				AddLimbHelper(solver.chain[3], size, root);
+				AddLimbHelper(solver.chain[4], size, root);
+			}
+			
+			// Effectors
+			IKSolverFullBodyInspector.AddScene(target, solver, color, modifiable, ref selectedEffector, size);
+		}
+
+		// Scene view handles to help with limb setup
+		private static void AddLimbHelper(FBIKChain chain, float size, Transform root = null) {
+			Vector3 cross = Vector3.Cross((chain.nodes[1].transform.position - chain.nodes[0].transform.position).normalized, (chain.nodes[2].transform.position - chain.nodes[0].transform.position).normalized);
+
+			Vector3 bendDirection = -Vector3.Cross(cross.normalized, (chain.nodes[2].transform.position - chain.nodes[0].transform.position).normalized);
+
+			if (bendDirection != Vector3.zero) {
+				Color c = Handles.color;
+				bool inverted = root != null && Vector3.Dot(root.forward, bendDirection.normalized) < 0f;
+
+				// Inverted bend direction
+				if (inverted) {
+					GUI.color = new Color(1f, 0.75f, 0.75f);
+					Handles.color = Color.yellow;
+
+					if (Inspector.DotButton(chain.nodes[1].transform.position, Quaternion.identity, size * 0.5f, size)) {
+						Warning.logged = false;
+						Warning.Log("The bend direction of this limb appears to be inverted. Please rotate this bone so that the limb is bent in it's natural bending direction. If this limb is supposed to be bent in the direction pointed by the arrow, ignore this warning.", root, true);
+					}
+				}
+
+				Inspector.ArrowCap(0, chain.nodes[1].transform.position, Quaternion.LookRotation(bendDirection), size * 2f);
+
+				GUI.color = Color.white;
+				Handles.color = c;
+			} else {
+				// The limb is completely stretched out
+				Color c = Handles.color;
+				Handles.color = Color.red;
+				GUI.color = new Color(1f, 0.75f, 0.75f);
+
+				if (Inspector.DotButton(chain.nodes[1].transform.position, Quaternion.identity, size * 0.5f, size)) {
+					Warning.logged = false;
+					Warning.Log("The limb is completely stretched out. Full Body Biped IK does not know which way the limb should be bent. Please rotate this bone slightly in it's bending direction.", root, true);
+				}
+
+				GUI.color = Color.white;
+				Handles.color = c;
+			}
+		}
+		
+		#endregion Public methods
+		
+		private const string style = "Box";
+
+		private static void AddProperty(SerializedProperty prop, GUIContent guiContent) {
+			GUILayout.BeginHorizontal();
+			GUILayout.Space(50);
+			EditorGUILayout.PropertyField(prop, guiContent);
+			GUILayout.Space(20);
+			GUILayout.EndHorizontal();
+		}
+
+		private static void AddSolver(SerializedProperty prop) {
+			var chains = prop.FindPropertyRelative("chain");
+
+			AddBody(prop, chains.GetArrayElementAtIndex(0), new GUIContent("Body", string.Empty));
+			AddLimb(prop, chains.GetArrayElementAtIndex(1), FullBodyBipedChain.LeftArm, new GUIContent("Left Arm", string.Empty));
+			AddLimb(prop, chains.GetArrayElementAtIndex(2), FullBodyBipedChain.RightArm, new GUIContent("Right Arm", string.Empty));
+			AddLimb(prop, chains.GetArrayElementAtIndex(3), FullBodyBipedChain.LeftLeg, new GUIContent("Left Leg", string.Empty));
+			AddLimb(prop, chains.GetArrayElementAtIndex(4), FullBodyBipedChain.RightLeg, new GUIContent("Right Leg", string.Empty));
+		}
+
+		private static void AddBody(SerializedProperty prop, SerializedProperty chain, GUIContent guiContent) {
+			EditorGUILayout.PropertyField(chain, guiContent, false);
+			GUILayout.BeginHorizontal();
+			GUILayout.Space(10);
+			GUILayout.BeginVertical();
+
+			if (chain.isExpanded) {
+				var effectors = prop.FindPropertyRelative("effectors");
+				var effector = effectors.GetArrayElementAtIndex(0);
+				var spineMapping = prop.FindPropertyRelative("spineMapping");
+				var headMapping = prop.FindPropertyRelative("boneMappings").GetArrayElementAtIndex(0);
+
+				GUILayout.BeginVertical(style);
+				
+				DrawLabel("Body Effector", startEffectorIcon);
+
+				AddProperty(effector.FindPropertyRelative("target"), new GUIContent("Target", "Target Transform (optional, you can also use bodyEffector.position and bodyEffector.rotation directly)."));
+				AddProperty(effector.FindPropertyRelative("positionWeight"), new GUIContent("Position Weight", "The weight of pinning the effector bone to the effector position."));
+				AddProperty(effector.FindPropertyRelative("effectChildNodes"), new GUIContent("Use Thighs", "If true, the effect of the body effector will be applied to also the thigh effectors (IKEffector.effectChildNodes)."));
+				
+				DrawLabel("Chain", null);
+				
+				// Spine stiffness
+				AddProperty(prop.FindPropertyRelative("spineStiffness"), new GUIContent("Spine Stiffness", "The bend resistance of the spine."));
+				
+				// Pull Body
+				AddProperty(prop.FindPropertyRelative("pullBodyVertical"), new GUIContent("Pull Body Vertical", "Weight of hand effectors pulling the body vertically."));
+				AddProperty(prop.FindPropertyRelative("pullBodyHorizontal"), new GUIContent("Pull Body Horizontal", "Weight of hand effectors pulling the body horizontally."));
+				
+				DrawLabel("Mapping", null);
+				
+				AddProperty(spineMapping.FindPropertyRelative("iterations"), new GUIContent("Spine Iterations", "The number of FABRIK iterations for mapping the spine bones to the solver armature."));
+				AddProperty(spineMapping.FindPropertyRelative("twistWeight"), new GUIContent("Spine Twist Weight", "The weight of spine twist."));
+				AddProperty(headMapping.FindPropertyRelative("maintainRotationWeight"), new GUIContent("Maintain Head Rot", "The weight of maintaining the bone's animated rotation in world space."));
+				
+				GUILayout.Space(5);
+				GUILayout.EndVertical();
+			}
+
+			GUILayout.EndVertical();
+			GUILayout.EndHorizontal();
+		}
+
+		private static void AddLimb(SerializedProperty prop, SerializedProperty chain, FullBodyBipedChain chainType, GUIContent guiContent) {
+			EditorGUILayout.PropertyField(chain, guiContent, false);
+			GUILayout.BeginHorizontal();
+			GUILayout.Space(10);
+			GUILayout.BeginVertical();
+			
+			if (chain.isExpanded) {
+				var effectors = prop.FindPropertyRelative("effectors");
+				var endEffector = effectors.GetArrayElementAtIndex(GetEndEffectorIndex(chainType));
+				var startEffector = effectors.GetArrayElementAtIndex(GetStartEffectorIndex(chainType));
+				var mapping = prop.FindPropertyRelative("limbMappings").GetArrayElementAtIndex(GetLimbMappingIndex(chainType));
+
+				GUILayout.BeginVertical(style);
+				
+				DrawLabel(GetEndEffectorName(chainType), endEffectorIcon);
+
+				AddProperty(endEffector.FindPropertyRelative("target"), new GUIContent("Target", "Target Transform (optional, you can also use IKEffector.position and IKEffector.rotation directly)."));
+				AddProperty(endEffector.FindPropertyRelative("positionWeight"), new GUIContent("Position Weight", "The weight of pinning the effector bone to the effector position."));
+				AddProperty(endEffector.FindPropertyRelative("rotationWeight"), new GUIContent("Rotation Weight", "The weight of pinning the effector bone to the effector rotation."));
+				AddProperty(endEffector.FindPropertyRelative("maintainRelativePositionWeight"), new GUIContent("Maintain Relative Pos", "Maintains the position of the hand/foot fixed relative to the chest/hips while effector positionWeight is not weighed in."));
+				
+				DrawLabel(GetStartEffectorName(chainType), startEffectorIcon);
+
+				AddProperty(startEffector.FindPropertyRelative("target"), new GUIContent("Target", "Target Transform (optional, you can also use IKEffector.position and IKEffector.rotation directly)."));
+				AddProperty(startEffector.FindPropertyRelative("positionWeight"), new GUIContent("Position Weight", "The weight of pinning the effector bone to the effector position."));
+				
+				DrawLabel("Chain", null);
+				
+				AddProperty(chain.FindPropertyRelative("pull"), new GUIContent("Pull", "The weight of pulling other chains."));
+				AddProperty(chain.FindPropertyRelative("reach"), new GUIContent("Reach", "Pulls the first node closer to the last node of the chain."));
+				AddProperty(chain.FindPropertyRelative("push"), new GUIContent("Push", "The weight of the end-effector pushing the first node."));
+				AddProperty(chain.FindPropertyRelative("pushParent"), new GUIContent("Push Parent", "The amount of push force transferred to the parent (from hand or foot to the body)."));
+				AddProperty(chain.FindPropertyRelative("reachSmoothing"), new GUIContent("Reach Smoothing", "Smoothing the effect of the Reach with the expense of some accuracy."));
+				AddProperty(chain.FindPropertyRelative("pushSmoothing"), new GUIContent("Push Smoothing", "Smoothing the effect of the Push."));
+				AddProperty(chain.FindPropertyRelative("bendConstraint").FindPropertyRelative("bendGoal"), new GUIContent("Bend Goal", "The Transform to bend towards (optional, you can also use ik.leftArmChain.bendConstraint.direction)."));
+				AddProperty(chain.FindPropertyRelative("bendConstraint").FindPropertyRelative("weight"), new GUIContent("Bend Goal Weight", "The weight of to bending towards the Bend Goal (optional, you can also use ik.leftArmChain.bendConstraint.weight)."));
+
+				DrawLabel("Mapping", null);
+				
+				AddProperty(mapping.FindPropertyRelative("weight"), new GUIContent("Mapping Weight", "The weight of mapping the limb to it's IK pose. This can be useful if you want to disable the effect of IK for the limb."));
+				AddProperty(mapping.FindPropertyRelative("maintainRotationWeight"), new GUIContent(GetEndBoneMappingName(chainType), "The weight of maintaining the bone's animated rotation in world space."));
+				
+				GUILayout.Space(5);
+				GUILayout.EndVertical();
+			}
+
+			GUILayout.EndVertical();
+			GUILayout.EndHorizontal();
+		}
+
+		private static void DrawLabel(string label, Texture2D texture) {
+			GUILayout.Space(3);
+			GUILayout.BeginHorizontal();
+			
+			if (texture != null) {
+				Rect rect = EditorGUILayout.GetControlRect(GUILayout.Width(16), GUILayout.Height(16));
+				GUI.DrawTexture(rect, texture);
+			} else GUILayout.Space(21);
+			
+			EditorGUILayout.LabelField(new GUIContent(label, string.Empty));
+			GUILayout.EndHorizontal();
+			GUILayout.Space(3);
+		}
+
+		private static string GetEndEffectorName(FullBodyBipedChain chain) {
+			switch(chain) {
+			case FullBodyBipedChain.LeftArm: return "Left Hand Effector";
+			case FullBodyBipedChain.RightArm: return "Right Hand Effector";
+			case FullBodyBipedChain.LeftLeg: return "Left Foot Effector";
+			case FullBodyBipedChain.RightLeg: return "Right Foot Effector";
+			default: return string.Empty;
+			}
+		}
+		
+		private static string GetStartEffectorName(FullBodyBipedChain chain) {
+			switch(chain) {
+			case FullBodyBipedChain.LeftArm: return "Left Shoulder Effector";
+			case FullBodyBipedChain.RightArm: return "Right Shoulder Effector";
+			case FullBodyBipedChain.LeftLeg: return "Left Thigh Effector";
+			case FullBodyBipedChain.RightLeg: return "Right Thigh Effector";
+			default: return string.Empty;
+			}
+		}
+		
+		private static string GetEndBoneMappingName(FullBodyBipedChain chain) {
+			switch(chain) {
+			case FullBodyBipedChain.LeftArm: return "Maintain Hand Rot";
+			case FullBodyBipedChain.RightArm: return "Maintain Hand Rot";
+			case FullBodyBipedChain.LeftLeg: return "Maintain Foot Rot";
+			case FullBodyBipedChain.RightLeg: return "Maintain Foot Rot";
+			default: return string.Empty;
+			}
+		}
+
+		private static int GetEndEffectorIndex(FullBodyBipedChain chainType) {
+			switch(chainType) {
+			case FullBodyBipedChain.LeftArm: return 5;
+			case FullBodyBipedChain.RightArm: return 6;
+			case FullBodyBipedChain.LeftLeg: return 7;
+			case FullBodyBipedChain.RightLeg: return 8;
+			}
+			return 0;
+		}
+		
+		private static int GetStartEffectorIndex(FullBodyBipedChain chainType) {
+			switch(chainType) {
+			case FullBodyBipedChain.LeftArm: return 1;
+			case FullBodyBipedChain.RightArm: return 2;
+			case FullBodyBipedChain.LeftLeg: return 3;
+			case FullBodyBipedChain.RightLeg: return 4;
+			}
+			return 0;
+		}
+		
+		private static int GetLimbMappingIndex(FullBodyBipedChain chainType) {
+			switch(chainType) {
+			case FullBodyBipedChain.LeftArm: return 0;
+			case FullBodyBipedChain.RightArm: return 1;
+			case FullBodyBipedChain.LeftLeg: return 2;
+			case FullBodyBipedChain.RightLeg: return 3;
+			}
+			return 0;
+		}
+
+		private static Texture2D endEffectorIcon {
+			get {
+				if (_endEffectorIcon == null) _endEffectorIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/RootMotion/FinalIK/Gizmos/EndEffector Icon.png", typeof(Texture2D));
+				return _endEffectorIcon;
+			}
+		}
+		private static Texture2D _endEffectorIcon;
+		
+		private static Texture2D startEffectorIcon {
+			get {
+				if (_startEffectorIcon == null) _startEffectorIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/RootMotion/FinalIK/Gizmos/MidEffector Icon.png", typeof(Texture2D));
+				return _startEffectorIcon;
+			}
+		}
+		private static Texture2D _startEffectorIcon;
+		
+		private static Texture2D chainIcon {
+			get {
+				if (_chainIcon == null) _chainIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/RootMotion/FinalIK/Gizmos/Chain Icon.png", typeof(Texture2D));
+				return _chainIcon;
+			}
+		}
+		private static Texture2D _chainIcon;
+		
+		private static Texture2D mappingIcon {
+			get {
+				if (_mappingIcon == null) _mappingIcon = (Texture2D)AssetDatabase.LoadAssetAtPath("Assets/RootMotion/FinalIK/Gizmos/Mapping Icon.png", typeof(Texture2D));
+				return _mappingIcon;
+			}
+		}
+		private static Texture2D _mappingIcon;
+	}
+}

+ 10 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverFullBodyBipedInspector.cs.meta

@@ -0,0 +1,10 @@
+fileFormatVersion: 2
+guid: 533c5d8f60bd14648a10c7c1ad3f9ee5
+MonoImporter:
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

+ 0 - 0
Assets/Plugins/RootMotion/Editor/FinalIK/IKSolverFullBodyInspector.cs


Някои файлове не бяха показани, защото твърде много файлове са промени