In class I started by pointing out that you can make arbitrarily complex - but controllable - smooth curves by stringing together parametric cubic spline curves end to end, as long as you make sure that the derivatives of successive spline curves match where they join.
In any given dimension, the value of a parametric cubic spline is given by the vector C of coefficients [a,b,c,d]:
f(t) = a t^{3} + b t^{2} + c t + d
So if you wanted to make a two dimensional parametric cubic spline, to define a path on the (x,y) plane, you would use two of these functions:
x(t) = a_{x} t^{3} + b_{x} t^{2} + c_{x} t + d
y(t) = a_{y} t^{3} + b_{y} t^{2} + c_{y} t + d
Generally we can split the right side of the above equations into two parts, the coefficient vector C = [a,b,c,d] and the cubic parameter vector T = [t^{3},t^{2},t,1], because we're really just doing an inner (dot) product between those two vectors. For example, we can express the last two equations as:
x(t) = C_{x} • T
y(t) = C_{y} • T
In this form it's easy to evaluate splines. For example, let's say you're doing an animation, and you want to animate a value (eg: the angle of a swinging arm) from time time_{1} to time_{2}. If you have the four spline coefficients C = [a,b,c,d] for that segment of the animation, then at any moment in time you just need to evaluate the cubic spline function based on the fraction of time that has elapsed between time_{1} and time_{2}:
t = (time - time_{1}) / (time_{2} - time_{1})
T = [t^{3},t^{2},t,1]
f(t) = C • T
Similarly, if you want to draw a cubic curve, and you have the coefficient vectors C_{x} and C_{y}, then you can do something like this (in pseudocode):
for (t = 0 ; t < 1 ; t += ε) {
T_{0} = [t^{3},t^{2},t,1]
T_{1} = [(t+&epsilon)^{3}, (t+&epsilon)^{2}, t+&epsilon, 1]
drawLine ( C_{x}•T_{0} , C_{y}•T_{0} , C_{x}•T_{1} , C_{y}•T_{1} )
}
Of course, as we said in class, it is not really intuitive for humans to build nice looking cubic curves as weighted sums of the primitive functions t^{3}, t^{2}, t and 1. So we generally want to design parametric cubic spline curves not in the space C, but rather in some more convenient space of coefficients G, which would allow us to use more intuitive curve shapes.
Hermite splines:
For example, if we want to specify a function value at the beginning and at the end (of the spline curve, as well as a function derivative at the beginning and the end of the spline curve, then we are working with Hermite splines. By convention, we refer to the beginning and end points as P1 and P4, respectively, and we refer to their derivatives as as R1 and R4, respectively.
This allows us to work with the four intuitive curve primitives:
To do our inner loop computations, we need to convert this geometry description G = [P1,P4,R1,R4] to a cubic coefficients description C = [a,b,c,d].
In other words, we need to transform function coordinate systems:
We want cubic functions | We have geometric functions | |
---|---|---|
To do this, we just use the Hermite matrix:
a | 2 | -2 | 1 | 1 | P1 | ||
b | ← | -3 | 3 | -2 | -1 | P4 | |
c | 0 | 0 | 1 | 0 | R1 | ||
d | 1 | 0 | 0 | 0 | R4 |
Note that the columns of the Hermite matrix are just the coefficients of the geometric functions (you can see this from the parts highlighted in red above).
Bezier splines and B-Splines:
We also briefly touched on Bezier splines and B-Splines, which are different ways of presenting parametric cubic splines to a user. In the next class we will go over these in more detail.