Advertisement
athos_k

Custom IK

Nov 4th, 2016
170
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.64 KB | None | 0 0
  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. public class customIk : MonoBehaviour {
  5.  
  6. Animator anim;
  7.  
  8. //Our bones
  9. public Transform upperArm;
  10. public Transform forearm;
  11. public Transform hand;
  12.  
  13. //our targets
  14. public Transform target;
  15. public Transform elbowTarget;
  16.  
  17. //is it enable
  18. public bool IsEnabled;
  19. public float Weight = 1;
  20.  
  21. //Starting rotations
  22. Quaternion upperArmStartRotation, forearmStartRotation,handStartRotation;
  23.  
  24. //relative starting positions
  25. Vector3 targetRelativeStartPosition,elbowTargetRelativeStartPosition;
  26.  
  27. //helper gos that are used every frame
  28. GameObject upperArmAxisCorrection, forearmAxisCorrection, handAxisCorrection;
  29.  
  30. //hold last positions so recalculation is only done if needed
  31. private Vector3 lastUpperArmPosition, lastTargetPosition, lastElbowTargetPosition;
  32.  
  33.  
  34. void Start()
  35. {
  36. anim = GetComponentInParent<Animator> ();
  37.  
  38. //assign the starting rotations
  39. upperArmStartRotation = upperArm.rotation;
  40. forearmStartRotation = forearm.rotation;
  41. handStartRotation = hand.rotation;
  42.  
  43. //assign realtive starting positions
  44. elbowTargetRelativeStartPosition = elbowTarget.position - upperArm.position;
  45.  
  46. //Create helper GOs
  47. upperArmAxisCorrection = new GameObject("upperArmAxisCorrection");
  48. forearmAxisCorrection = new GameObject("forearmAxisCorrection");
  49. handAxisCorrection = new GameObject("handAxisCorrection");
  50.  
  51. //set helper hierarchy
  52. upperArmAxisCorrection.transform.parent = transform;
  53. forearmAxisCorrection.transform.parent = upperArmAxisCorrection.transform;
  54. handAxisCorrection.transform.parent = forearmAxisCorrection.transform;
  55.  
  56. //guarantee first-frame update
  57. lastUpperArmPosition = upperArm.position + 5*Vector3.up;
  58.  
  59. }
  60.  
  61.  
  62. void LateUpdate()
  63. {
  64. CalculateIK();
  65. }
  66.  
  67. void CalculateIK()
  68. {
  69. //if we have no target then reset the relative position
  70. if(target == null) {
  71. targetRelativeStartPosition = Vector3.zero;
  72. return;
  73. }
  74.  
  75. //if we have a target and the relative start position is zeroed
  76. if(targetRelativeStartPosition == Vector3.zero && target != null) {
  77. targetRelativeStartPosition = target.position - upperArm.position;
  78. }
  79.  
  80. //save our positions
  81. lastUpperArmPosition = upperArm.position;
  82. lastTargetPosition = target.position;
  83. lastElbowTargetPosition = elbowTarget.position;
  84.  
  85. //Calculate ikAngle variable which defines the angle that will be subtracted from the upperarm axis
  86. float upperArmLength = Vector3.Distance(upperArm.position, forearm.position);
  87. float forearmLength = Vector3.Distance(forearm.position, hand.position);
  88.  
  89. //find the arm length
  90. float armLength = upperArmLength + forearmLength;
  91. //find the hypoethenuse, is the longest side of a right-angled triangle 90o degrees angle
  92. float hypotenuse = upperArmLength;
  93.  
  94. //find the distance betwen our upperarm and the target
  95. float targetDistance = Vector3.Distance(upperArm.position, target.position);
  96.  
  97. //Do not allow target distance be further away than the arm's length.
  98. targetDistance = Mathf.Min(targetDistance, armLength - 0.0001f);
  99.  
  100. //(of a pair of angles) formed on the same side of a straight line when intersected by another line.
  101. float adjacent = (hypotenuse*hypotenuse - forearmLength*forearmLength + targetDistance*targetDistance) /(2*targetDistance);
  102.  
  103. //find the ik Angle
  104. float ikAngle = Mathf.Acos(adjacent/hypotenuse) * Mathf.Rad2Deg;
  105.  
  106. //Store pre-ik info.
  107. Vector3 targetPosition = target.position;
  108. Vector3 elbowTargetPosition = elbowTarget.position;
  109.  
  110. //Store the parent of each bone
  111. Transform upperArmParent = upperArm.parent;
  112. Transform forearmParent = forearm.parent;
  113. Transform handParent = hand.parent;
  114.  
  115. //Store the scale
  116. Vector3 upperArmScale = upperArm.localScale;
  117. Vector3 forearmScale = forearm.localScale;
  118. Vector3 handScale = hand.localScale;
  119.  
  120. //Store the local positions
  121. Vector3 upperArmLocalPosition = upperArm.localPosition;
  122. Vector3 forearmLocalPosition = forearm.localPosition;
  123. Vector3 handLocalPosition = hand.localPosition;
  124.  
  125. //Store the rotations
  126. Quaternion upperArmRotation = upperArm.rotation;
  127. Quaternion forearmRotation = forearm.rotation;
  128. Quaternion handRotation = hand.rotation;
  129. Quaternion handLocalRotation = hand.localRotation;
  130.  
  131. //Reset arm so that the ik starts from a known postion
  132. target.position = targetRelativeStartPosition + upperArm.position;
  133. elbowTarget.position = elbowTargetRelativeStartPosition + upperArm.position;
  134. upperArm.rotation = upperArmStartRotation;
  135. forearm.rotation = forearmStartRotation;
  136. hand.rotation = handStartRotation;
  137.  
  138. //Work with temporaty game objects and align & parent them to the arm.
  139. transform.position = upperArm.position;
  140. //position the elbow using as an up axis a vector from the upperArm position to the target of the elbow
  141. //that will orient the elbow to the correct orientation
  142. transform.LookAt(targetPosition, elbowTargetPosition - transform.position);
  143.  
  144. upperArmAxisCorrection.transform.position = upperArm.position;
  145. upperArmAxisCorrection.transform.LookAt(forearm.position, upperArm.up);
  146. upperArm.parent = upperArmAxisCorrection.transform;
  147.  
  148. forearmAxisCorrection.transform.position = forearm.position;
  149. forearmAxisCorrection.transform.LookAt(hand.position, forearm.up);
  150. forearm.parent = forearmAxisCorrection.transform;
  151.  
  152. handAxisCorrection.transform.position = hand.position;
  153. hand.parent = handAxisCorrection.transform;
  154.  
  155. //Reset targets.
  156. target.position = targetPosition;
  157. elbowTarget.position = elbowTargetPosition;
  158.  
  159. //Apply rotation for temporary game objects.
  160. upperArmAxisCorrection.transform.LookAt(target,elbowTarget.position - upperArmAxisCorrection.transform.position);
  161. upperArmAxisCorrection.transform.localRotation = Quaternion.Euler(upperArmAxisCorrection.transform.localRotation.eulerAngles - new Vector3(ikAngle, 0, 0));
  162. forearmAxisCorrection.transform.LookAt(target,elbowTarget.position - upperArmAxisCorrection.transform.position);
  163. handAxisCorrection.transform.rotation = target.rotation;
  164.  
  165. //Restore limbs.
  166. upperArm.parent = upperArmParent;
  167. forearm.parent = forearmParent;
  168. hand.parent = handParent;
  169. upperArm.localScale = upperArmScale;
  170. forearm.localScale = forearmScale;
  171. hand.localScale = handScale;
  172. upperArm.localPosition = upperArmLocalPosition;
  173. forearm.localPosition = forearmLocalPosition;
  174. hand.localPosition = handLocalPosition;
  175.  
  176. //Transition.
  177. Weight = Mathf.Clamp01(Weight);
  178. upperArm.rotation = Quaternion.Slerp(upperArmRotation, upperArm.rotation, Weight);
  179. forearm.rotation = Quaternion.Slerp(forearmRotation, forearm.rotation, Weight);
  180. hand.rotation = target.rotation;
  181.  
  182. }
  183.  
  184. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement