How to convert cubic Bezier curve into AnimationCurve

I need to transfer animation from 3d party animation software ([spine][1]) in to unity.
Here is how it looks in spine

[21030-spinecurve.png*_|21030]

according to [this page][3]

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*.time);*

_ float value = (float)(curve.keys[nextI].value - curve.keys*.value);_
_ Keyframe thisKeyframe = curve;
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
[21031-unity_curve.png*
|21031]
I’ve already seen some similar bezier questions like [The algorithm of curve in Shuriken Particle System][5]. But 2d day can’t figure out how to solve this problem, probably because my math skills is low =).
Thanks.
[1]: http://esotericsoftware.com*
*
[3]: http://esotericsoftware.com/spine-json-format/*_

*[5]: http://answers.unity3d.com/questions/438407/the-algorithm-of-curve-in-shuriken-particle-system.html*_

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][1] 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*;*

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();
}
[1]: UnityUIExtensions / Unity-UI-Extensions / wiki / Controls / UILineRenderer — Bitbucket

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.

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.