AnimationWarping.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129
  1. using UnityEngine;
  2. using System.Collections;
  3. using RootMotion.FinalIK;
  4. namespace RootMotion.Demos {
  5. /// <summary>
  6. /// Warping an effector from animation space to world space.
  7. /// The weight curve of the warp is used to add the offset from "Warp From" to "Warp To" to the effector.
  8. /// "Warp From" should be a Transform parented to the root of the character, hence in animation space (virtual position where a soccer player's foot hits the ball in the animation).
  9. /// "Warp To" should be a Transform in the world space (the actual ball).
  10. /// </summary>
  11. public class AnimationWarping : OffsetModifier {
  12. /// <summary>
  13. /// Definition of a warp from 'warpFrom' to 'warpTo' by normalized time of the animation
  14. /// </summary>
  15. [System.Serializable]
  16. public struct Warp {
  17. [Tooltip("Layer of the 'Animation State' in the Animator.")]
  18. public int animationLayer;
  19. [Tooltip("Name of the state in the Animator to warp.")]
  20. public string animationState;
  21. [Tooltip("Warping weight by normalized time of the animation state.")]
  22. public AnimationCurve weightCurve;
  23. [Tooltip("Animated point to warp from. This should be in character space so keep this Transform parented to the root of the character.")]
  24. public Transform warpFrom;
  25. [Tooltip("World space point to warp to.")]
  26. public Transform warpTo;
  27. [Tooltip("Which FBBIK effector to use?")]
  28. public FullBodyBipedEffector effector;
  29. }
  30. /// <summary>
  31. /// Using effector.positionOffset or effector.position with effector.positionWeight?
  32. /// </summary>
  33. [System.Serializable]
  34. public enum EffectorMode {
  35. PositionOffset,
  36. Position,
  37. }
  38. [Tooltip("Reference to the Animator component to use")]
  39. public Animator animator;
  40. [Tooltip("Using effector.positionOffset or effector.position with effector.positionWeight? " +
  41. "The former will enable you to use effector.position for other things, the latter will weigh in the effectors, hence using Reach and Pull in the process.")]
  42. public EffectorMode effectorMode;
  43. [Space(10)]
  44. [Tooltip("The array of warps, can have multiple simultaneous warps.")]
  45. public Warp[] warps;
  46. private EffectorMode lastMode;
  47. protected override void Start() {
  48. base.Start();
  49. lastMode = effectorMode;
  50. }
  51. /// <summary>
  52. /// Gets the current warping weight of the warp at the specified index.
  53. /// </summary>
  54. public float GetWarpWeight(int warpIndex) {
  55. if (warpIndex < 0) {
  56. Debug.LogError("Warp index out of range.");
  57. return 0f;
  58. }
  59. if (warpIndex >= warps.Length) {
  60. Debug.LogError("Warp index out of range.");
  61. return 0f;
  62. }
  63. if (animator == null) {
  64. Debug.LogError("Animator unassigned in AnimationWarping");
  65. return 0f;
  66. }
  67. // Get the animator state info
  68. AnimatorStateInfo info = animator.GetCurrentAnimatorStateInfo(warps[warpIndex].animationLayer);
  69. // If not currently playing the animation state of the warp, return
  70. if (!info.IsName(warps[warpIndex].animationState)) return 0f;
  71. // Evaluate the weight of the warp by the current normalized time of the state
  72. return warps[warpIndex].weightCurve.Evaluate(info.normalizedTime - (int)info.normalizedTime);
  73. }
  74. // Called each time before FBBIK solves
  75. protected override void OnModifyOffset() {
  76. // Go through all the warps...
  77. for (int i = 0; i < warps.Length; i++) {
  78. float warpWeight = GetWarpWeight(i);
  79. // Get the offset form warpFrom to warpTo
  80. Vector3 offset = warps[i].warpTo.position - warps[i].warpFrom.position;
  81. // Add that offset to the effector (using positionOffset additively, because it will be reset to Vector3.zero by FBBIK after each update)
  82. switch(effectorMode) {
  83. case EffectorMode.PositionOffset:
  84. ik.solver.GetEffector(warps[i].effector).positionOffset += offset * warpWeight * weight;
  85. break;
  86. case EffectorMode.Position:
  87. ik.solver.GetEffector(warps[i].effector).position = ik.solver.GetEffector(warps[i].effector).bone.position + offset;
  88. ik.solver.GetEffector(warps[i].effector).positionWeight = weight * warpWeight;
  89. break;
  90. }
  91. }
  92. // Switching modes safely, weighing out effector positionWeights
  93. if (lastMode == EffectorMode.Position && effectorMode == EffectorMode.PositionOffset) {
  94. foreach (Warp warp in warps) {
  95. ik.solver.GetEffector(warp.effector).positionWeight = 0f;
  96. }
  97. }
  98. lastMode = effectorMode;
  99. }
  100. // Set effector positionWeights to 0 if in "Position" effector mode
  101. void OnDisable() {
  102. if (effectorMode != EffectorMode.Position) return;
  103. foreach (Warp warp in warps) {
  104. ik.solver.GetEffector(warp.effector).positionWeight = 0f;
  105. }
  106. }
  107. }
  108. }