170 lines
4.9 KiB
C#
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;
|
|
}
|
|
} |