I’ve figured out a lot of math and how to fit it in the Spline Framework. Particularly CatmullRom with alpha and tension, and Hermite1stDerivative. Both have been implemented with matrix operations.
I also have functions that outputs an EasingFunction (untested so far).
GetEasingFunction(SplineName, params, inputPoints)
Here’s the document I’m working on
class Spline
Provides a set of common Splines and allows the creation of new polynomial splines.
For most splines, you will need only GetSpline and either genCubicPoints or genSegment.
GetSpline(SplineName,params,emit,consume)
This is the primary method of creating a spline. The spline name is a string, params is an object,
and emit & consume provide flexibility for specifying points (explained below).
Current splines:
- Bezier,
- CubicBezier,
- QuadraticBezier,
- CubicCatmullRom,
- CubicHermite,
- CubicHermite1stDerivative,
- CubicB,
- CubicBeta01,
- CubicBeta,
- CubicM,
- CubicCardinal,
- CubicTau,
- CubicDelta
Functions
*genSegment( tesselation,inputPoints,emitFirstPoint,emit,consume)
Generate ouput points for a single segment of the spline. Called by genCubicPoints, and calls setTessellationMatrix and then genPoint repeatedly.
*genCubicPoints(tesselation,points,closed=false,clampStart=true,clampEnd=true)
Generate output points for a sequence of piecewise segments. For Bezier and Hermite, use genSegment only.
setTessellationMatrix(inputPoints,consume) - set input points
Generate a new tesselation matrix for a new segment. Automatically called from genCubicPoints but can be called on its own.
getPoint(t,emit)
Calculate a new point with already defined tesselation matrix.
setBasisMatrix(splineString,...parameters) - change spline type and/or parameters
Update the basis matrix with new parameters (or a new spline)
constructor(squareMatrixPointsColFirst,emit,consume)
If you know the exact basis matrix, you can use the constructor. Using GetSpline to obtain a pre-defined spline is preferred.
EmitVector3, ConsumeVector3 (and \*Array(default), \*Vector2, \*Scalar, \*Color3, and \*Color4)
Useful for defining the input and output as Vector3 when calling the GetSpline or the constructor. Can be overridden in any function that accepts emit or consume. Other pre-defined emit and consume functions are provided for values: Scalar, Vector2, Color3, Color4
About
Spline class creates generic polynomial splines that use the form:
Monomial Basis * Geometric Matrix * Control Points
The creation of a spline occurs in two steps, much like Curve3 splines which use CreateX() then .getPoints(). In contrast, Spline uses GetSpline() and genSegment(). Input points (and tesselation/nbPoints) are provided to genSegment(tesselation,inputPoints) rather than the constructor.
This provides a convenient separation of the calculation required to generate the points and minimizes the creation of Vector3 point arrays. Instead, the calculated matrices are retained in the instance in two steps. As mentioned, the general form of the Spline is:
Monomial Basis * Geometric Matrix * Control Points
Note that the Geometric Matrix is sometimes referred to as the spline basis.
The constructor calculates and retains the Geometric Matrix based on the spline type and spline parameters, such as tension or beta. Then genSegment(tesselation,inputPoints) calculates and retains
Geometric Matrix * Control Points as *tesselationMatrix*.
Finally, t sweeps from zero to one, and each tesselation step calculates the Monomial Basis from the value of t and generates each point from Monomial Basis * this.tesselationMatrix.
Evaluation of a Spline segment
A spline segment is evaluated with a number of control points equal to the Order of the spline. A Cubic spline (order 4) has four points needed for evaluation of a segment. For most splines (with the notable exceptions of Bezier and Hermite) only the segment between the second and third point is calculated as the value of t is swept from zero to one.
Sequence of control points
A sequence of control points is specified to genCubicPoints. Nominally, the sequence is divided into a “rolling” group of points of size equal to the order of the spline. For a cubic spline, each group of four points is evaluated as a spline segment evaluated between the second and third point. The group is shifted by one point and repeated until all points are included in a group.
The arguments “closed,” “clampStart,” and “clampEnd” control how the first and last points are treated. Without closed or clamped, the first and last segments are not calculated.
Flexibility
Several aspects of this Spline class provide a lot of flexibility in the creation of splines and the the input and output of “points”.
Internal point format
The internal representation of points, and the nominal input and output point format is as an Array of numbers. Calculations use a flexible Matrix class.
Input point format
individual points are expected as an array, and can be of any dimension (typically, 1, 2, 3, or 4 numbers). However, a function can be specified (“consume”) and is used to convert each point provided into an Array (or TypedArray). consume() can be specified in the constructor or each time genSegment() is called.
Output point format
the ouput format is nominally an array, as well, that is the same length, and thus the same dimension, as the input points. The user can specify a function “emit” to convert each point from an array to any format desired.
Point Format Conversion
as a useful example, EmitConsumeVector3 is provided which will convert to and from Vector3 objects.
EmitConsumeVector3 = [(a)=> new BABYLON.Vector3(a[0],a[1],a[2]), (v)=>v.asArray()]
The full set of supplied format conversions is: Array(default), Vector3, Vector2, Scalar, Color3, and Color4
EmitVector3, ConsumeVector3, EmitVector2, ConsumeVector2, EmitScalar, ConsumeScalar, EmitColor3, ConsumeColor3, EmitColor4, ConsumeColor4
Once I figure out Quaternion splines, I’ll add that to the list.
Generators
The advantage of using generators vs arrays to create output points is not needing to store output points in temporary arrays. When an array of output points is needed, the user can use […genCubicPoints()] to do so. When emit is a=>new BABYLON.Vector3(…a), […genCubicPoints()] will result in an array of Vector3 points. Further, new BABYLON.Curve3([…genCubicPoints()]) results in a Curve3 object.
However, an intermediate array can be eliminated if the output is written directly to a VertexBuffer using a simple for…of loop. Similarly, writing directly to a thinInstance Matrix buffer is possible, again, without creating large and temporary array storage.
Flexible Matrix Calculations
In the most common case, the matrix sizes are
Monomial Basis * Geometric Matrix * Control Points => 1x4 * 4x4 * 4x3
This represents a Cubic Spline (defined by square Geometric Matrix) and four three-dimensional Control Points. The Geometric Matrix size is defined by the spline “order”, and the Control Points size is defined by the user (e.g. 2d or 3d points) and is mirrored in the output point dimension. Generically,
Output Point = Monomial Basis * Geometric Matrix * Control Points =>
1 x Dimension = 1 x Order * Order x Order * Order x Dimension
Because the Spline class uses a flexible Matrix class for calculations, it can support any Order spline and any Dimension point. Internal to the Matrix class, a Float32Array is used for storage.
Monomial Basis
Nominally, the Monomial Basis is a function of “t” and is a matrix of size 1xOrder consisting of t raised to increasing powers starting with power zero.
Monomial Basis => [t^0, t^1, t^2, t^3, t^4,...] up to one minus the spline order.
For a Cubic Spline, Order is 4 and the Monomial Basis is [0, t, t*t, t*t*t]
For each step in evaluating the spline, t is uniformly swept from 0 to 1, resulting in a number of points (specified by the tesselation parameter to genSegment) that define line segments along the spline curve.
Parameterization
Parameterization refers to a modification in the step size of t. In general, a uniform step in t does not result in a uniform distance of the resulting spline curve (called “arc length”).
A uniform arc length with a given uniform step in t is called arc-length parameterization. There is not a deterministic general solution to creating a uniform arc-length parameterization of a spline, and is not yet available in the Spline class.
Alpha
Another application of Parameterization is implememting the parameter “alpha” for a Catmull-Rom Spline. The difference between Chordal, Centripital, and Uniform Catmull-Rom Spline is the value for alpha.
Application of “alpha” for a Catmull-Rom Spline requires a parameterization of t that includes the distance between control points. A convenient place in the Spline class to capture this parameterization is when the spline segment is defined with new input points supplied to genSegment.