FabrikSolver2D.cs 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116
  1. using System.Collections.Generic;
  2. using UnityEngine.Profiling;
  3. using UnityEngine.Scripting.APIUpdating;
  4. namespace UnityEngine.U2D.IK
  5. {
  6. /// <summary>
  7. /// Component for 2D Forward And Backward Reaching Inverse Kinematics (FABRIK) IK.
  8. /// </summary>
  9. [MovedFrom("UnityEngine.Experimental.U2D.IK")]
  10. [Solver2DMenu("Chain (FABRIK)")]
  11. public class FabrikSolver2D : Solver2D
  12. {
  13. private const float kMinTolerance = 0.001f;
  14. private const int kMinIterations = 1;
  15. [SerializeField]
  16. private IKChain2D m_Chain = new IKChain2D();
  17. [SerializeField][Range(kMinIterations, 50)]
  18. private int m_Iterations = 10;
  19. [SerializeField][Range(kMinTolerance, 0.1f)]
  20. private float m_Tolerance = 0.01f;
  21. private float[] m_Lengths;
  22. private Vector2[] m_Positions;
  23. private Vector3[] m_WorldPositions;
  24. /// <summary>
  25. /// Get and Set the solver's itegration count.
  26. /// </summary>
  27. public int iterations
  28. {
  29. get { return m_Iterations; }
  30. set { m_Iterations = Mathf.Max(value, kMinIterations); }
  31. }
  32. /// <summary>
  33. /// Get and Set target distance tolerance.
  34. /// </summary>
  35. public float tolerance
  36. {
  37. get { return m_Tolerance; }
  38. set { m_Tolerance = Mathf.Max(value, kMinTolerance); }
  39. }
  40. /// <summary>
  41. /// Returns the number of chain in the solver.
  42. /// </summary>
  43. /// <returns>This always returns 1.</returns>
  44. protected override int GetChainCount()
  45. {
  46. return 1;
  47. }
  48. /// <summary>
  49. /// Gets the chain in the solver by index.
  50. /// </summary>
  51. /// <param name="index">Chain index.</param>
  52. /// <returns>Returns IKChain2D at the index.</returns>
  53. public override IKChain2D GetChain(int index)
  54. {
  55. return m_Chain;
  56. }
  57. /// <summary>
  58. /// DoPrepare override from base class.
  59. /// </summary>
  60. protected override void DoPrepare()
  61. {
  62. if (m_Positions == null || m_Positions.Length != m_Chain.transformCount)
  63. {
  64. m_Positions = new Vector2[m_Chain.transformCount];
  65. m_Lengths = new float[m_Chain.transformCount - 1];
  66. m_WorldPositions = new Vector3[m_Chain.transformCount];
  67. }
  68. for (int i = 0; i < m_Chain.transformCount; ++i)
  69. {
  70. m_Positions[i] = GetPointOnSolverPlane(m_Chain.transforms[i].position);
  71. }
  72. for (int i = 0; i < m_Chain.transformCount - 1; ++i)
  73. {
  74. m_Lengths[i] = (m_Positions[i + 1] - m_Positions[i]).magnitude;
  75. }
  76. }
  77. /// <summary>
  78. /// DoUpdateIK override from base class.
  79. /// </summary>
  80. /// <param name="effectorPositions">Target position for the chain.</param>
  81. protected override void DoUpdateIK(List<Vector3> effectorPositions)
  82. {
  83. Profiler.BeginSample("FABRIKSolver2D.DoUpdateIK");
  84. Vector3 effectorPosition = effectorPositions[0];
  85. effectorPosition = GetPointOnSolverPlane(effectorPosition);
  86. if (FABRIK2D.Solve(effectorPosition, iterations, tolerance, m_Lengths, ref m_Positions))
  87. {
  88. // Convert all plane positions to world positions
  89. for (int i = 0; i < m_Positions.Length; ++i)
  90. {
  91. m_WorldPositions[i] = GetWorldPositionFromSolverPlanePoint(m_Positions[i]);
  92. }
  93. for (int i = 0; i < m_Chain.transformCount - 1; ++i)
  94. {
  95. Vector3 startLocalPosition = m_Chain.transforms[i + 1].localPosition;
  96. Vector3 endLocalPosition = m_Chain.transforms[i].InverseTransformPoint(m_WorldPositions[i + 1]);
  97. m_Chain.transforms[i].localRotation *= Quaternion.FromToRotation(startLocalPosition, endLocalPosition);
  98. }
  99. }
  100. Profiler.EndSample();
  101. }
  102. }
  103. }