IKSolver.cs 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453
  1. using UnityEngine;
  2. using System.Collections;
  3. namespace RootMotion.FinalIK {
  4. /// <summary>
  5. /// The base abstract class for all %IK solvers
  6. /// </summary>
  7. [System.Serializable]
  8. public abstract class IKSolver {
  9. #region Main Interface
  10. [HideInInspector] public bool executedInEditor;
  11. /// <summary>
  12. /// Determines whether this instance is valid or not.
  13. /// </summary>
  14. public bool IsValid() {
  15. string message = string.Empty;
  16. return IsValid(ref message);
  17. }
  18. /// <summary>
  19. /// Determines whether this instance is valid or not. If returns false, also fills in an error message.
  20. /// </summary>
  21. public abstract bool IsValid(ref string message);
  22. /// <summary>
  23. /// Initiate the solver with specified root Transform. Use only if this %IKSolver is not a member of an %IK component.
  24. /// </summary>
  25. public void Initiate(Transform root) {
  26. if (executedInEditor) return;
  27. if (OnPreInitiate != null) OnPreInitiate();
  28. if (root == null) Debug.LogError("Initiating IKSolver with null root Transform.");
  29. this.root = root;
  30. initiated = false;
  31. string message = string.Empty;
  32. if (!IsValid(ref message)) {
  33. Warning.Log(message, root, false);
  34. return;
  35. }
  36. OnInitiate();
  37. StoreDefaultLocalState();
  38. initiated = true;
  39. firstInitiation = false;
  40. if (OnPostInitiate != null) OnPostInitiate();
  41. }
  42. /// <summary>
  43. /// Updates the %IK solver. Use only if this %IKSolver is not a member of an %IK component or the %IK component has been disabled and you intend to manually control the updating.
  44. /// </summary>
  45. public void Update() {
  46. if (OnPreUpdate != null) OnPreUpdate();
  47. if (firstInitiation) Initiate(root); // when the IK component has been disabled in Awake, this will initiate it.
  48. if (!initiated) return;
  49. OnUpdate();
  50. if (OnPostUpdate != null) OnPostUpdate();
  51. }
  52. /// <summary>
  53. /// The %IK position.
  54. /// </summary>
  55. [HideInInspector] public Vector3 IKPosition;
  56. [Tooltip("The positional or the master weight of the solver.")]
  57. /// <summary>
  58. /// The %IK position weight or the master weight of the solver.
  59. /// </summary>
  60. [Range(0f, 1f)]
  61. public float IKPositionWeight = 1f;
  62. /// <summary>
  63. /// Gets the %IK position. NOTE: You are welcome to read IKPosition directly, this method is here only to match the Unity's built in %IK API.
  64. /// </summary>
  65. public virtual Vector3 GetIKPosition() {
  66. return IKPosition;
  67. }
  68. /// <summary>
  69. /// Sets the %IK position. NOTE: You are welcome to set IKPosition directly, this method is here only to match the Unity's built in %IK API.
  70. /// </summary>
  71. public void SetIKPosition(Vector3 position) {
  72. IKPosition = position;
  73. }
  74. /// <summary>
  75. /// Gets the %IK position weight. NOTE: You are welcome to read IKPositionWeight directly, this method is here only to match the Unity's built in %IK API.
  76. /// </summary>
  77. public float GetIKPositionWeight() {
  78. return IKPositionWeight;
  79. }
  80. /// <summary>
  81. /// Sets the %IK position weight. NOTE: You are welcome to set IKPositionWeight directly, this method is here only to match the Unity's built in %IK API.
  82. /// </summary>
  83. public void SetIKPositionWeight(float weight) {
  84. IKPositionWeight = Mathf.Clamp(weight, 0f, 1f);
  85. }
  86. /// <summary>
  87. /// Gets the root Transform.
  88. /// </summary>
  89. public Transform GetRoot() {
  90. return root;
  91. }
  92. /// <summary>
  93. /// Gets a value indicating whether this <see cref="IKSolver"/> has successfully initiated.
  94. /// </summary>
  95. public bool initiated { get; private set; }
  96. /// <summary>
  97. /// Gets all the points used by the solver.
  98. /// </summary>
  99. public abstract IKSolver.Point[] GetPoints();
  100. /// <summary>
  101. /// Gets the point with the specified Transform.
  102. /// </summary>
  103. public abstract IKSolver.Point GetPoint(Transform transform);
  104. /// <summary>
  105. /// Fixes all the Transforms used by the solver to their initial state.
  106. /// </summary>
  107. public abstract void FixTransforms();
  108. /// <summary>
  109. /// Stores the default local state for the bones used by the solver.
  110. /// </summary>
  111. public abstract void StoreDefaultLocalState();
  112. /// <summary>
  113. /// The most basic element type in the %IK chain that all other types extend from.
  114. /// </summary>
  115. [System.Serializable]
  116. public class Point {
  117. /// <summary>
  118. /// The transform.
  119. /// </summary>
  120. public Transform transform;
  121. /// <summary>
  122. /// The weight of this bone in the solver.
  123. /// </summary>
  124. [Range(0f, 1f)]
  125. public float weight = 1f;
  126. /// <summary>
  127. /// Virtual position in the %IK solver.
  128. /// </summary>
  129. public Vector3 solverPosition;
  130. /// <summary>
  131. /// Virtual rotation in the %IK solver.
  132. /// </summary>
  133. public Quaternion solverRotation = Quaternion.identity;
  134. /// <summary>
  135. /// The default local position of the Transform.
  136. /// </summary>
  137. public Vector3 defaultLocalPosition;
  138. /// <summary>
  139. /// The default local rotation of the Transform.
  140. /// </summary>
  141. public Quaternion defaultLocalRotation;
  142. /// <summary>
  143. /// Stores the default local state of the point.
  144. /// </summary>
  145. public void StoreDefaultLocalState() {
  146. defaultLocalPosition = transform.localPosition;
  147. defaultLocalRotation = transform.localRotation;
  148. }
  149. /// <summary>
  150. /// Fixes the transform to it's default local state.
  151. /// </summary>
  152. public void FixTransform() {
  153. if (transform.localPosition != defaultLocalPosition) transform.localPosition = defaultLocalPosition;
  154. if (transform.localRotation != defaultLocalRotation) transform.localRotation = defaultLocalRotation;
  155. }
  156. /// <summary>
  157. /// Updates the solverPosition (in world space).
  158. /// </summary>
  159. public void UpdateSolverPosition() {
  160. solverPosition = transform.position;
  161. }
  162. /// <summary>
  163. /// Updates the solverPosition (in local space).
  164. /// </summary>
  165. public void UpdateSolverLocalPosition() {
  166. solverPosition = transform.localPosition;
  167. }
  168. /// <summary>
  169. /// Updates the solverPosition/Rotation (in world space).
  170. /// </summary>
  171. public void UpdateSolverState() {
  172. solverPosition = transform.position;
  173. solverRotation = transform.rotation;
  174. }
  175. /// <summary>
  176. /// Updates the solverPosition/Rotation (in local space).
  177. /// </summary>
  178. public void UpdateSolverLocalState() {
  179. solverPosition = transform.localPosition;
  180. solverRotation = transform.localRotation;
  181. }
  182. }
  183. /// <summary>
  184. /// %Bone type of element in the %IK chain. Used in the case of skeletal Transform hierarchies.
  185. /// </summary>
  186. [System.Serializable]
  187. public class Bone: Point {
  188. /// <summary>
  189. /// The length of the bone.
  190. /// </summary>
  191. public float length;
  192. /// <summary>
  193. /// The sqr mag of the bone.
  194. /// </summary>
  195. public float sqrMag;
  196. /// <summary>
  197. /// Local axis to target/child bone.
  198. /// </summary>
  199. public Vector3 axis = -Vector3.right;
  200. /// <summary>
  201. /// Gets the rotation limit component from the Transform if there is any.
  202. /// </summary>
  203. public RotationLimit rotationLimit {
  204. get {
  205. if (!isLimited) return null;
  206. if (_rotationLimit == null) _rotationLimit = transform.GetComponent<RotationLimit>();
  207. isLimited = _rotationLimit != null;
  208. return _rotationLimit;
  209. }
  210. set {
  211. _rotationLimit = value;
  212. isLimited = value != null;
  213. }
  214. }
  215. /*
  216. * Swings the Transform's axis towards the swing target
  217. * */
  218. public void Swing(Vector3 swingTarget, float weight = 1f) {
  219. if (weight <= 0f) return;
  220. Quaternion r = Quaternion.FromToRotation(transform.rotation * axis, swingTarget - transform.position);
  221. if (weight >= 1f) {
  222. transform.rotation = r * transform.rotation;
  223. return;
  224. }
  225. transform.rotation = Quaternion.Lerp(Quaternion.identity, r, weight) * transform.rotation;
  226. }
  227. public static void SolverSwing(Bone[] bones, int index, Vector3 swingTarget, float weight = 1f) {
  228. if (weight <= 0f) return;
  229. Quaternion r = Quaternion.FromToRotation(bones[index].solverRotation * bones[index].axis, swingTarget - bones[index].solverPosition);
  230. if (weight >= 1f) {
  231. for (int i = index; i < bones.Length; i++) {
  232. bones[i].solverRotation = r * bones[i].solverRotation;
  233. }
  234. return;
  235. }
  236. for (int i = index; i < bones.Length; i++) {
  237. bones[i].solverRotation = Quaternion.Lerp(Quaternion.identity, r, weight) * bones[i].solverRotation;
  238. }
  239. }
  240. /*
  241. * Swings the Transform's axis towards the swing target on the XY plane only
  242. * */
  243. public void Swing2D(Vector3 swingTarget, float weight = 1f) {
  244. if (weight <= 0f) return;
  245. Vector3 from = transform.rotation * axis;
  246. Vector3 to = swingTarget - transform.position;
  247. float angleFrom = Mathf.Atan2(from.x, from.y) * Mathf.Rad2Deg;
  248. float angleTo = Mathf.Atan2(to.x, to.y) * Mathf.Rad2Deg;
  249. transform.rotation = Quaternion.AngleAxis(Mathf.DeltaAngle(angleFrom, angleTo) * weight, Vector3.back) * transform.rotation;
  250. }
  251. /*
  252. * Moves the bone to the solver position
  253. * */
  254. public void SetToSolverPosition() {
  255. transform.position = solverPosition;
  256. }
  257. public Bone() {}
  258. public Bone (Transform transform) {
  259. this.transform = transform;
  260. }
  261. public Bone (Transform transform, float weight) {
  262. this.transform = transform;
  263. this.weight = weight;
  264. }
  265. private RotationLimit _rotationLimit;
  266. private bool isLimited = true;
  267. }
  268. /// <summary>
  269. /// %Node type of element in the %IK chain. Used in the case of mixed/non-hierarchical %IK systems
  270. /// </summary>
  271. [System.Serializable]
  272. public class Node: Point {
  273. /// <summary>
  274. /// Distance to child node.
  275. /// </summary>
  276. public float length;
  277. /// <summary>
  278. /// The effector position weight.
  279. /// </summary>
  280. public float effectorPositionWeight;
  281. /// <summary>
  282. /// The effector rotation weight.
  283. /// </summary>
  284. public float effectorRotationWeight;
  285. /// <summary>
  286. /// Position offset.
  287. /// </summary>
  288. public Vector3 offset;
  289. public Node() {}
  290. public Node (Transform transform) {
  291. this.transform = transform;
  292. }
  293. public Node (Transform transform, float weight) {
  294. this.transform = transform;
  295. this.weight = weight;
  296. }
  297. }
  298. /// <summary>
  299. /// Delegates solver update events.
  300. /// </summary>
  301. public delegate void UpdateDelegate();
  302. /// <summary>
  303. /// Delegates solver iteration events.
  304. /// </summary>
  305. public delegate void IterationDelegate(int i);
  306. /// <summary>
  307. /// Called before initiating the solver.
  308. /// </summary>
  309. public UpdateDelegate OnPreInitiate;
  310. /// <summary>
  311. /// Called after initiating the solver.
  312. /// </summary>
  313. public UpdateDelegate OnPostInitiate;
  314. /// <summary>
  315. /// Called before updating.
  316. /// </summary>
  317. public UpdateDelegate OnPreUpdate;
  318. /// <summary>
  319. /// Called after writing the solved pose
  320. /// </summary>
  321. public UpdateDelegate OnPostUpdate;
  322. #endregion Main Interface
  323. protected abstract void OnInitiate();
  324. protected abstract void OnUpdate();
  325. protected bool firstInitiation = true;
  326. [SerializeField][HideInInspector] protected Transform root;
  327. protected void LogWarning(string message) {
  328. Warning.Log(message, root, true);
  329. }
  330. #region Class Methods
  331. /// <summary>
  332. /// Checks if an array of objects contains any duplicates.
  333. /// </summary>
  334. public static Transform ContainsDuplicateBone(Bone[] bones) {
  335. for (int i = 0; i < bones.Length; i++) {
  336. for (int i2 = 0; i2 < bones.Length; i2++) {
  337. if (i != i2 && bones[i].transform == bones[i2].transform) return bones[i].transform;
  338. }
  339. }
  340. return null;
  341. }
  342. /*
  343. * Make sure the bones are in valid Hierarchy
  344. * */
  345. public static bool HierarchyIsValid(IKSolver.Bone[] bones) {
  346. for (int i = 1; i < bones.Length; i++) {
  347. // If parent bone is not an ancestor of bone, the hierarchy is invalid
  348. if (!Hierarchy.IsAncestor(bones[i].transform, bones[i - 1].transform)) {
  349. return false;
  350. }
  351. }
  352. return true;
  353. }
  354. // Calculates bone lengths and axes, returns the length of the entire chain
  355. protected static float PreSolveBones(ref Bone[] bones) {
  356. float length = 0;
  357. for (int i = 0; i < bones.Length; i++) {
  358. bones[i].solverPosition = bones[i].transform.position;
  359. bones[i].solverRotation = bones[i].transform.rotation;
  360. }
  361. for (int i = 0; i < bones.Length; i++) {
  362. if (i < bones.Length - 1) {
  363. bones[i].sqrMag = (bones[i + 1].solverPosition - bones[i].solverPosition).sqrMagnitude;
  364. bones[i].length = Mathf.Sqrt(bones[i].sqrMag);
  365. length += bones[i].length;
  366. bones[i].axis = Quaternion.Inverse(bones[i].solverRotation) * (bones[i + 1].solverPosition - bones[i].solverPosition);
  367. } else {
  368. bones[i].sqrMag = 0f;
  369. bones[i].length = 0f;
  370. }
  371. }
  372. return length;
  373. }
  374. #endregion Class Methods
  375. }
  376. }