How to convert Unreal Engine 4 spline to a bezier curve?

I have read the source code of USplineComponent and found that for a curve in Unreal, the result is calculated via FMath::CubicInterp:


/**
* Performs a cubic interpolation
*
* @param  P - end points
* @param  T - tangent directions at end points
* @param  Alpha - distance along spline
*
* @return  Interpolated value
*/
template< class T, class U >
static FORCEINLINE_DEBUGGABLE T CubicInterp( const T& P0, const T& T0, const T& P1, const T& T1, const U& A )
{
const float A2 = A  * A;
const float A3 = A2 * A;

return (T)
(((2*A3)-(3*A2)+1) * P0)
+ ((A3-(2*A2)+A) * T0)
+ ((A3-A2) * T1)
+ (((-2*A3)+(3*A2)) * P1);
}


You can follow the logic in USplineComponent::Draw to be convinced.

And the calculation approach above is the same as the cubic hermite spline:

$$\boldsymbol{p}(t) = (2t^3-3t^2+1)\boldsymbol{p}_0 + (t^3-2t^2+t)\boldsymbol{m}_0 + (-2t^3+3t^2)\boldsymbol{p}_1 +(t^3-t^2)\boldsymbol{m}_1$$

Then the problem becomes how to convert a cubic hermite spline to a bezier curve.

I have tried several conversion methods on SO:

But all failed to get a correct bezier curve as USD that can be correctly rendered by Houdini.

But what I have been worrying most is that USplineComponet is not a cubic hermite spline. I'm not sure since I knew few about curve math, even after reading some introduction of curve wiki, PDFs and articles.

The bezier curve data to USD bezier-basis curve procedure may also fail, I don't have a solution to verify converted bezier curve is correct (can generate the same shape in UE4) or not.

All you need to do is rearrange the formula:

\begin{align} P(t) &= (2t^3 - 3t^2 + 1) P_0 \\ &+ (t^3 - 2t^2 + t) T_0 \\ &+ (t^3 - t^2) T_1 \\ &+ (-2t^3 + 3t^2)P_1 \\ \\ &= (-t^3 + 3t^2 - 3t + 1) P_0 + (3t^3 - 6t^2 + 3t) P_0 \\ &+ (3t^3 - 6t^2 + 3t) \frac 1 3 T_0 \\ &+ (-3t^3 + 3t^2) \frac {-1} 3 T_1\\ &+ (t^3) P_1 + (-3t^3 + 3t^2) P_1\\ \\ &= (-t^3 + 3t^2 - 3t + 1) P_0 \\ &+ (3t^3 - 6t^2 + 3t)(P_0 + \frac 1 3 T_0) \\ &+ (-3t^3 + 3t^2)(P_1 - \frac 1 3 T_1) \\ &+ (t^3) P_1 \\ \\ &= (1 - t)^3 P_0 \\ &+ 3(1 - t)^2 t (P_0 + \frac 1 3 T_0) \\ &+ 3(1 - t)t^2(P_1 - \frac 1 3 T_1) \\ &+ t^3 P_1 \\ \end{align}

Now we have it in cubic Bézier form.

So your four control points are:

\begin{align} A &= P_0\\ B &= P_0 + \frac 1 3 T_0\\ C &= P_1 - \frac 1 3 T_1\\ D &= P_1 \end{align}

• That seems equivalent to stackoverflow.com/a/1099357/3427520 which the OP references. Can you show some images of incorrect spline shapes? I've come across some cubic spline schemes where the points B and C don't have the factor of 1/3rd in them (because the underlying library has that factor built in), I wonder if that could be why this conversion didn't work as anticipated? Feb 27, 2020 at 17:07
• Thank you but I had already tried that. Are you sure a USplineComponent represents a cubic hermite spline? Feb 28, 2020 at 5:09
• You verified that in the code yourself, did you not? As RFairey says, showing some examples of expected curves and unexpected outputs can help us diagnose the source of the problem. Feb 28, 2020 at 12:05

As RFairey mentioned, I found the handles in UE4 one-third the length of the Bezier equivalents in other programs like Photoshop and Inkscape. This meant by making them three times longer, the curves would match. This is shown below in all but the bottom right of the image where I intentionally left the handles the same length to show the mismatch.

Edit (19 Feb 21): I found a Editor preference called "Spline Tangent Scale" which defaults to 1, so dropping that to 0.33 now has the spline handle lengths matching.