暫無描述
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

FabrikSolver2D.cs 4.1KB

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 responsible for 2D Forward And Backward Reaching Inverse Kinematics (FABRIK) IK.
  8. /// </summary>
  9. [MovedFrom("UnityEngine.Experimental.U2D.IK")]
  10. [Solver2DMenu("Chain (FABRIK)")]
  11. [IconAttribute(IconUtility.IconPath + "Animation.IKFabrik.png")]
  12. public sealed class FabrikSolver2D : Solver2D
  13. {
  14. const float k_MinTolerance = 0.001f;
  15. const int k_MinIterations = 1;
  16. [SerializeField]
  17. IKChain2D m_Chain = new IKChain2D();
  18. [SerializeField]
  19. [Range(k_MinIterations, 50)]
  20. int m_Iterations = 10;
  21. [SerializeField]
  22. [Range(k_MinTolerance, 0.1f)]
  23. float m_Tolerance = 0.01f;
  24. float[] m_Lengths;
  25. Vector2[] m_Positions;
  26. Vector3[] m_WorldPositions;
  27. /// <summary>
  28. /// Get and set the solver's integration count.
  29. /// </summary>
  30. public int iterations
  31. {
  32. get => m_Iterations;
  33. set => m_Iterations = Mathf.Max(value, k_MinIterations);
  34. }
  35. /// <summary>
  36. /// Get and set target distance tolerance.
  37. /// </summary>
  38. public float tolerance
  39. {
  40. get => m_Tolerance;
  41. set => m_Tolerance = Mathf.Max(value, k_MinTolerance);
  42. }
  43. /// <summary>
  44. /// Returns the number of chains in the solver.
  45. /// </summary>
  46. /// <returns>Returns 1, because FABRIK Solver has only one chain.</returns>
  47. protected override int GetChainCount() => 1;
  48. /// <summary>
  49. /// Gets the chain in the solver at index.
  50. /// </summary>
  51. /// <param name="index">Index to query. Not used in this override.</param>
  52. /// <returns>Returns IKChain2D for the Solver.</returns>
  53. public override IKChain2D GetChain(int index) => m_Chain;
  54. /// <summary>
  55. /// Prepares the data required for updating the solver.
  56. /// </summary>
  57. protected override void DoPrepare()
  58. {
  59. if (m_Positions == null || m_Positions.Length != m_Chain.transformCount)
  60. {
  61. m_Positions = new Vector2[m_Chain.transformCount];
  62. m_Lengths = new float[m_Chain.transformCount - 1];
  63. m_WorldPositions = new Vector3[m_Chain.transformCount];
  64. }
  65. for (var i = 0; i < m_Chain.transformCount; ++i)
  66. {
  67. m_Positions[i] = GetPointOnSolverPlane(m_Chain.transforms[i].position);
  68. }
  69. for (var i = 0; i < m_Chain.transformCount - 1; ++i)
  70. {
  71. m_Lengths[i] = (m_Positions[i + 1] - m_Positions[i]).magnitude;
  72. }
  73. }
  74. /// <summary>
  75. /// Updates the IK and sets the chain's transform positions.
  76. /// </summary>
  77. /// <param name="targetPositions">Target position for the chain.</param>
  78. protected override void DoUpdateIK(List<Vector3> targetPositions)
  79. {
  80. Profiler.BeginSample(nameof(FabrikSolver2D.DoUpdateIK));
  81. var targetPosition = targetPositions[0];
  82. targetPosition = GetPointOnSolverPlane(targetPosition);
  83. if (FABRIK2D.Solve(targetPosition, iterations, tolerance, m_Lengths, ref m_Positions))
  84. {
  85. // Convert all plane positions to world positions
  86. for (var i = 0; i < m_Positions.Length; ++i)
  87. {
  88. m_WorldPositions[i] = GetWorldPositionFromSolverPlanePoint(m_Positions[i]);
  89. }
  90. for (var i = 0; i < m_Chain.transformCount - 1; ++i)
  91. {
  92. var startLocalPosition = (Vector2)m_Chain.transforms[i + 1].localPosition;
  93. var endLocalPosition = (Vector2)m_Chain.transforms[i].InverseTransformPoint(m_WorldPositions[i + 1]);
  94. m_Chain.transforms[i].localRotation *= Quaternion.AngleAxis(Vector2.SignedAngle(startLocalPosition, endLocalPosition), Vector3.forward);
  95. }
  96. }
  97. Profiler.EndSample();
  98. }
  99. }
  100. }