As you can see, the points are not evenly spread out and the part does not travel at a linear rate.
I’ve tried readjusting every point but to no avail.
local points = {
}
for t = 0, 100 do
local v3 = cubic(p0.Position, p1.Position, p2.Position, p3.Position, t / 100)
local Or = cubic(p0.Orientation, p1.Orientation, p2.Orientation, p3.Orientation, t / 100)
points[t] = { -- table with all info all that certain point
["Vector"] = v3,
["Time"] = t,
["Orientation"] = Or
}
end
print(points)
local totaldistance = points[#points].Vector - points[0].Vector -- getting total curve length by subracting the last point's vector3 from the first's.
print(#points)
for i,v in pairs(points) do
print(i)
v = (totaldistance / #points) * i -- readjusting every point (total curve length divided by the number of points multiplied by whatever point we are currently on.
end
Any help is deeply appreciated, this is my 3rd time posting about this.
There are a number of ways to compute this, and because you’re working with cubic Beziers, they are all numerical solutions; only quadratic Bezier curves have a closed-form expression for arc length, and in practice not even that is commonly used because it has enough square roots in it to make it slower than many numerical approximations. Which numerical method you use normally depends on whether you’re prioritizing speed (typical for games), or accuracy (e.g. for smooth vector graphics rendering).
The approach most game developers use is the simplest one that you can do in two passes:
Pass 1 is what you already have implemented, but in addition to saving the 3D points, you also accumulate the approximate arc length as you go, by adding up the length of the segments between points, i.e. summing (points[n].v3-points[n-1].v3).Magnitude in your example.
Pass 2 involves resampling the curve into uniformish-length segments. Figure out how many final sample points you want and divide the arc-length estimate you got in Pass 1 by that number. Then just take a linear pass through the non-uniform sample point array, and build the uniform array by doing simple interpolation between the pairs of non-uniform samples whose arc length estimates bound the estimate for the uniform sample point (which is just a multiple of the uniform segment length). If your initial non-uniform pass has MANY more samples than you need for the uniform pass, you could also possibly speed things up by doing a binary search instead of a linear pass, but that’s rarely necessary.
There is a lot more that can be said about this. For example, it’s another part of the problem to estimate the minimum number of sample points needed for each pass in order achieve an acceptable error (amount from which the discrete estimate differs from the ideal curve). It becomes application-specific at this point: if you know the worst-case curvature, you might be able to hard-code sample numbers and avoid any iteration. If curves vary widely in curvature, an interative approach might be best; one where you subdivide the uniform segments until the adjustments to the resulting mid-points become too small to care about.
You can find the length by first finding the derivative of your bezier curves with respect to each XYZ dimension. This can be done by taking it in its parametric form.
x’(t) = (3(1-t)^2)*(P1.X-P0.X)+6(1-t)*t*(P2-P1)+(3t^2)*(P3-P2)
y’(t) = … just replace the .X with .Y
z’(t) = … just replace the .X with .Z
then your going to need to integrate across your bezier curve. I am assuming your bezier curve is limited to a t value of 0 to 1. You could do this by hand… but its probably going to end up with an integral that’s impossible to solve without using maxima
so I would just use numerical integration for that. The length of the bezier curve then is the definite integral from 0 to 1 of sqrt(x’(t)^2 + y’(t)^2 + z’(t)^2)dt