Open GoogleCodeExporter opened 9 years ago
HOWTO: Using Splines to compute animation paths:
(should be easy enough to extrapolate this into 3 dimensions. Alternatively
we could use Cartmull Rom splines which are supported in DirectX:
http://www.mvps.org/directx/articles/catmull/index.htm
Cartmull Rom splines may take any no. of control points (min 4), but we
cannot calculate end positions)
The code provided uses Qubic Bezier-splines which takes four control points and
generates the curve using four blending functions:
* f1(u) = (1 - u)³
* f2(u) = 3u(1 - u)²
* f3(u) = 3u²(1 - u)
* f4(u) = u³
where 0 <= u <= 1
Below, the function that computes points in the curve is shown. fPoint is just a
struct that contains two floats x and y. The blending functions multiplied with
the
control points are added to the pDstPoint.
void BezierComputePoint(float fU, fPoint* pDstPoint, CPoint* pSrcPoints)
{
//
// Add up all the blending functions multiplied with the control points
//
float fBlend;
float f1subu = 1.0f - fU;
//
// First blending function (1-u)^3
//
fBlend = f1subu * f1subu * f1subu;
pDstPoint->x = fBlend * pSrcPoints[0].x;
pDstPoint->y = fBlend * pSrcPoints[0].y;
//
// Second blending function 3u(1-u)^2
//
fBlend = 3 * fU * f1subu * f1subu;
pDstPoint->x += fBlend * pSrcPoints[1].x;
pDstPoint->y += fBlend * pSrcPoints[1].y;
//
// Third blending function 3u^2 * (1-u)
//
fBlend = 3 * fU * fU * f1subu;
pDstPoint->x += fBlend * pSrcPoints[2].x;
pDstPoint->y += fBlend * pSrcPoints[2].y;
//
// Fourth blending function u^3
//
fBlend = fU * fU * fU;
pDstPoint->x += fBlend * pSrcPoints[3].x;
pDstPoint->y += fBlend * pSrcPoints[3].y;
}
The next code snippet shows the DrawBezier function. It takes a CDC pointer as
input,
four control points and how many segments the spline should be divided in. The
more
segments you use, the better the result but this will take more time. So it's
best to
experiment for the best results.
Iterate over all the segments and generate a point on the curve. Draw a line
between
the previous point and the one computed. And at last, draw a line to the ending
point.
void DrawBezier(CDC *pDC, CPoint *pPoints, int nSegments)
{
pDC->MoveTo(pPoints[0]);
fPoint fPointBezier;
for(int i = 0; i < nSegments; i++)
{
BezierComputePoint(i / (float)nSegments, &fPointBezier, pPoints);
pDC->LineTo(ROUND(fPointBezier.x), ROUND(fPointBezier.y));
}
pDC->LineTo(pPoints[3]);
}
Original comment by aretman...@gmail.com
on 4 Feb 2009 at 11:07
Original issue reported on code.google.com by
aretman...@gmail.com
on 4 Feb 2009 at 11:06