For next Wednesday you need to make things in your animated scene move in cool ways using spline curves, which can be either Hermites or Beziers (which we went over in class this week) or Bsplines (which Denis Zorin is going over in class).
Remember that there are several steps here:
a,b,c,d
;
at^{3}+bt^{2}+ct+d
.
The first step is often done via an interactive user interface. But you can hard-wire in the geometric parameters.
How do I get from the geometric parameters to the cubic form at^{3}+bt^{2}+ct+d?
Recall from class that each type of geometric spline definition requires a characteristic matrix to determine the corresponding cubic parameters (a,b,c,d).
For Hermite splines, the characteristic matrix is:
For Bezier splines, the characteristic matrix is:
a 2 -2 1 1 P0 b -3 3 -2 -1 P3 c 0 0 1 0 R0 d 1 0 0 0 R3
a -1 3 -3 1 P0 b 3 -6 3 0 P1 c -3 3 0 0 P2 d 1 0 0 0 P3
Key things to keep in mind:
As you bring your animation to life using time-varying cubic splines, the key thing to remember is that any numeric quantity that you want to vary over time in your animation can be controlled by a single parametric curve. For example, you can vary the angle of a joint rotation using one spline curve, or you can vary the X, Y or Z coordinates of an object's position using three spline curves. To control any one time-varying numeric value, you will need to define one corresponding parametric curve.
Also, generally the way to make interesting time-varying curves is to string a number of cubic parametric curves end-to-end in time. If you want the resulting animation to be C(1) continuous (ie: to have a continuous gradient as you transition from one parametric cubic spline to the next), then you just need to make sure that the gradient at the end of one cubic curve is equal to the gradient at the beginning of the next.
For example, suppose we want to trace out a roughly circular path using Hermite parametric curves, and we want an object to follow this path over a four second animation. We will need to define two sequences of cubic parametric curves: one sequence to control the X coordinate of the movement, and the other to control the Y coordinate of the movement.
In particular, we will want to approximate a cosine function in X by using four successive Hermite curves, while approximating a sine function in Y by using four successive Hermite curves.
Recall from class that the four geometric parameters for any Hermite curve are, respectively:
P0 the value at t=0 P3 the value at t=1 R0 the gradient at t=0 R3 the gradient at t=1
To approximate a cosine, the geometric parameters P0,P3,R0,R3 of the four successive Hermite splines for X (to approximate a cosine function) would be:
P0 P3 R0 R3 time=0 to time=1 1 0 0 -1 time=1 to time=2 0 -1 -1 0 time=2 to time=3 -1 0 0 1 time=3 to time=4 0 1 1 0
and the geometric parameters P0,R0,P3,R3 of the four successive Hermite splines for Y (to approximate a sine function) would be:
P0 P3 R0 R3 time=0 to time=1 0 1 1 0 time=1 to time=2 1 0 0 -1 time=2 to time=3 0 -1 -1 0 time=3 to time=4 -1 0 0 1
How do you make successive Bezier curves C(1) continuous?
You might want to define your time-varying path by using Bezier curves. Recall that in order to define a Bezier parametric cubic curve segment, we need four control points: P0,P1,P2,P3. The first and last (P0 and P3) are interpolating points, whereas the second and third (P1 and P2) are noninterpolating guide points.
If you define your path as a sequence of Bezier curves, and you want to ensure C(1) continuity between any curve P0_{i},P1_{i},P2_{i},P3_{i} and the next curve P0_{i+1},P1_{i+1},P2_{i+1},P3_{i+1}, you just need to make sure of the following two things:
But when are two line segments collinear? Remembering that any key point P_{i} is really a coordinate pair (x_{i},y_{i}), we can rewrite these two line segments as:
(x2_{i},y2_{i})→(x3_{i},y3_{i})To say that the two seqments are colinear just means that the ratio between the change in x to the change in y is the same between these two segments:
and(x0_{i+1},y0_{i+1})→(x1_{i+1},y1_{i+1})
(y3_{i} - y2_{i}) / (x3_{i} - x2_{i}) = (y1_{i+1} - y0_{i+1}) / (x1_{i+1} - x0_{i+1})
How do you make successive Bspline curves C(1) continuous?
Successive Bspline curves are always C(1) continuous. Isn't that convenient!
What's a nice object-oriented way to implement all this anyway?
One way to do it is to
make an object class called CubicSpline,
that has an internal storage area for
the four cubic coefficients a,b,c,d
,
and an evaluation method:
public double eval(double t) { return t * (t * (t * a + b) + c) + d; }and then extend that class to make HermiteSpline, BezierSpline, etc., classes.
The class constructor for HermiteSpline could take the four geometric coefficients:
HermiteSpline hs = new HermiteSpline(P0,P3,R0,R3);Internally, you would multiply these four geometric coefficients by your Hermite characteristic matrix to compute the four cubic coefficients
a,b,c,d
.
Then when somebody evaluates the spline,
it will produce the right result.
For example:
// DRAW AN APPROXIMATE QUARTER CIRCLE HermiteSpline hx = new HermiteSpline(1,0,0,-1); HermiteSpline hy = new HermiteSpline(0,1,1, 0); double eps = 0.01; for (double t = 0.0 ; t < 1.0 ; t += eps) drawLine(hx.eval(t ), hy.eval(t ), hx.eval(t+eps), hy.eval(t+eps));Or, in this slightly more ambitious example, we create four such splines to approximate a complete circle:
// DRAW AN APPROXIMATE CIRCLE drawXYCurve(1,0,0,-1, 0,1,1,0); drawXYCurve(0,-1,-1,0, 1,0,0,-1); drawXYCurve(-1,0,0,1, 0,-1,-1,0); drawXYCurve(0,1,1,0, -1,0,0,1); ... // DRAW A PARAMETRIC CUBIC CURVE FOR X AND Y void drawXYCurve(double px0,double px3,double rx0,double rx3, double py0,double py3,double ry0,double ry3) { HermiteSpline hx = new HermiteSpline(px0,px3,rx0,rx3); HermiteSpline hy = new HermiteSpline(py0,py3,ry0,ry3); double eps = 0.01; for (double t = 0.0 ; t < 1.0 ; t += eps) drawLine(hx.eval(t ), hy.eval(t ), hx.eval(t+eps), hy.eval(t+eps));