- Home /
How to convert cubic Bezier curve into AnimationCurve
I need to transfer animation from 3d party animation software (spine) in to unity. Here is how it looks in spine
according to this page
The Bézier curve array has 4 elements which define the control points: cx1, cy1, cx2, cy2. The X axis is from 0 to 1 and represents the percent of time between the two keyframes. The Y axis is from 0 to 1 and represents the percent of the difference between the keyframe’s values.
here is what I see in input data
[ 0.135, 0.74, 0.918, 0.17 ]
and this is cooridnates for P1 = (0.135, 0.74) and P2 = (0.918, 0.17).
for all cases P0 = (0,0), P3 = (1,1)
At unity side, i need to provide outTangent for P0 and inTangent for P3 which is keyframe[0] and keframe[1] in case of curve has just 2 points.
here is my calculation (which doesn't show correct result):
i and nextI is a keyframe indexes of P0 and P3 in AnimationCurve,
tangentArray is json array contains data specified above [cx1,cy1,cx2,cy2]
parseFloat custom method, i can't use default (float)cx1 or float.parse(cx1)
public static void setCustomTangents(AnimationCurve curve, int i, int nextI, JsonData tangentArray){
float cx1 = parseFloat(tangentArray[0]);
float cy1 = parseFloat(tangentArray[1]);
float cx2 = parseFloat(tangentArray[2]);
float cy2 = parseFloat(tangentArray[3]);
float time = (float)(curve.keys[nextI].time - curve.keys[i].time);
float value = (float)(curve.keys[nextI].value - curve.keys[i].value);
Keyframe thisKeyframe = curve[i];
Keyframe nextKeyframe = curve[nextI];
float outTangent = (cy1 * value)/ (cx1 * time);
float inTangent = ((1 - cy2) * value)/ ((1 - cx2) * time);
thisKeyframe.outTangent = outTangent;
nextKeyframe.inTangent = inTangent;
curve.MoveKey(i, thisKeyframe);
curve.MoveKey(nextI, nextKeyframe);
}
This is result in unity
I've already seen some similar bezier questions like The algorithm of curve in Shuriken Particle System. But 2d day can't figure out how to solve this problem, probably because my math skills is low =).
Thanks.
On Unity P0 and P3 is scaled depends of the time and value zoo$$anonymous$$g, because of that original curve can be stretched in the unity curve view.
Answer by SkywardRoy · Jul 25, 2020 at 02:21 PM
The answer by @Ferb was already great, but I wanted to include the option of keyframe weights to cover everything the animation curve can do.
This function builds the points needed for a line renderer to render the animation curve in Ugui. Maybe it's useful for someone else coming across this page.
private void BuildLine () {
lineRenderer.Points.Clear();
for (var i = 0; i < animationCurve.length - 1; i++) {
var start = animationCurve[i];
var end = animationCurve[i + 1];
var difference = Mathf.Abs(start.time - end.time);
var startTangentLength = difference;
var endTangentLength = difference;
if (start.weightedMode == WeightedMode.Out || start.weightedMode == WeightedMode.Both)
startTangentLength *= start.outWeight;
else
startTangentLength /= 3f;
if (end.weightedMode == WeightedMode.In || end.weightedMode == WeightedMode.Both)
endTangentLength *= end.inWeight;
else
endTangentLength /= 3f;
var p1 = new Vector2(start.time, start.value);
var p2 = new Vector2(end.time, end.value);
var c1 = new Vector2(startTangentLength, startTangentLength * start.outTangent);
var c2 = new Vector2(-endTangentLength, -endTangentLength * end.inTangent);
lineRenderer.Points.Add(p1);
lineRenderer.Points.Add(p1 + c1);
lineRenderer.Points.Add(p2 + c2);
}
var last = animationCurve[animationCurve.length - 1];
lineRenderer.Points.Add(new Vector2(last.time, last.value));
lineRenderer.SetAllDirty();
}
Thank you soo much! This really helped me in converting an AnimationCurve into a bezier curve!
Answer by Ferb · Jan 23, 2014 at 04:30 PM
I don't really understand how Unity is doing its curves myself - or why it doesn't use plain easy-to-calculate Bezier curves. But this answer gives the following code for going from Unity Animation curves to Bezier curves - that is, getting the vectors for the two control points, c1 and c2, from the endpoints, p1 and p2, and Unity's outtangent and intangent:
float tangLengthX = Mathf.Abs(p1.x-p2.x)*0.333333f;
float tangLengthY = tangLengthX ;
c1 = p1;
c2 = p2;
c1.x += tangLengthX ;
c1.y += tangLengthY * tgOut;
c2.x -= tangLengthX ;
c2.y -= tangLengthY * tgIn;
If that's correct (and I don't know whether it is - I can't find any mathematical reference on defining Bezier curves by 'tangent lines', it just seem to be something Unity's creators have dreamt up), you can solve for tgIn and tgOut, which gives:
tangLength = Mathf.Abs(p1.x-p2.x)*0.333333f;
tgOut = (c1.y - p1.y)/tangLength;
tgIn = (p2.y - c2.y)/tangLength;
If that doesn't work, I can only suggest that you construct an animation curve consisting of a few dozen keyframes, as shown here. Then you can evaluate the Bezier curve properly yourself and just force the AnimationCurve to follow it the way you've evaluated it.
Actually, I'm sure that's what you'll have to do. Mathematically, there's no why you can represent cubic Bezier curves properly using just two endpoints and two tangents. To see why, go into your Spine editor (or go here) and make a curve with it's control points in the two corners as shown above, but its first control point somewhere on the bottom axis, and its second control point somewhere on the top axis. That curve has horizontal tangents. Now move those control points horizontally a bit - keep them on the top and bottom axis. The curve changes - but its endpoints and tangents stay the same. There's an infinite number of possible cubic Bezier curves with those same endpoints and tangents - but if its just taking control points and tangents then Unity will only represent a certain one of them, and it probably won't be the one you want.
thanks for your reply. I've seen that post. After it, probably, i do understand what is 0.33333f. Problem is that c1 and c2 is the control points of bezier curve, and x coordinates of these points are hardcoded on unity side for 1/3 of time for c1 and 2/3 of time for c2 of one keyframe. Unfortunately I have different values of x for c1 and c2 in source data, and can't directly calculate tangents for p1 and p2
just for clarification according to my first screenshot and your answers P0 = p1, P1 = c1, P2 = c2, P3 = p2.
unity animation curve,uses tangents ins$$anonymous$$d of control points,because it's an Hermite curve, the Bezier curve deals with control points,however each hermite has a coresponding bezier,and the coresponding bezier for unity has the control points at 1/3,so when someone's changing in the unity's curve editor the tangents,the control points allways remains at 1/3 of its neigbour ... personally I worked only with bezier, and just calculated the control points out of unity curve's tangents ....but it should be possible to just deal with hermite as well(so only the tangents,nothing about control points), Paulius Liekis explained something somewhere else(I didn't try to verify if it's correct)...and for nicolay, if you have a bezier curve with the given control points ,I'm almost sure you can't have another bezier curve with same shape but with different control points ...I mean in the unity's case,the control points' x coordinates are at 1/3 distance ,and your control points aren't ....
Varaughe Thanks for reply, You right, there is algorythm to find corresponding points by bezier curve, and I've already done it. but it doesn't work for some cases. when you have control points with p1 with long x position and y with -x. something like that. p1(100000,0) p2(-100000,-10000000)
Answer by Varaughe · Jul 25, 2020 at 04:55 PM
If you want to see what is the exact equation behind an AnimationCurve, you should check Runtime Curve Editor (from Unity Asset Store). A curve in that package is modeled above an AnimationCurve instance.
Your answer
Follow this Question
Related Questions
What is the length of the Keyframe tangent? 0 Answers
How can I set the tangents of Keyframes in an AnimationCurve through scripting? 1 Answer
Tangents ignored while setting keyframes 1 Answer
How can I set my Animation Curve's Tangents to Flat in script? 0 Answers
Tangent for 5th order Bezier curve 2 Answers