BesselPath.cs 3.1 KB

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