TwoBoneIKJob.cs 3.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. // Copyright Unity Technologies 2019 // https://github.com/Unity-Technologies/animation-jobs-samples //
  2. // This file has not been modified other to put it in the Animancer.Samples.Jobs namespace and add this message and the comment on the struct.
  3. using UnityEngine;
  4. using UnityEngine.Animations;
  5. namespace Animancer.Samples.Jobs
  6. {
  7. /// <summary>An <see cref="IAnimationJob"/> which executes two bone Inverse Kinematics.</summary>
  8. ///
  9. /// <remarks>
  10. /// <strong>Sample:</strong>
  11. /// <see href="https://kybernetik.com.au/animancer/docs/samples/jobs/two-bone-ik">
  12. /// Two Bone IK</see>
  13. /// </remarks>
  14. ///
  15. /// https://kybernetik.com.au/animancer/api/Animancer.Samples.Jobs/TwoBoneIKJob
  16. ///
  17. public struct TwoBoneIKJob : IAnimationJob
  18. {
  19. public TransformSceneHandle effector;
  20. public TransformStreamHandle top;
  21. public TransformStreamHandle mid;
  22. public TransformStreamHandle low;
  23. public void Setup(Animator animator, Transform topX, Transform midX, Transform lowX, Transform effectorX)
  24. {
  25. top = animator.BindStreamTransform(topX);
  26. mid = animator.BindStreamTransform(midX);
  27. low = animator.BindStreamTransform(lowX);
  28. effector = animator.BindSceneTransform(effectorX);
  29. }
  30. public readonly void ProcessRootMotion(AnimationStream stream)
  31. {
  32. }
  33. public readonly void ProcessAnimation(AnimationStream stream)
  34. {
  35. Solve(stream, top, mid, low, effector);
  36. }
  37. /// <summary>
  38. /// Returns the angle needed between v1 and v2 so that their extremities are
  39. /// spaced with a specific length.
  40. /// </summary>
  41. /// <returns>The angle between v1 and v2.</returns>
  42. /// <param name="aLen">The desired length between the extremities of v1 and v2.</param>
  43. /// <param name="v1">First triangle edge.</param>
  44. /// <param name="v2">Second triangle edge.</param>
  45. private static float TriangleAngle(float aLen, Vector3 v1, Vector3 v2)
  46. {
  47. float aLen1 = v1.magnitude;
  48. float aLen2 = v2.magnitude;
  49. float c = Mathf.Clamp((aLen1 * aLen1 + aLen2 * aLen2 - aLen * aLen) / (aLen1 * aLen2) / 2.0f, -1.0f, 1.0f);
  50. return Mathf.Acos(c);
  51. }
  52. private static void Solve(AnimationStream stream, TransformStreamHandle topHandle, TransformStreamHandle midHandle, TransformStreamHandle lowHandle, TransformSceneHandle effectorHandle)
  53. {
  54. Quaternion aRotation = topHandle.GetRotation(stream);
  55. Quaternion bRotation = midHandle.GetRotation(stream);
  56. Quaternion eRotation = effectorHandle.GetRotation(stream);
  57. Vector3 aPosition = topHandle.GetPosition(stream);
  58. Vector3 bPosition = midHandle.GetPosition(stream);
  59. Vector3 cPosition = lowHandle.GetPosition(stream);
  60. Vector3 ePosition = effectorHandle.GetPosition(stream);
  61. Vector3 ab = bPosition - aPosition;
  62. Vector3 bc = cPosition - bPosition;
  63. Vector3 ac = cPosition - aPosition;
  64. Vector3 ae = ePosition - aPosition;
  65. float abcAngle = TriangleAngle(ac.magnitude, ab, bc);
  66. float abeAngle = TriangleAngle(ae.magnitude, ab, bc);
  67. float angle = (abcAngle - abeAngle) * Mathf.Rad2Deg;
  68. Vector3 axis = Vector3.Cross(ab, bc).normalized;
  69. Quaternion fromToRotation = Quaternion.AngleAxis(angle, axis);
  70. Quaternion worldQ = fromToRotation * bRotation;
  71. midHandle.SetRotation(stream, worldQ);
  72. cPosition = lowHandle.GetPosition(stream);
  73. ac = cPosition - aPosition;
  74. Quaternion fromTo = Quaternion.FromToRotation(ac, ae);
  75. topHandle.SetRotation(stream, fromTo * aRotation);
  76. lowHandle.SetRotation(stream, eRotation);
  77. }
  78. }
  79. }