Files
2026-07-13 13:13:17 +08:00

170 lines
4.9 KiB
C#

using System.Runtime.CompilerServices;
using T3.Core.DataTypes;
namespace T3.Core.Utils.Splines;
public static class BezierPointSpline
{
public static Point[] SamplePointsEvenly(int count, int preSampleSteps, float curvature, Vector3 upVector, ref Point[] sourcePoints)
{
count.Clamp(1, 1000);
var result = new Point[count];
if (_lengthList.Length < preSampleSteps)
{
_lengthList = new float[preSampleSteps];
}
// Pre-sample bezier curve for even distribution
var totalLength = 0f;
var lastPoint = SampleCubicBezier(0, curvature, sourcePoints);
for (var preSampleIndex = 1; preSampleIndex < preSampleSteps; preSampleIndex++)
{
var t = (float)preSampleIndex / preSampleSteps;
var newPoint = SampleCubicBezier(t, curvature, sourcePoints);
var stepLength = Vector3.Distance(newPoint, lastPoint);
lastPoint = newPoint;
totalLength += stepLength;
_lengthList[preSampleIndex] = totalLength;
}
var walkedIndex = 0;
Vector3 lastPos = SampleCubicBezier(0, curvature, sourcePoints);
for (var index = 0; index < count; index++)
{
var wantedLength = totalLength * index / (count - 1) + 0.0002f;
while (wantedLength > _lengthList[walkedIndex + 1] && walkedIndex < preSampleSteps - 2 && walkedIndex < _lengthList.Length-2)
{
walkedIndex++;
}
var l0 = _lengthList[walkedIndex];
var l1 = _lengthList[walkedIndex + 1];
var deltaL = (l1 - l0);
var fraction = (wantedLength - l0) / (deltaL + 0.00001f);
var t = (walkedIndex + fraction) / (preSampleSteps - 1);
var pos = SampleCubicBezier(t - 0.0002f, curvature, sourcePoints);
result[index].Position = pos;
var d = pos - lastPos;
lastPos = pos;
result[index].F1 = 1;
result[index].Orientation = MathUtils.LookAt(Vector3.Normalize(d), -upVector);
result[index].Color = SampleLinearColors(t, ref sourcePoints);
result[index].Scale = new Vector3(1.0f, 1.0f, 1.0f);
result[index].F2 = 1;
}
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector3 SampleCubicBezier2(float t, ref Point[] points)
{
int i;
if (t >= 1f)
{
t = 1f;
i = points.Length - 4;
}
else
{
t = t.Clamp(0, 1) * (points.Length - 1) / 3;
i = (int)t;
t -= i;
i = (i * 3).Clamp(0, points.Length - 4);
}
return Bezier.GetPoint(points[i].Position, points[i + 1].Position, points[i + 2].Position, points[i + 3].Position, t);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 SampleLinearColors(float t, ref Point[] points)
{
int i;
if (t >= 1f)
{
t = 1f;
i = points.Length - 2; // Adjusted index
}
else
{
var tt = t * (points.Length - 1);
i = (int)tt;
t = tt - i;
}
var pA = points[i].Color;
var pB = points[i + 1].Color;
// Perform linear interpolation between colors
var interpolatedColor = pA + (pB - pA) * t;
return interpolatedColor;
}
public static Vector3 SampleCubicBezier(float t, float curvature, Point[] points)
{
int i;
if (t >= 1f)
{
t = 1f;
i = points.Length - 2;
}
else
{
float tt = t * (points.Length - 2);
i = (int)tt;
t = tt - i;
}
var pA = points[i].Position;
var pB = points[i + 1].Position;
var pNext = pB;
var pLast = pA;
if (i > 0)
{
pLast = points[i - 1].Position;
}
if (i < points.Length - 2)
{
pNext = points[i + 2].Position;
}
return Bezier.GetPoint(pA,
pA - (pLast - pB) / curvature * points[i].F1,
pB + (pA - pNext) / curvature * points[i + 1].F1,
pB,
t);
}
private static float[] _lengthList = new float[10];
public static Point[] SamplePoints(int count, ref Point[] sourcePoints)
{
count.Clamp(1, 1000);
var result = new Point[count];
for (var index = 0; index < count; index++)
{
var t = (float)index / count;
result[index].Position = SampleCubicBezier(t, 4, sourcePoints);
result[index].F1 = 1;
}
return result;
}
}