BakerUtilities.cs 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580
  1. using UnityEngine;
  2. using System.Collections;
  3. namespace RootMotion
  4. {
  5. public static class BakerUtilities
  6. {
  7. public static void ReduceKeyframes(AnimationCurve curve, float maxError)
  8. {
  9. if (maxError <= 0f) return;
  10. curve.keys = GetReducedKeyframes(curve, maxError);
  11. // 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
  12. }
  13. public static Keyframe[] GetReducedKeyframes(AnimationCurve curve, float maxError)
  14. {
  15. Keyframe[] keys = curve.keys;
  16. int i = 1;
  17. while (i < keys.Length - 1 && keys.Length > 2)
  18. {
  19. Keyframe[] testKeys = new Keyframe[keys.Length - 1];
  20. int c = 0;
  21. for (int n = 0; n < keys.Length; n++)
  22. {
  23. if (i != n)
  24. {
  25. testKeys[c] = new Keyframe(keys[n].time, keys[n].value, keys[n].inTangent, keys[n].outTangent);
  26. c++;
  27. }
  28. }
  29. AnimationCurve testCurve = new AnimationCurve();
  30. testCurve.keys = testKeys;
  31. float test0 = Mathf.Abs(testCurve.Evaluate(keys[i].time) - keys[i].value);
  32. float beforeTime = keys[i].time + (keys[i - 1].time - keys[i].time) * 0.5f;
  33. float afterTime = keys[i].time + (keys[i + 1].time - keys[i].time) * 0.5f;
  34. float testBefore = Mathf.Abs(testCurve.Evaluate(beforeTime) - curve.Evaluate(beforeTime));
  35. float testAfter = Mathf.Abs(testCurve.Evaluate(afterTime) - curve.Evaluate(afterTime));
  36. if (test0 < maxError && testBefore < maxError && testAfter < maxError)
  37. {
  38. keys = testKeys;
  39. }
  40. else
  41. {
  42. i++;
  43. }
  44. }
  45. return keys;
  46. }
  47. public static void SetLoopFrame(float time, AnimationCurve curve)
  48. {
  49. Keyframe[] keys = curve.keys;
  50. keys[keys.Length - 1].value = keys[0].value;
  51. float inTangent = Mathf.Lerp(keys[0].inTangent, keys[keys.Length - 1].inTangent, 0.5f);
  52. keys[0].inTangent = inTangent;
  53. keys[keys.Length - 1].inTangent = inTangent;
  54. float outTangent = Mathf.Lerp(keys[0].outTangent, keys[keys.Length - 1].outTangent, 0.5f);
  55. keys[0].outTangent = outTangent;
  56. keys[keys.Length - 1].outTangent = outTangent;
  57. keys[keys.Length - 1].time = time;
  58. curve.keys = keys;
  59. }
  60. public static void SetTangentMode(AnimationCurve curve)
  61. {
  62. #if UNITY_EDITOR
  63. if (curve.length < 2) return;
  64. for (int i = 1; i < curve.length - 1; i++)
  65. {
  66. UnityEditor.AnimationUtility.SetKeyLeftTangentMode(curve, i, UnityEditor.AnimationUtility.TangentMode.ClampedAuto);
  67. UnityEditor.AnimationUtility.SetKeyRightTangentMode(curve, i, UnityEditor.AnimationUtility.TangentMode.ClampedAuto);
  68. }
  69. #endif
  70. }
  71. // Realigns quaternion keys to ensure shortest interpolation paths.
  72. public static Quaternion EnsureQuaternionContinuity(Quaternion lastQ, Quaternion q)
  73. {
  74. Quaternion flipped = new Quaternion(-q.x, -q.y, -q.z, -q.w);
  75. Quaternion midQ = new Quaternion(
  76. Mathf.Lerp(lastQ.x, q.x, 0.5f),
  77. Mathf.Lerp(lastQ.y, q.y, 0.5f),
  78. Mathf.Lerp(lastQ.z, q.z, 0.5f),
  79. Mathf.Lerp(lastQ.w, q.w, 0.5f)
  80. );
  81. Quaternion midQFlipped = new Quaternion(
  82. Mathf.Lerp(lastQ.x, flipped.x, 0.5f),
  83. Mathf.Lerp(lastQ.y, flipped.y, 0.5f),
  84. Mathf.Lerp(lastQ.z, flipped.z, 0.5f),
  85. Mathf.Lerp(lastQ.w, flipped.w, 0.5f)
  86. );
  87. float angle = Quaternion.Angle(lastQ, midQ);
  88. float angleFlipped = Quaternion.Angle(lastQ, midQFlipped);
  89. return angleFlipped < angle ? flipped : q;
  90. }
  91. }
  92. //Manages the Animation Curves for Humanoid Q/T channels.
  93. [System.Serializable]
  94. public class BakerHumanoidQT
  95. {
  96. private Transform transform;
  97. private string Qx, Qy, Qz, Qw;
  98. private string Tx, Ty, Tz;
  99. // Animation curves for each channel of the Transform
  100. public AnimationCurve rotX, rotY, rotZ, rotW;
  101. public AnimationCurve posX, posY, posZ;
  102. private AvatarIKGoal goal;
  103. private Quaternion lastQ;
  104. private bool lastQSet;
  105. // The custom constructor
  106. public BakerHumanoidQT(string name)
  107. {
  108. Qx = name + "Q.x";
  109. Qy = name + "Q.y";
  110. Qz = name + "Q.z";
  111. Qw = name + "Q.w";
  112. Tx = name + "T.x";
  113. Ty = name + "T.y";
  114. Tz = name + "T.z";
  115. Reset();
  116. }
  117. public BakerHumanoidQT(Transform transform, AvatarIKGoal goal, string name)
  118. {
  119. this.transform = transform;
  120. this.goal = goal;
  121. Qx = name + "Q.x";
  122. Qy = name + "Q.y";
  123. Qz = name + "Q.z";
  124. Qw = name + "Q.w";
  125. Tx = name + "T.x";
  126. Ty = name + "T.y";
  127. Tz = name + "T.z";
  128. Reset();
  129. }
  130. // Clear all curves
  131. public void Reset()
  132. {
  133. rotX = new AnimationCurve();
  134. rotY = new AnimationCurve();
  135. rotZ = new AnimationCurve();
  136. rotW = new AnimationCurve();
  137. posX = new AnimationCurve();
  138. posY = new AnimationCurve();
  139. posZ = new AnimationCurve();
  140. lastQ = Quaternion.identity;
  141. lastQSet = false;
  142. }
  143. public void SetIKKeyframes(float time, Avatar avatar, Transform root, float humanScale, Vector3 bodyPosition, Quaternion bodyRotation)
  144. {
  145. Vector3 bonePos = transform.position;
  146. Quaternion boneRot = transform.rotation;
  147. if (root.parent != null)
  148. {
  149. bonePos = root.parent.InverseTransformPoint(bonePos);
  150. boneRot = Quaternion.Inverse(root.parent.rotation) * boneRot;
  151. }
  152. TQ IKTQ = AvatarUtility.GetIKGoalTQ(avatar, humanScale, goal, new TQ(bodyPosition, bodyRotation), new TQ(bonePos, boneRot));
  153. Quaternion rot = IKTQ.q;
  154. if (lastQSet) rot = BakerUtilities.EnsureQuaternionContinuity(lastQ, IKTQ.q);
  155. //rot.Normalize();
  156. lastQ = rot;
  157. lastQSet = true;
  158. rotX.AddKey(time, rot.x);
  159. rotY.AddKey(time, rot.y);
  160. rotZ.AddKey(time, rot.z);
  161. rotW.AddKey(time, rot.w);
  162. Vector3 pos = IKTQ.t;
  163. posX.AddKey(time, pos.x);
  164. posY.AddKey(time, pos.y);
  165. posZ.AddKey(time, pos.z);
  166. }
  167. public void SetKeyframes(float time, Vector3 pos, Quaternion rot)
  168. {
  169. // Rotation flipping already prevented in HumanoidBaker.UpdateHumanPose().
  170. rotX.AddKey(time, rot.x);
  171. rotY.AddKey(time, rot.y);
  172. rotZ.AddKey(time, rot.z);
  173. rotW.AddKey(time, rot.w);
  174. posX.AddKey(time, pos.x);
  175. posY.AddKey(time, pos.y);
  176. posZ.AddKey(time, pos.z);
  177. }
  178. public void MoveLastKeyframes(float time)
  179. {
  180. MoveLastKeyframe(time, rotX);
  181. MoveLastKeyframe(time, rotY);
  182. MoveLastKeyframe(time, rotZ);
  183. MoveLastKeyframe(time, rotW);
  184. MoveLastKeyframe(time, posX);
  185. MoveLastKeyframe(time, posY);
  186. MoveLastKeyframe(time, posZ);
  187. }
  188. // Add a copy of the first frame to the specified time
  189. public void SetLoopFrame(float time)
  190. {
  191. BakerUtilities.SetLoopFrame(time, rotX);
  192. BakerUtilities.SetLoopFrame(time, rotY);
  193. BakerUtilities.SetLoopFrame(time, rotZ);
  194. BakerUtilities.SetLoopFrame(time, rotW);
  195. BakerUtilities.SetLoopFrame(time, posX);
  196. BakerUtilities.SetLoopFrame(time, posY);
  197. BakerUtilities.SetLoopFrame(time, posZ);
  198. }
  199. private void MoveLastKeyframe(float time, AnimationCurve curve)
  200. {
  201. Keyframe[] keys = curve.keys;
  202. keys[keys.Length - 1].time = time;
  203. curve.keys = keys;
  204. }
  205. public void MultiplyLength(AnimationCurve curve, float mlp)
  206. {
  207. Keyframe[] keys = curve.keys;
  208. for (int i = 0; i < keys.Length; i++)
  209. {
  210. keys[i].time *= mlp;
  211. }
  212. curve.keys = keys;
  213. }
  214. // Add curves to the AnimationClip for each channel
  215. public void SetCurves(ref AnimationClip clip, float maxError, float lengthMlp)
  216. {
  217. MultiplyLength(rotX, lengthMlp);
  218. MultiplyLength(rotY, lengthMlp);
  219. MultiplyLength(rotZ, lengthMlp);
  220. MultiplyLength(rotW, lengthMlp);
  221. MultiplyLength(posX, lengthMlp);
  222. MultiplyLength(posY, lengthMlp);
  223. MultiplyLength(posZ, lengthMlp);
  224. BakerUtilities.ReduceKeyframes(rotX, maxError);
  225. BakerUtilities.ReduceKeyframes(rotY, maxError);
  226. BakerUtilities.ReduceKeyframes(rotZ, maxError);
  227. BakerUtilities.ReduceKeyframes(rotW, maxError);
  228. BakerUtilities.ReduceKeyframes(posX, maxError);
  229. BakerUtilities.ReduceKeyframes(posY, maxError);
  230. BakerUtilities.ReduceKeyframes(posZ, maxError);
  231. BakerUtilities.SetTangentMode(rotX);
  232. BakerUtilities.SetTangentMode(rotY);
  233. BakerUtilities.SetTangentMode(rotZ);
  234. BakerUtilities.SetTangentMode(rotW);
  235. /*
  236. BakerUtilities.SetTangentMode(posX);
  237. BakerUtilities.SetTangentMode(posY);
  238. BakerUtilities.SetTangentMode(posZ);
  239. */
  240. clip.SetCurve(string.Empty, typeof(Animator), Qx, rotX);
  241. clip.SetCurve(string.Empty, typeof(Animator), Qy, rotY);
  242. clip.SetCurve(string.Empty, typeof(Animator), Qz, rotZ);
  243. clip.SetCurve(string.Empty, typeof(Animator), Qw, rotW);
  244. clip.SetCurve(string.Empty, typeof(Animator), Tx, posX);
  245. clip.SetCurve(string.Empty, typeof(Animator), Ty, posY);
  246. clip.SetCurve(string.Empty, typeof(Animator), Tz, posZ);
  247. }
  248. }
  249. // Manages the Animation Curves for a single Transform that is a child of the root Transform.
  250. [System.Serializable]
  251. public class BakerMuscle
  252. {
  253. // Animation curves for each channel of the Transform
  254. public AnimationCurve curve;
  255. private int muscleIndex = -1;
  256. private string propertyName;
  257. // The custom constructor
  258. public BakerMuscle(int muscleIndex)
  259. {
  260. this.muscleIndex = muscleIndex;
  261. this.propertyName = MuscleNameToPropertyName(HumanTrait.MuscleName[muscleIndex]);
  262. Reset();
  263. }
  264. private string MuscleNameToPropertyName(string n)
  265. {
  266. // Left fingers
  267. if (n == "Left Index 1 Stretched") return "LeftHand.Index.1 Stretched";
  268. if (n == "Left Index 2 Stretched") return "LeftHand.Index.2 Stretched";
  269. if (n == "Left Index 3 Stretched") return "LeftHand.Index.3 Stretched";
  270. if (n == "Left Middle 1 Stretched") return "LeftHand.Middle.1 Stretched";
  271. if (n == "Left Middle 2 Stretched") return "LeftHand.Middle.2 Stretched";
  272. if (n == "Left Middle 3 Stretched") return "LeftHand.Middle.3 Stretched";
  273. if (n == "Left Ring 1 Stretched") return "LeftHand.Ring.1 Stretched";
  274. if (n == "Left Ring 2 Stretched") return "LeftHand.Ring.2 Stretched";
  275. if (n == "Left Ring 3 Stretched") return "LeftHand.Ring.3 Stretched";
  276. if (n == "Left Little 1 Stretched") return "LeftHand.Little.1 Stretched";
  277. if (n == "Left Little 2 Stretched") return "LeftHand.Little.2 Stretched";
  278. if (n == "Left Little 3 Stretched") return "LeftHand.Little.3 Stretched";
  279. if (n == "Left Thumb 1 Stretched") return "LeftHand.Thumb.1 Stretched";
  280. if (n == "Left Thumb 2 Stretched") return "LeftHand.Thumb.2 Stretched";
  281. if (n == "Left Thumb 3 Stretched") return "LeftHand.Thumb.3 Stretched";
  282. if (n == "Left Index Spread") return "LeftHand.Index.Spread";
  283. if (n == "Left Middle Spread") return "LeftHand.Middle.Spread";
  284. if (n == "Left Ring Spread") return "LeftHand.Ring.Spread";
  285. if (n == "Left Little Spread") return "LeftHand.Little.Spread";
  286. if (n == "Left Thumb Spread") return "LeftHand.Thumb.Spread";
  287. // Right fingers
  288. if (n == "Right Index 1 Stretched") return "RightHand.Index.1 Stretched";
  289. if (n == "Right Index 2 Stretched") return "RightHand.Index.2 Stretched";
  290. if (n == "Right Index 3 Stretched") return "RightHand.Index.3 Stretched";
  291. if (n == "Right Middle 1 Stretched") return "RightHand.Middle.1 Stretched";
  292. if (n == "Right Middle 2 Stretched") return "RightHand.Middle.2 Stretched";
  293. if (n == "Right Middle 3 Stretched") return "RightHand.Middle.3 Stretched";
  294. if (n == "Right Ring 1 Stretched") return "RightHand.Ring.1 Stretched";
  295. if (n == "Right Ring 2 Stretched") return "RightHand.Ring.2 Stretched";
  296. if (n == "Right Ring 3 Stretched") return "RightHand.Ring.3 Stretched";
  297. if (n == "Right Little 1 Stretched") return "RightHand.Little.1 Stretched";
  298. if (n == "Right Little 2 Stretched") return "RightHand.Little.2 Stretched";
  299. if (n == "Right Little 3 Stretched") return "RightHand.Little.3 Stretched";
  300. if (n == "Right Thumb 1 Stretched") return "RightHand.Thumb.1 Stretched";
  301. if (n == "Right Thumb 2 Stretched") return "RightHand.Thumb.2 Stretched";
  302. if (n == "Right Thumb 3 Stretched") return "RightHand.Thumb.3 Stretched";
  303. if (n == "Right Index Spread") return "RightHand.Index.Spread";
  304. if (n == "Right Middle Spread") return "RightHand.Middle.Spread";
  305. if (n == "Right Ring Spread") return "RightHand.Ring.Spread";
  306. if (n == "Right Little Spread") return "RightHand.Little.Spread";
  307. if (n == "Right Thumb Spread") return "RightHand.Thumb.Spread";
  308. return n;
  309. }
  310. public void MultiplyLength(AnimationCurve curve, float mlp)
  311. {
  312. Keyframe[] keys = curve.keys;
  313. for (int i = 0; i < keys.Length; i++)
  314. {
  315. keys[i].time *= mlp;
  316. }
  317. curve.keys = keys;
  318. }
  319. // Add curves to the AnimationClip for each channel
  320. public void SetCurves(ref AnimationClip clip, float maxError, float lengthMlp)
  321. {
  322. MultiplyLength(curve, lengthMlp);
  323. BakerUtilities.ReduceKeyframes(curve, maxError);
  324. // BakerUtilities.SetTangentMode(curve);
  325. clip.SetCurve(string.Empty, typeof(Animator), propertyName, curve);
  326. }
  327. // Clear all curves
  328. public void Reset()
  329. {
  330. curve = new AnimationCurve();
  331. }
  332. // Record a keyframe for each channel
  333. public void SetKeyframe(float time, float[] muscles)
  334. {
  335. curve.AddKey(time, muscles[muscleIndex]);
  336. }
  337. // Add a copy of the first frame to the specified time
  338. public void SetLoopFrame(float time)
  339. {
  340. BakerUtilities.SetLoopFrame(time, curve);
  341. }
  342. }
  343. //Manages the Animation Curves for a single Transform that is a child of the root Transform.
  344. [System.Serializable]
  345. public class BakerTransform
  346. {
  347. public Transform transform; // The Transform component to record
  348. // Animation curves for each channel of the Transform
  349. public AnimationCurve
  350. posX, posY, posZ,
  351. rotX, rotY, rotZ, rotW;
  352. private string relativePath; // Path relative to the root
  353. private bool recordPosition; // Should we record the localPosition if the transform?
  354. private Vector3 relativePosition;
  355. private bool isRootNode;
  356. private Quaternion relativeRotation;
  357. // The custom constructor
  358. public BakerTransform(Transform transform, Transform root, bool recordPosition, bool isRootNode)
  359. {
  360. this.transform = transform;
  361. this.recordPosition = recordPosition || isRootNode;
  362. this.isRootNode = isRootNode;
  363. relativePath = string.Empty;
  364. #if UNITY_EDITOR
  365. relativePath = UnityEditor.AnimationUtility.CalculateTransformPath(transform, root);
  366. #endif
  367. Reset();
  368. }
  369. public void SetRelativeSpace(Vector3 position, Quaternion rotation)
  370. {
  371. relativePosition = position;
  372. relativeRotation = rotation;
  373. }
  374. // Add curves to the AnimationClip for each channel
  375. public void SetCurves(ref AnimationClip clip)
  376. {
  377. if (recordPosition)
  378. {
  379. clip.SetCurve(relativePath, typeof(Transform), "localPosition.x", posX);
  380. clip.SetCurve(relativePath, typeof(Transform), "localPosition.y", posY);
  381. clip.SetCurve(relativePath, typeof(Transform), "localPosition.z", posZ);
  382. }
  383. clip.SetCurve(relativePath, typeof(Transform), "localRotation.x", rotX);
  384. clip.SetCurve(relativePath, typeof(Transform), "localRotation.y", rotY);
  385. clip.SetCurve(relativePath, typeof(Transform), "localRotation.z", rotZ);
  386. clip.SetCurve(relativePath, typeof(Transform), "localRotation.w", rotW);
  387. if (isRootNode) AddRootMotionCurves(ref clip);
  388. // @todo probably only need to do it once for the clip
  389. clip.EnsureQuaternionContinuity(); // DOH!
  390. }
  391. private void AddRootMotionCurves(ref AnimationClip clip)
  392. {
  393. if (recordPosition)
  394. {
  395. clip.SetCurve("", typeof(Animator), "MotionT.x", posX);
  396. clip.SetCurve("", typeof(Animator), "MotionT.y", posY);
  397. clip.SetCurve("", typeof(Animator), "MotionT.z", posZ);
  398. }
  399. clip.SetCurve("", typeof(Animator), "MotionQ.x", rotX);
  400. clip.SetCurve("", typeof(Animator), "MotionQ.y", rotY);
  401. clip.SetCurve("", typeof(Animator), "MotionQ.z", rotZ);
  402. clip.SetCurve("", typeof(Animator), "MotionQ.w", rotW);
  403. }
  404. // Clear all curves
  405. public void Reset()
  406. {
  407. posX = new AnimationCurve();
  408. posY = new AnimationCurve();
  409. posZ = new AnimationCurve();
  410. rotX = new AnimationCurve();
  411. rotY = new AnimationCurve();
  412. rotZ = new AnimationCurve();
  413. rotW = new AnimationCurve();
  414. }
  415. public void ReduceKeyframes(float maxError)
  416. {
  417. BakerUtilities.ReduceKeyframes(rotX, maxError);
  418. BakerUtilities.ReduceKeyframes(rotY, maxError);
  419. BakerUtilities.ReduceKeyframes(rotZ, maxError);
  420. BakerUtilities.ReduceKeyframes(rotW, maxError);
  421. BakerUtilities.ReduceKeyframes(posX, maxError);
  422. BakerUtilities.ReduceKeyframes(posY, maxError);
  423. BakerUtilities.ReduceKeyframes(posZ, maxError);
  424. }
  425. // Record a keyframe for each channel
  426. public void SetKeyframes(float time)
  427. {
  428. if (recordPosition)
  429. {
  430. Vector3 pos = transform.localPosition;
  431. if (isRootNode)
  432. {
  433. pos = transform.position - relativePosition;
  434. }
  435. posX.AddKey(time, pos.x);
  436. posY.AddKey(time, pos.y);
  437. posZ.AddKey(time, pos.z);
  438. }
  439. Quaternion rot = transform.localRotation;
  440. if (isRootNode)
  441. {
  442. rot = Quaternion.Inverse(relativeRotation) * transform.rotation;
  443. }
  444. rotX.AddKey(time, rot.x);
  445. rotY.AddKey(time, rot.y);
  446. rotZ.AddKey(time, rot.z);
  447. rotW.AddKey(time, rot.w);
  448. }
  449. // Add a copy of the first frame to the specified time
  450. public void AddLoopFrame(float time)
  451. {
  452. // TODO change to SetLoopFrame
  453. if (recordPosition && !isRootNode)
  454. {
  455. posX.AddKey(time, posX.keys[0].value);
  456. posY.AddKey(time, posY.keys[0].value);
  457. posZ.AddKey(time, posZ.keys[0].value);
  458. }
  459. rotX.AddKey(time, rotX.keys[0].value);
  460. rotY.AddKey(time, rotY.keys[0].value);
  461. rotZ.AddKey(time, rotZ.keys[0].value);
  462. rotW.AddKey(time, rotW.keys[0].value);
  463. }
  464. }
  465. }