non-linear interpolation

I have an object, and i want to interpolate its position between two points over a given time period; but i dont want it to be a linear interpolation. I'm not sure if i'm phrasing this right.

vector posA; // Where we start
vector posB; // Where we end
float timeI; // An interval from 0 - 1


normally i would just do it linearly

vector currentPos = posA  + (posB - posA) * timeI


but i want the object to either:

• a) move faster at the start and slower at the end
• b) move slower at the start and faster at the end

Can anybody point me in the right direction

• Proboably dupe : gamedev.stackexchange.com/questions/11287/…, or at least, the answers you are looking for can be found here. – Jonathan Connell Jul 13 '11 at 12:26
• I really should check to see if it's a duplicate before I answer :( – CiscoIPPhone Jul 13 '11 at 12:32
• Yeah, ill try to search more thorough next time. Maybe i shoulda searched "easing". – Larry Jul 13 '11 at 12:53
• I agree that it's covering the same material as that other question, but this one is a much better question (it's asking a real development-related question with a real answer, not just asking for a forgotten web link). If we can only have one of the two questions, then I'd vote that this is definitely the one to keep. – Trevor Powell Jul 13 '11 at 13:01
• Also probably a duplicate of: gamedev.stackexchange.com/questions/6978/easing-functions – bummzack Jul 13 '11 at 13:20

One way to move slower at the start and faster towards the end would be to square the time:

vector currentPos = posA  + (posB - posA) * (timeI * timeI)


If you look at this graph (wolfram) you can see why this works.

To move faster at the start and slower at the end:

float t = 1 - timeI
vector currentPos = posA  + (posB - posA) * t * t


In video editing (and animation and other fields), the terms used for what you're talking about are "ease in/out" and "smash in/out", with "ease" meaning to begin or end from a standstill, and "smash" meaning to begin or end with full velocity.

Your existing algorithm gives you "smash in, smash out", since it maintains a constant velocity the whole way across the interpolation.

An easy way to get "ease in, smash out" is to square your fraction before performing the interpolation, like this:

timeI = timeI * timeI;


An easy way to get "smash in, ease out" is to square 1.0-fraction, like this:

timeI = (1.0f - timeI) * (1.0f - timeI);


An easy way to get "ease in, ease out" is to use a hermite interpolator:

timeI = (3.0f * timeI * timeI) - (2.0f * timeI * timeI * timeI);


If you need more control than that, you might consider actually moving your object along a hermite spline rather than interpolating. This would allow you far more precise control over starting and ending velocities for your object.

Copying hermite spline maths from my own code:

Vector3D Spline3D::PositionAtTime( float t ) const
{
float tSquared = t * t;
float tCubed = tSquared * t;

float a = 2.f * tCubed - 3.f * tSquared + 1.f;  // 2t^3 - 3t^2 + 1
float b = tCubed - 2.f * tSquared + t;          // t^3 - 2t^2 + t
float c = -2.f * tCubed + 3.f * tSquared;       // -2t^3 + 3t^2
float d = tCubed - tSquared;                    // t^3 - t^2

Vector3D result = (a * m_start) +
(b * m_startVelocity) +
(c * m_end) +
(d * m_endVelocity);

return result;
}


What about Bézier curve? A segment is basically a first degree BC but you can construct second or superior degrees curves that are still segments. I suggest to you to use a cubic BC having the two control point laying on the segment itself. Doing so you can control the speed of the point when moves out the first position and when it reaches the final point.

These are the recursive formula for BCurves As you can see the first is the linear interpolation of two point (a segment); the second is a "linear interpolation of segments" (a quadric), the third is a "linear interpolation of quadrics".

From this comes that when t is small B ≈ P1 and the tangent is P2-P1; when t is near to 1 B becomes P4 and the tangent is P4-P3.

You should not exaggerate with the lenght of P2-P1 and P4-P3 because the curve can elongate, going over the last point and then coming back.

Use a function of the time to produce a t value for your interpolation, for example an ease-in and ease-out function like this:

http://coc.dev77.com/2009/06/smoothness.html

or use one of the standard parabola results.

ease-in : t = time^2

ease-out : t = 1-(1-time)^2