ecurtiss / CatRom

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

Add rotation-minimizing frames #11

Closed ecurtiss closed 2 months ago

ecurtiss commented 2 months ago

Starting an issue here to track my progress with rotation-minimizing frames.

There are three types of methods for computing the RMF:

  1. Discrete approximations
  2. Compute the RMF on an approximation of the curve
  3. Numerically integrate the RMF ODE

There's actually a fourth, which is to obtain the RMF as a rotation of the Frenet frame, but this falls victim to the Frenet frame's instability.

Sources

ecurtiss commented 2 months ago

For fun, I tried the fourth option (6b8e138267e036e9ef0bf9efe81166acaf235739), which is to obtain the RMF as a rotation of the Frenet frame. To do this, we numerically compute the following integral given in Guggenheimer: image

I used two strategies, each employing the existing Gauss-Legendre quadrature routines.

  1. For each time $t_i$, parallel transport an initial normal vector $v$ from 0 to $t_i$. (pink)
  2. For each time $ti$, parallel transport the previous normal vector $v{i-1}$ from $t_{i-1}$ to $t_i$. (purple)

The second strategy will always be more accurate, but if the first strategy is sufficiently accurate, then we would have a fast way to compute one-off RMFs.

Indeed, in many cases, the two nearly coincide: image

However, it does not take much effort to break the first strategy. Using a quadrature rule with more samples helps but not enough to make the method sufficiently stable. image

Therefore, only the second strategy is viable. However, if we must go the iterative route, then the double reflection method will easily trump this strategy.

ecurtiss commented 2 months ago

6dfec6c5f519b2f99e9ffa82b4880aecb42c8d69 adds the double reflection method from Wang (2008). Computing the RMF with double reflection relies on precomputing previous RMFs, so users are given the option to precompute a desired number of RMFs for each interpolant. If the user does not precompute any RMFs, then the minimal number of precomputes are performed to satisfy the requested call.

Just eyeballing it, 4 precomputes seems to give nearly the same results as 64, so that's what I've set as the default.

It would be worth looking into whether the double reflection method for quaternions from Yoon (2012) is any faster.