GrounderFBBIK.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. using UnityEngine;
  2. using System.Collections;
  3. namespace RootMotion.FinalIK {
  4. /// <summary>
  5. /// Grounding for FBBIK characters.
  6. /// </summary>
  7. [HelpURL("https://www.youtube.com/watch?v=9MiZiaJorws&index=6&list=PLVxSIA1OaTOu8Nos3CalXbJ2DrKnntMv6")]
  8. [AddComponentMenu("Scripts/RootMotion.FinalIK/Grounder/Grounder Full Body Biped")]
  9. public class GrounderFBBIK: Grounder {
  10. // Open a video tutorial video
  11. [ContextMenu("TUTORIAL VIDEO")]
  12. void OpenTutorial() {
  13. Application.OpenURL("https://www.youtube.com/watch?v=9MiZiaJorws&index=6&list=PLVxSIA1OaTOu8Nos3CalXbJ2DrKnntMv6");
  14. }
  15. // Open the User Manual URL
  16. [ContextMenu("User Manual")]
  17. protected override void OpenUserManual() {
  18. Application.OpenURL("http://www.root-motion.com/finalikdox/html/page9.html");
  19. }
  20. // Open the Script Reference URL
  21. [ContextMenu("Scrpt Reference")]
  22. protected override void OpenScriptReference() {
  23. Application.OpenURL("http://www.root-motion.com/finalikdox/html/class_root_motion_1_1_final_i_k_1_1_grounder_f_b_b_i_k.html");
  24. }
  25. #region Main Interface
  26. /// <summary>
  27. /// Contains the bending weights for an effector.
  28. /// </summary>
  29. [System.Serializable]
  30. public class SpineEffector {
  31. /// <summary>
  32. /// The type of the effector.
  33. /// </summary>
  34. [Tooltip("The type of the effector.")]
  35. public FullBodyBipedEffector effectorType;
  36. /// <summary>
  37. /// The weight of horizontal bend offset towards the slope..
  38. /// </summary>
  39. [Tooltip("The weight of horizontal bend offset towards the slope.")]
  40. public float horizontalWeight = 1f;
  41. /// <summary>
  42. /// The vertical bend offset weight.
  43. /// </summary>
  44. [Tooltip("The vertical bend offset weight.")]
  45. public float verticalWeight;
  46. public SpineEffector() {}
  47. /// <summary>
  48. /// Initializes a new instance of the <see cref="RootMotion.FinalIK.GrounderFBBIK+SpineEffector"/> class.
  49. /// </summary>
  50. /// <param name="effectorType">Effector type.</param>
  51. /// <param name="horizontalWeight">Horizontal weight.</param>
  52. /// <param name="verticalWeight">Vertical weight.</param>
  53. public SpineEffector(FullBodyBipedEffector effectorType, float horizontalWeight, float verticalWeight) {
  54. this.effectorType = effectorType;
  55. this.horizontalWeight = horizontalWeight;
  56. this.verticalWeight = verticalWeight;
  57. }
  58. }
  59. /// <summary>
  60. /// Reference to the FBBIK componet.
  61. /// </summary>
  62. [Tooltip("Reference to the FBBIK componet.")]
  63. public FullBodyBipedIK ik;
  64. /// <summary>
  65. /// The amount of spine bending towards upward slopes.
  66. /// </summary>
  67. [Tooltip("The amount of spine bending towards upward slopes.")]
  68. public float spineBend = 2f;
  69. /// <summary>
  70. /// The interpolation speed of spine bending.
  71. /// </summary>
  72. [Tooltip("The interpolation speed of spine bending.")]
  73. public float spineSpeed = 3f;
  74. /// <summary>
  75. /// The spine bending effectors.
  76. /// </summary>
  77. public SpineEffector[] spine = new SpineEffector[0];
  78. #endregion Main Interface
  79. public override void ResetPosition() {
  80. solver.Reset();
  81. spineOffset = Vector3.zero;
  82. }
  83. private Transform[] feet = new Transform[2];
  84. private Vector3 spineOffset;
  85. private bool firstSolve;
  86. // Can we initiate the Grounding?
  87. private bool IsReadyToInitiate() {
  88. if (ik == null) return false;
  89. if (!ik.solver.initiated) return false;
  90. return true;
  91. }
  92. // Initiate once we have a FBBIK component
  93. void Update() {
  94. firstSolve = true;
  95. weight = Mathf.Clamp(weight, 0f, 1f);
  96. if (weight <= 0f) return;
  97. if (initiated) return;
  98. if (!IsReadyToInitiate()) return;
  99. Initiate();
  100. }
  101. void FixedUpdate() {
  102. firstSolve = true;
  103. }
  104. void LateUpdate() {
  105. firstSolve = true;
  106. }
  107. private void Initiate () {
  108. // Set maintainRotationWeight to 1 for both limbs so their rotation will be maintained as animated
  109. ik.solver.leftLegMapping.maintainRotationWeight = 1f;
  110. ik.solver.rightLegMapping.maintainRotationWeight = 1f;
  111. // Gathering both foot bones from the FBBIK
  112. feet = new Transform[2];
  113. feet[0] = ik.solver.leftFootEffector.bone;
  114. feet[1] = ik.solver.rightFootEffector.bone;
  115. // Add to the FBBIK OnPreUpdate delegate to know when it solves
  116. ik.solver.OnPreUpdate += OnSolverUpdate;
  117. // Initiate Grounding
  118. solver.Initiate(ik.references.root, feet);
  119. initiated = true;
  120. }
  121. // Called before updating the main IK solver
  122. private void OnSolverUpdate() {
  123. if (!firstSolve) return;
  124. firstSolve = false;
  125. if (!enabled) return;
  126. if (weight <= 0f) return;
  127. if (OnPreGrounder != null) OnPreGrounder();
  128. solver.Update();
  129. // Move the pelvis
  130. ik.references.pelvis.position += solver.pelvis.IKOffset * weight;
  131. // Set effector positionOffsets for the feet
  132. SetLegIK(ik.solver.leftFootEffector, solver.legs[0]);
  133. SetLegIK(ik.solver.rightFootEffector, solver.legs[1]);
  134. // Bending the spine
  135. if (spineBend != 0f) {
  136. spineSpeed = Mathf.Clamp(spineSpeed, 0f, spineSpeed);
  137. Vector3 spineOffseTarget = GetSpineOffsetTarget() * weight;
  138. spineOffset = Vector3.Lerp(spineOffset, spineOffseTarget * spineBend, Time.deltaTime * spineSpeed);
  139. Vector3 verticalOffset = ik.references.root.up * spineOffset.magnitude;
  140. for (int i = 0; i < spine.Length; i++) {
  141. ik.solver.GetEffector(spine[i].effectorType).positionOffset += (spineOffset * spine[i].horizontalWeight) + (verticalOffset * spine[i].verticalWeight);
  142. }
  143. }
  144. if (OnPostGrounder != null) OnPostGrounder();
  145. }
  146. // Set the effector positionOffset for the foot
  147. private void SetLegIK(IKEffector effector, Grounding.Leg leg) {
  148. effector.positionOffset += (leg.IKPosition - effector.bone.position) * weight;
  149. effector.bone.rotation = Quaternion.Slerp(Quaternion.identity, leg.rotationOffset, weight) * effector.bone.rotation;
  150. }
  151. // Auto-assign ik
  152. void OnDrawGizmosSelected() {
  153. if (ik == null) ik = GetComponent<FullBodyBipedIK>();
  154. if (ik == null) ik = GetComponentInParent<FullBodyBipedIK>();
  155. if (ik == null) ik = GetComponentInChildren<FullBodyBipedIK>();
  156. }
  157. // Cleaning up the delegate
  158. void OnDestroy() {
  159. if (initiated && ik != null) ik.solver.OnPreUpdate -= OnSolverUpdate;
  160. }
  161. }
  162. }