CCD2D.cs 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960
  1. using UnityEngine.Scripting.APIUpdating;
  2. namespace UnityEngine.U2D.IK
  3. {
  4. /// <summary>
  5. /// Utility for 2D based Cyclic Coordinate Descent (CCD) IK Solver.
  6. /// </summary>
  7. [MovedFrom("UnityEngine.Experimental.U2D.IK")]
  8. public static class CCD2D
  9. {
  10. /// <summary>
  11. /// Solve IK Chain based on CCD.
  12. /// </summary>
  13. /// <param name="targetPosition">Target position.</param>
  14. /// <param name="forward">Forward vector for solver.</param>
  15. /// <param name="solverLimit">Solver iteration count.</param>
  16. /// <param name="tolerance">Target position's tolerance.</param>
  17. /// <param name="velocity">Velocity towards target position.</param>
  18. /// <param name="positions">Chain positions.</param>
  19. /// <returns>Returns true if solver successfully completes within iteration limit. False otherwise.</returns>
  20. public static bool Solve(Vector3 targetPosition, Vector3 forward, int solverLimit, float tolerance, float velocity, ref Vector3[] positions)
  21. {
  22. int last = positions.Length - 1;
  23. int iterations = 0;
  24. float sqrTolerance = tolerance * tolerance;
  25. float sqrDistanceToTarget = (targetPosition - positions[last]).sqrMagnitude;
  26. while (sqrDistanceToTarget > sqrTolerance)
  27. {
  28. DoIteration(targetPosition, forward, last, velocity, ref positions);
  29. sqrDistanceToTarget = (targetPosition - positions[last]).sqrMagnitude;
  30. if (++iterations >= solverLimit)
  31. break;
  32. }
  33. return iterations != 0;
  34. }
  35. static void DoIteration(Vector3 targetPosition, Vector3 forward, int last, float velocity, ref Vector3[] positions)
  36. {
  37. for (int i = last - 1; i >= 0; --i)
  38. {
  39. Vector3 toTarget = targetPosition - positions[i];
  40. Vector3 toLast = positions[last] - positions[i];
  41. float angle = Vector3.SignedAngle(toLast, toTarget, forward);
  42. angle = Mathf.Lerp(0f, angle, velocity);
  43. Quaternion deltaRotation = Quaternion.AngleAxis(angle, forward);
  44. for (int j = last; j > i; --j)
  45. positions[j] = RotatePositionFrom(positions[j], positions[i], deltaRotation);
  46. }
  47. }
  48. static Vector3 RotatePositionFrom(Vector3 position, Vector3 pivot, Quaternion rotation)
  49. {
  50. Vector3 v = position - pivot;
  51. v = rotation * v;
  52. return pivot + v;
  53. }
  54. }
  55. }