|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionMany people are impressed by realistic camera animations in games or multimedia demos. The math behind what is commonly called camera interpolation is actually pretty simple. In this article, I will focus on a simple algorithm that uses a particular class of spline curves called Overhauser or Catmull-Rom splines, and I will show how and why they are superior to other existing more or less similar approaches. Math is Your FriendYou may hate me for this, but math can be really nice. We will brush up our knowledge of vector calculus in this section, which will allow us to understand the sample code better. Let's start with the basics: A curve that passes through its control points is said to interpolate those points. Bezier curves interpolate only 2 out of each 4 control points, while B-splines interpolate none of the specified control points (the curve goes smoothly around those points). The Catmull-Rom splines, also called Overhauser splines, belong to a class of curves known as Hermite splines. They are uniform rational cubic polynomial curves that interpolate between N control points and pass through exactly N-2 control points (except the first and last one). They are uniform, because the control points (also known as knots) are spaced at equal intervals with respect to the curve's parameter ( The parametric equation of the Catmull-Rom spline is given by:
Figure 1: Parametric equation of Catmull-Rom spline.
Where the vectors V and T and matrix M are:
Figure 2: Members of Catmull-Rom spline equation.
We could simply use this equation as is, and code up our solution using vector and matrix multiplication. While doable, that would probably not be very efficient. Let us simplify the equation a bit. I encourage you to double-check my math -- it's fun. By multiplying the horizontal vector T with matrix M and factoring in the vertical vector, we get:
Figure 3A: Simplification of Eq1.
Where
Figure 3: Simplification of Eq1.
Figure 3A shows the final equation's members. What does all of this gibberish mean? Well, it means that if you know N intermediate positions plus possibly axis/angle pairs for a camera at N moments in time, you can produce an accurate and smooth animation of the camera by interpolating between N-2 of those positions and axis/angle pairs using Eq 3A above. The camera will pass through all the middle N-2 points. [Note: If you double the start and end points, the camera will pass through all N positions.] Coding It UpFirst, we need a class to provide an abstraction for our control points, /// Minimal 3-dimensional vector abstraction
class vec3
{
public:
// Constructors
vec3() : x(0), y(0), z(0)
{}
vec3(float vx, float vy, float vz)
{
x = vx;
y = vy;
z = vz;
}
vec3(const vec3& v)
{
x = v.x;
y = v.y;
z = v.z;
}
// Destructor
~vec3() {}
// A minimal set of vector operations
vec3 operator * (float mult) const // result = this * arg
{
return vec3(x * mult, y * mult, z * mult);
}
vec3 operator + (const vec3& v) const // result = this + arg
{
return vec3(x + v.x, y + v.y, z + v.z);
}
vec3 operator - (const vec3& v) const // result = this - arg
{
return vec3(x - v.x, y - v.y, z - v.z);
}
float x, y, z;
};
Pretty simple. Now we will introduce a new class for abstracting our spline. #include "vec3.hpp"
#include
This is, again, pretty intuitive: the The methods vec3 CRSpline::GetInterpolatedSplinePoint(float t)
{
// Find out in which interval we are on the spline
int p = (int)(t / delta_t);
// Compute local control point indices
#define BOUNDS(pp) { if (pp < 0) pp = 0;
else if (pp >= (int)vp.size()-1) pp = vp.size() - 1; }
int p0 = p - 1; BOUNDS(p0);
int p1 = p; BOUNDS(p1);
int p2 = p + 1; BOUNDS(p2);
int p3 = p + 2; BOUNDS(p3);
// Relative (local) time
float lt = (t - delta_t*(float)p) / delta_t;
// Interpolate
return CRSpline::Eq(lt, vp[p0], vp[p1], vp[p2], vp[p3]);
}
As the code above shows, function Any sequence of 2D or 3D vectors can be interpolated in a similar fashion. For example, camera axis/angles, the positions and orientation of various moving objects in a scene, etc. The beauty of this approach compared to using b-splines or Bezier curves is that the resulting curves touch all of their control points (again, make sure to double the first and last control points to make that possible). Using the CodeHere, I included a very primitive application of the package, implemented in Borland Dev Studio 4. It basically instantiates the
I hope you did not find my little math session too boring. Enjoy the code. References
History
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||