Sign in to follow this  
irreversible

Auto-calculating tension at interpolation points

Recommended Posts

I am in need of mathematical help on calculating the "tension" (I have no idea if the word is correct for the occasion) of a point between two points. The problem best applies to keyframes and interpolating from one to the next along a smooth path (which happens to be my case). When drawing a non-linearly interpolated line from point A to B to C, I need to calculate the tension at which it enters and leaves B. More graphicaly: let's say the tension value of 0 means that at this point the tension of the line runs horizontally from left to right. I can change the tension by rotating the tensor up to 360 degrees at which point it will again be "horizontal". Given the tension value of 0, if the previous (and the next) keyframe(s) lie(s) on the same level as this one, there is no problem. However, moving the previous and/or next keyframes around (closer, further, up and/or down) will require adjustment of the tension at the current point. To demonstrate this (in this case using cubic interpolation), I have provided a screenshot: in the upper graph the tensors have been manually adjusted to allow the line to smoothly pass through the middle point (note that the adjustment really is manual and therefore not perfect). In the lower graph I've turned the tensor randomly - by roughly 100 degrees - clockwise, causing the incoming line to pass over and twist back on the middle point (since this is the representation of a value changing in TIME on a timeline, the line isn't actually allowed to wrap over the middle point, but is rather clipped horizontally, resulting in a sudden drop). I have solved the graphical representation and user interaction issues and I have my timeline up and running smoothly. However - the key problem here is that the tension value at each point has to be set manually. That I do not like as tension values, as mentioned above, become invalid when moving ajdacent keyframes and have to be readjusted, which is very annoying. What I would like to do is automatically calculate the tension at each point based on the current, previous and next keyframe's value (but also allow the user to change it to create more radical transitions). Unfotunately my math is thoroughly failing me here. To recap - I know the following: - the value at the previous, current and next point (a defined quantity - between 0 and 1) - the tension at the previous point (expressed in the range 0 ... 1) - distance from either point (in absolute quantities, such as time or frames - in this case frames) I need to calculate: - the tension value at the current point (a value between 0 ... 1), which would allow the line passing through it be at a minimum tension I hope I was clear enough in my description and that I didn't omit anything important. Since I've been pondering over this problem for some time now, any feedback would be appreciated :) Thank you.

Share this post


Link to post
Share on other sites
take a look at bezier curve
http://en.wikipedia.org/wiki/B%C3%A9zier_curve

it can be helpfull to your problem.
I don't remeber how to do clickified links at gamedev :)

Share this post


Link to post
Share on other sites
Heh - tangent is a much better word than tension :D

In any case I haven't really been able to figure out yet how to auto-calculate the tangent (since I'm using cubic splines not Bezier curves), but then again I haven't really given it a real shot.

Thank you for the link, though :).

Share this post


Link to post
Share on other sites
Maybe something simple would do.

My first action would be to create the tangent as a weighted proportion of the positions of the neighbouring control points. For example, if the spline is generated by the set {x[i], y[i]}i=0...n you could generate tangents with:

// Border cases
tangent[0] = (y[1] - y[0]) / (x[1] - x[0]);
tangent[n] = (y[n] - y[n-1]) / (x[n] - x[n-1]);

// Interior cases
for (int i = 1, i < n; ++i) {
float tangent_right = (y[i+1] - y[i]) / (x[i+1] - x[i]);
float tangent_left = (y[i] - y[i-1]) / (x[i] - x[i-1]);
float weight = (x[i] - x[i-1]) / (x[i+1] - x[i-1]);
tangent[i] = weight * tangent_right + (1 - weight) * tangent_left;
}
Be warned - this code is untested and not very well thought-through. I'm not entirely sure that it's 'safe' to interpolate gradients like that. You'd probably have a better time writing the equivalent code using normalised vectors to represent the tangents. It's not clear which format you're working in, so I arbitrarily opted for y(x).

If you do use any of that code, it may be worth writing it out on paper and running a few simplification passes over it, as it's not optimised.

Admiral

Share this post


Link to post
Share on other sites
Another way to approximate the tangent is to use finite differences: sample the curve slightly before and slightly after the point you're interested in, the vector connecting the samples should be approximately the tangent.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this