ecurtiss / CatRom

Creates Catmull-Rom splines for Roblox
https://ecurtiss.github.io/CatRom/
Mozilla Public License 2.0
45 stars 11 forks source link

Support assigning knot vector in constructor #26

Closed ecurtiss closed 1 month ago

ecurtiss commented 2 months ago

Today, the knots in the knot vector are always proportional to the arc lengths of the segments. However, number-type splines are not often used in this way. For example, one could use a number-type spline to interpolate a scalar value in an animation. In this case, the knots would need to correspond to keyframe times, which is something that the user must supply. In fact, this is precisely what I want to do in the internals of CatRom--use a CatRom to animate a roll angle along the spline. In this case, the knot vector would need to be the knot vector of the original spline.

This improvement would imply having 5 arguments for the constructor (points, alpha, tension, loops, knots), so I propose that the constructor now accept a table.

ecurtiss commented 1 month ago

Closing because the stated motivation for this proposal is flawed—merely setting the knot vector to be the keyframes does not fix the issue that we cannot interpolate adjacent points that are equal.

There are two ways we could approach assigning keyframes to control points that do permit equal adjacent points:

  1. Create the spline $S$ as normal with duplicates control points removed, but compose it with some progress function $f: [0, 1]\to [0, 1]$ that accounts for the duplicates. In particular, $f$ would be constant when interpolating equal adjacent points.
  2. Given $n$-dimensional control points, construct a spline in $\mathbb{R}^{n+1}$ where the last coordinate is for time. That is, we create a spline one dimension higher and project a dimension down. This permits us to interpolate adjacent points that are equal in the first $n$ coordinates because they would not be equal in the time coordinate. Moreover, we would need to reparametrize the first $n$ coordinates of the spline in terms of the time coordinate.

This feature is a larger effort than just assigning the knot vector.

ecurtiss commented 1 month ago

I wrote a proof of concept of option 2: https://github.com/ecurtiss/CatRom/tree/keyframes

I modified SegmentFactory to allow us to supply the distances between points while constructing the segments. This allowed me to a create a separate $n$-dimensional positional spline and 1-dimensional time spline using the distances between the $(n+1)$-dimensional points. Then, each 1-dimensional segment is written in the Chebyshev basis and inverted, allowing us to reparametrize the positional spline by the time coordinate.

It works, but some of the methods act poorly given duplicate points, in particular the SolveCFrame methods. Also, since the position and time coordinates are linked, the positional spline is different from what you would get with a regular $n$-dimensional spline between the same control points. I still think option 1 is better.