Unity define a curve with 2 keyframes, each composed of a point and a tangent. I guess the simplest curve matching that is a third degree polynomial (a cubic function). Given the 2 points and tangents, it is possible to compute the polynomial coefficients simply by solving the following equation system:
(1) a*p1x^3 + b*p1x^2 + c*p1x + d = p1y
(2) a*p2x^3 + b*p2x^2 + c*p2x + d = p2y
(3) 3*a*p1x^2 + 2*b*p1x + c = tp1
(4) 3*a*p2x^2 + 2*b*p2x + c = tp2
You can solve this manually or using a computer algebra system.
This gives you:
float a = (p1x * tp1 + p1x * tp2 - p2x * tp1 - p2x * tp2 - 2 * p1y + 2 * p2y) / (p1x * p1x * p1x - p2x * p2x * p2x + 3 * p1x * p2x * p2x - 3 * p1x * p1x * p2x);
float b = ((-p1x * p1x * tp1 - 2 * p1x * p1x * tp2 + 2 * p2x * p2x * tp1 + p2x * p2x * tp2 - p1x * p2x * tp1 + p1x * p2x * tp2 + 3 * p1x * p1y - 3 * p1x * p2y + 3 * p1y * p2x - 3 * p2x * p2y) / (p1x * p1x * p1x - p2x * p2x * p2x + 3 * p1x * p2x * p2x - 3 * p1x * p1x * p2x));
float c = ((p1x * p1x * p1x * tp2 - p2x * p2x * p2x * tp1 - p1x * p2x * p2x * tp1 - 2 * p1x * p2x * p2x * tp2 + 2 * p1x * p1x * p2x * tp1 + p1x * p1x * p2x * tp2 - 6 * p1x * p1y * p2x + 6 * p1x * p2x * p2y) / (p1x * p1x * p1x - p2x * p2x * p2x + 3 * p1x * p2x * p2x - 3 * p1x * p1x * p2x));
float d = ((p1x * p2x * p2x * p2x * tp1 - p1x * p1x * p2x * p2x * tp1 + p1x * p1x * p2x * p2x * tp2 - p1x * p1x * p1x * p2x * tp2 - p1y * p2x * p2x * p2x + p1x * p1x * p1x * p2y + 3 * p1x * p1y * p2x * p2x - 3 * p1x * p1x * p2x * p2y) / (p1x * p1x * p1x - p2x * p2x * p2x + 3 * p1x * p2x * p2x - 3 * p1x * p1x * p2x));
Then, to evaluate the value:
float Evaluate(float t)
{
return a*t*t*t + b*t*t + c*t + d;
}
I checked with Unity with the following quick and dirty code:
using UnityEngine;
[ExecuteInEditMode]
public class TestAnimCurve : MonoBehaviour {
public AnimationCurve anim = AnimationCurve.EaseInOut(0, 0, 1, 1);
float a;
float b;
float c;
float d;
void Update () {
float p1x= anim.keys[0].time;
float p1y= anim.keys[0].value;
float tp1=anim.keys[0].outTangent;
float p2x=anim.keys[1].time;
float p2y= anim.keys[1].value;
float tp2= anim.keys[1].inTangent;
Debug.Log(p1x+ ", " + p1y+ ", " + tp1 + ", " + p2x + ", " + p2y + ", " + tp2);
Debug.Log("Evaluate Unity: " + anim.Evaluate(0.1f) + ", " + anim.Evaluate(0.2f) + ", " + anim.Evaluate(0.3f) + ", " + anim.Evaluate(0.4f) + ", " + anim.Evaluate(0.5f) + ", " + anim.Evaluate(0.6f) + ", " + anim.Evaluate(0.76f) + ", " + anim.Evaluate(0.88f) + ", " + anim.Evaluate(0.98f));
a = (p1x * tp1 + p1x * tp2 - p2x * tp1 - p2x * tp2 - 2 * p1y + 2 * p2y) / (p1x * p1x * p1x - p2x * p2x * p2x + 3 * p1x * p2x * p2x - 3 * p1x * p1x * p2x);
b = ((-p1x * p1x * tp1 - 2 * p1x * p1x * tp2 + 2 * p2x * p2x * tp1 + p2x * p2x * tp2 - p1x * p2x * tp1 + p1x * p2x * tp2 + 3 * p1x * p1y - 3 * p1x * p2y + 3 * p1y * p2x - 3 * p2x * p2y) / (p1x * p1x * p1x - p2x * p2x * p2x + 3 * p1x * p2x * p2x - 3 * p1x * p1x * p2x));
c = ((p1x * p1x * p1x * tp2 - p2x * p2x * p2x * tp1 - p1x * p2x * p2x * tp1 - 2 * p1x * p2x * p2x * tp2 + 2 * p1x * p1x * p2x * tp1 + p1x * p1x * p2x * tp2 - 6 * p1x * p1y * p2x + 6 * p1x * p2x * p2y) / (p1x * p1x * p1x - p2x * p2x * p2x + 3 * p1x * p2x * p2x - 3 * p1x * p1x * p2x));
d = ((p1x * p2x * p2x * p2x * tp1 - p1x * p1x * p2x * p2x * tp1 + p1x * p1x * p2x * p2x * tp2 - p1x * p1x * p1x * p2x * tp2 - p1y * p2x * p2x * p2x + p1x * p1x * p1x * p2y + 3 * p1x * p1y * p2x * p2x - 3 * p1x * p1x * p2x * p2y) / (p1x * p1x * p1x - p2x * p2x * p2x + 3 * p1x * p2x * p2x - 3 * p1x * p1x * p2x));
Debug.Log("Evaluate Cubic: " + Evaluate(0.1f) + ", " + Evaluate(0.2f) + ", " + Evaluate(0.3f) + ", " + Evaluate(0.4f) + ", " + Evaluate(0.5f) + ", " + Evaluate(0.6f) + ", " + Evaluate(0.76f) + ", " + Evaluate(0.88f) + ", " + anim.Evaluate(0.98f));
}
float Evaluate(float t)
{
return a * t * t * t + b * t * t + c * t + d;
}
}
After modifing tangents of the animation curve, the debug messages produced by this code are:
0, 0, -4.484611, 1, 1, -10.23884
Evaluate Unity: -0.2431039, -0.1423873, 0.2018093, 0.6891449, 1.219279, 1.691871, 2.077879, 1.854902, 1.193726
Evaluate Cubic: -0.2431039, -0.1423873, 0.2018092, 0.6891448, 1.219279, 1.691871, 2.077879, 1.854902, 1.193726
So it really seams that this approach is the math behind AnimationCurve.Evaluate