BesselPath.cs 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. using System.Collections.Generic;
  2. using Fort23.Core;
  3. using UnityEngine;
  4. namespace Core.Utility
  5. {
  6. [System.Serializable]
  7. /// <summary>
  8. /// 贝塞尔曲线
  9. /// </summary>
  10. public class BesselPath : CObject
  11. {
  12. public List<Vector3> controlPoints = new List<Vector3>();
  13. /// <summary>
  14. /// 全部长度
  15. /// </summary>
  16. public float allDis;
  17. public Vector3 CalculatePoint(float t)
  18. {
  19. if (controlPoints.Count < 2)
  20. {
  21. Debug.LogError("需要至少2个控制点来计算贝塞尔曲线");
  22. return Vector3.zero;
  23. }
  24. t = Mathf.Clamp01(t);
  25. // return controlPoints[0] * ((1 - t) * (1 - t) * (1 - t)) +
  26. // controlPoints[1] * (3 * t * (1 - t) * (1 - t)) +
  27. // controlPoints[2] * (3 * t * t * (1 - t)) +
  28. // controlPoints[3] * (t * t * t);
  29. int n = controlPoints.Count - 1; // 阶数
  30. Vector3 point = Vector3.zero;
  31. for (int i = 0; i <= n; i++)
  32. {
  33. // 计算伯恩斯坦多项式
  34. float bernstein = Bernstein(n, i, t);
  35. point += bernstein * controlPoints[i];
  36. }
  37. return point;
  38. }
  39. // 计算伯恩斯坦多项式
  40. private float Bernstein(int n, int i, float t)
  41. {
  42. return BinomialCoefficient(n, i) * Mathf.Pow(1 - t, n - i) * Mathf.Pow(t, i);
  43. }
  44. public void SetLengthAtT(int segments = 50)
  45. {
  46. allDis = GetLengthAtT(segments);
  47. }
  48. public float GetLengthAtT(float t, int segments = 50)
  49. {
  50. if (controlPoints.Count < 2) return 0f;
  51. t = Mathf.Clamp01(t);
  52. float length = 0f;
  53. Vector3 previousPoint = CalculatePoint(0);
  54. float step = 1.0f / segments;
  55. for (int i = 1; i <= segments; i++)
  56. {
  57. float currentT = i * step;
  58. if (currentT < t)
  59. {
  60. continue;
  61. }
  62. Vector3 currentPoint = CalculatePoint(currentT);
  63. length += Vector3.Distance(previousPoint, currentPoint);
  64. previousPoint = currentPoint;
  65. }
  66. return length;
  67. }
  68. // 计算二项式系数 C(n,i)
  69. private float BinomialCoefficient(int n, int i)
  70. {
  71. return Factorial(n) / (Factorial(i) * Factorial(n - i));
  72. }
  73. // 计算阶乘
  74. private float Factorial(int n)
  75. {
  76. if (n <= 1) return 1;
  77. float result = 1;
  78. for (int i = 2; i <= n; i++)
  79. {
  80. result *= i;
  81. }
  82. return result;
  83. }
  84. // 获取曲线的切线(数值近似)
  85. public Vector3 GetTangent(float t)
  86. {
  87. const float delta = 0.001f;
  88. t = Mathf.Clamp01(t);
  89. // 使用数值微分近似切线
  90. Vector3 p1 = CalculatePoint(t - delta);
  91. Vector3 p2 = CalculatePoint(t + delta);
  92. return (p2 - p1).normalized;
  93. }
  94. public override void ActiveObj()
  95. {
  96. }
  97. public override void DormancyObj()
  98. {
  99. controlPoints.Clear();
  100. }
  101. }
  102. }