IKMapping.cs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336
  1. using UnityEngine;
  2. using System.Collections;
  3. namespace RootMotion.FinalIK {
  4. /// <summary>
  5. /// Maps a bone or a collection of bones to a node based %IK solver
  6. /// </summary>
  7. [System.Serializable]
  8. public class IKMapping {
  9. #region Main Interface
  10. /// <summary>
  11. /// Contains mapping information of a single bone
  12. /// </summary>
  13. [System.Serializable]
  14. public class BoneMap {
  15. /// <summary>
  16. /// The transform.
  17. /// </summary>
  18. public Transform transform;
  19. /// <summary>
  20. /// The node in %IK Solver.
  21. /// </summary>
  22. //public IKSolver.Node node;
  23. public int chainIndex = -1;
  24. public int nodeIndex = -1;
  25. public Vector3 defaultLocalPosition;
  26. public Quaternion defaultLocalRotation;
  27. public Vector3 localSwingAxis, localTwistAxis, planePosition, ikPosition;
  28. public Quaternion defaultLocalTargetRotation;
  29. private Quaternion maintainRotation;
  30. public float length;
  31. public Quaternion animatedRotation;
  32. private Transform planeBone1, planeBone2, planeBone3;
  33. private int plane1ChainIndex = -1;
  34. private int plane1NodeIndex = -1;
  35. private int plane2ChainIndex = -1;
  36. private int plane2NodeIndex = -1;
  37. private int plane3ChainIndex = -1;
  38. private int plane3NodeIndex = -1;
  39. //private IKSolver.Node planeNode1, planeNode2, planeNode3;
  40. public void Initiate(Transform transform, IKSolverFullBody solver) {
  41. this.transform = transform;
  42. solver.GetChainAndNodeIndexes(transform, out chainIndex, out nodeIndex);
  43. //IKSolver.Point point = solver.GetPoint(transform);
  44. //this.node = point as IKSolver.Node;
  45. }
  46. /// <summary>
  47. /// Gets the current swing direction of the bone in world space.
  48. /// </summary>
  49. public Vector3 swingDirection {
  50. get {
  51. return transform.rotation * localSwingAxis;
  52. }
  53. }
  54. public void StoreDefaultLocalState() {
  55. defaultLocalPosition = transform.localPosition;
  56. defaultLocalRotation = transform.localRotation;
  57. }
  58. public void FixTransform(bool position) {
  59. if (position) transform.localPosition = defaultLocalPosition;
  60. transform.localRotation = defaultLocalRotation;
  61. }
  62. #region Reading
  63. /*
  64. * Does this bone have a node in the IK Solver?
  65. * */
  66. public bool isNodeBone {
  67. get {
  68. return nodeIndex != -1;
  69. //return node != null;
  70. }
  71. }
  72. /*
  73. * Calculate length of the bone
  74. * */
  75. public void SetLength(BoneMap nextBone) {
  76. length = Vector3.Distance(transform.position, nextBone.transform.position);
  77. }
  78. /*
  79. * Sets the direction to the swing target in local space
  80. * */
  81. public void SetLocalSwingAxis(BoneMap swingTarget) {
  82. SetLocalSwingAxis(swingTarget, this);
  83. }
  84. /*
  85. * Sets the direction to the swing target in local space
  86. * */
  87. public void SetLocalSwingAxis(BoneMap bone1, BoneMap bone2) {
  88. localSwingAxis = Quaternion.Inverse(transform.rotation) * (bone1.transform.position - bone2.transform.position);
  89. }
  90. /*
  91. * Sets the direction to the twist target in local space
  92. * */
  93. public void SetLocalTwistAxis(Vector3 twistDirection, Vector3 normalDirection) {
  94. Vector3.OrthoNormalize(ref normalDirection, ref twistDirection);
  95. localTwistAxis = Quaternion.Inverse(transform.rotation) * twistDirection;
  96. }
  97. /*
  98. * Sets the 3 points defining a plane for this bone
  99. * */
  100. public void SetPlane(IKSolverFullBody solver, Transform planeBone1, Transform planeBone2, Transform planeBone3) {
  101. this.planeBone1 = planeBone1;
  102. this.planeBone2 = planeBone2;
  103. this.planeBone3 = planeBone3;
  104. solver.GetChainAndNodeIndexes(planeBone1, out plane1ChainIndex, out plane1NodeIndex);
  105. solver.GetChainAndNodeIndexes(planeBone2, out plane2ChainIndex, out plane2NodeIndex);
  106. solver.GetChainAndNodeIndexes(planeBone3, out plane3ChainIndex, out plane3NodeIndex);
  107. //this.planeNode1 = planeNode1;
  108. //this.planeNode2 = planeNode2;
  109. //this.planeNode3 = planeNode3;
  110. UpdatePlane(true, true);
  111. }
  112. /*
  113. * Updates the 3 plane points
  114. * */
  115. public void UpdatePlane(bool rotation, bool position) {
  116. Quaternion t = lastAnimatedTargetRotation;
  117. if (rotation) defaultLocalTargetRotation = QuaTools.RotationToLocalSpace(transform.rotation, t);
  118. if (position) planePosition = Quaternion.Inverse(t) * (transform.position - planeBone1.position);
  119. }
  120. /*
  121. * Sets the virtual position for this bone
  122. * */
  123. public void SetIKPosition() {
  124. ikPosition = transform.position;
  125. }
  126. /*
  127. * Stores the current rotation for later use.
  128. * */
  129. public void MaintainRotation() {
  130. maintainRotation = transform.rotation;
  131. }
  132. #endregion Reading
  133. #region Writing
  134. /*
  135. * Moves the bone to its virtual position
  136. * */
  137. public void SetToIKPosition() {
  138. transform.position = ikPosition;
  139. }
  140. /*
  141. * Moves the bone to the solver position of it's node
  142. * */
  143. public void FixToNode(IKSolverFullBody solver, float weight, IKSolver.Node fixNode = null) {
  144. if (fixNode == null) fixNode = solver.GetNode(chainIndex, nodeIndex);
  145. if (weight >= 1f) {
  146. transform.position = fixNode.solverPosition;
  147. return;
  148. }
  149. transform.position = Vector3.Lerp(transform.position, fixNode.solverPosition, weight);
  150. }
  151. /*
  152. * Gets the bone's position relative to it's 3 plane nodes
  153. * */
  154. public Vector3 GetPlanePosition(IKSolverFullBody solver) {
  155. return solver.GetNode(plane1ChainIndex, plane1NodeIndex).solverPosition + (GetTargetRotation(solver) * planePosition);
  156. //return planeNode1.solverPosition + (targetRotation * planePosition);
  157. }
  158. /*
  159. * Positions the bone relative to it's 3 plane nodes
  160. * */
  161. public void PositionToPlane(IKSolverFullBody solver) {
  162. transform.position = GetPlanePosition(solver);
  163. }
  164. /*
  165. * Rotates the bone relative to it's 3 plane nodes
  166. * */
  167. public void RotateToPlane(IKSolverFullBody solver, float weight) {
  168. Quaternion r = GetTargetRotation(solver) * defaultLocalTargetRotation;
  169. if (weight >= 1f) {
  170. transform.rotation = r;
  171. return;
  172. }
  173. transform.rotation = Quaternion.Lerp(transform.rotation, r, weight);
  174. }
  175. /*
  176. * Swings to the swing target
  177. * */
  178. public void Swing(Vector3 swingTarget, float weight) {
  179. Swing(swingTarget, transform.position, weight);
  180. }
  181. /*
  182. * Swings to a direction from pos2 to pos1
  183. * */
  184. public void Swing(Vector3 pos1, Vector3 pos2, float weight) {
  185. Quaternion r = Quaternion.FromToRotation(transform.rotation * localSwingAxis, pos1 - pos2) * transform.rotation;
  186. if (weight >= 1f) {
  187. transform.rotation = r;
  188. return;
  189. }
  190. transform.rotation = Quaternion.Lerp(transform.rotation, r, weight);
  191. }
  192. /*
  193. * Twists to the twist target
  194. * */
  195. public void Twist(Vector3 twistDirection, Vector3 normalDirection, float weight) {
  196. Vector3.OrthoNormalize(ref normalDirection, ref twistDirection);
  197. Quaternion r = Quaternion.FromToRotation(transform.rotation * localTwistAxis, twistDirection) * transform.rotation;
  198. if (weight >= 1f) {
  199. transform.rotation = r;
  200. return;
  201. }
  202. transform.rotation = Quaternion.Lerp(transform.rotation, r, weight);
  203. }
  204. /*
  205. * Rotates back to the last animated local rotation
  206. * */
  207. public void RotateToMaintain(float weight) {
  208. if (weight <= 0f) return;
  209. transform.rotation = Quaternion.Lerp(transform.rotation, maintainRotation, weight);
  210. }
  211. /*
  212. * Rotates to match the effector rotation
  213. * */
  214. public void RotateToEffector(IKSolverFullBody solver, float weight) {
  215. if (!isNodeBone) return;
  216. float w = weight * solver.GetNode(chainIndex, nodeIndex).effectorRotationWeight;
  217. if (w <= 0f) return;
  218. if (w >= 1f) {
  219. transform.rotation = solver.GetNode(chainIndex, nodeIndex).solverRotation;
  220. return;
  221. }
  222. transform.rotation = Quaternion.Lerp(transform.rotation, solver.GetNode(chainIndex, nodeIndex).solverRotation, w);
  223. }
  224. #endregion Writing
  225. /*
  226. * Rotation of plane nodes in the solver
  227. * */
  228. private Quaternion GetTargetRotation(IKSolverFullBody solver) {
  229. Vector3 p1 = solver.GetNode(plane1ChainIndex, plane1NodeIndex).solverPosition;
  230. Vector3 p2 = solver.GetNode(plane2ChainIndex, plane2NodeIndex).solverPosition;
  231. Vector3 p3 = solver.GetNode(plane3ChainIndex, plane3NodeIndex).solverPosition;
  232. if (p1 == p3) return Quaternion.identity;
  233. return Quaternion.LookRotation(p2 - p1, p3 - p1);
  234. //if (planeNode1.solverPosition == planeNode3.solverPosition) return Quaternion.identity;
  235. //return Quaternion.LookRotation(planeNode2.solverPosition - planeNode1.solverPosition, planeNode3.solverPosition - planeNode1.solverPosition);
  236. }
  237. /*
  238. * Rotation of plane nodes in the animation
  239. * */
  240. private Quaternion lastAnimatedTargetRotation {
  241. get {
  242. if (planeBone1.position == planeBone3.position) return Quaternion.identity;
  243. return Quaternion.LookRotation(planeBone2.position - planeBone1.position, planeBone3.position - planeBone1.position);
  244. }
  245. }
  246. }
  247. /// <summary>
  248. /// Determines whether this IKMapping is valid.
  249. /// </summary>
  250. public virtual bool IsValid(IKSolver solver, ref string message) {
  251. return true;
  252. }
  253. #endregion Main Interface
  254. public virtual void Initiate(IKSolverFullBody solver) {}
  255. protected bool BoneIsValid(Transform bone, IKSolver solver, ref string message, Warning.Logger logger = null) {
  256. if (bone == null) {
  257. message = "IKMappingLimb contains a null reference.";
  258. if (logger != null) logger(message);
  259. return false;
  260. }
  261. if (solver.GetPoint(bone) == null) {
  262. message = "IKMappingLimb is referencing to a bone '" + bone.name + "' that does not excist in the Node Chain.";
  263. if (logger != null) logger(message);
  264. return false;
  265. }
  266. return true;
  267. }
  268. /*
  269. * Interpolates the joint position to match the bone's length
  270. */
  271. protected Vector3 SolveFABRIKJoint(Vector3 pos1, Vector3 pos2, float length) {
  272. return pos2 + (pos1 - pos2).normalized * length;
  273. }
  274. }
  275. }