Quick answer: AnimationCurve.Evaluate returns 0 when the curve has no keyframes, when the evaluation time is outside the keyframe range and the edge keyframe values are 0, or when the curve field was overwritten by Unity’s serialization. Add keyframes with non-zero values, check your time range, and ensure the curve is populated in the Inspector or in Reset().

Here is how to fix AnimationCurve.Evaluate returning zero in Unity. You set up a beautiful ease-in curve in the Inspector, call Evaluate(t) at runtime, and get 0.0 every single frame. Your object does not move, your alpha does not fade, your scale does not change. The curve looks correct in the Inspector preview but produces nothing at runtime. This is usually a data problem, not a math problem.

The Symptom

Calling curve.Evaluate(time) returns 0 regardless of the time value. Variations include:

Logging the curve’s keyframe count reveals 0 keys, or the time values being passed are outside the expected range.

Cause 1: Empty Curve

An AnimationCurve with no keyframes returns 0 for any input. This happens when the curve is declared but never populated:

// This curve has zero keyframes — Evaluate always returns 0
[SerializeField] private AnimationCurve fadeCurve;

void Update()
{
    float alpha = fadeCurve.Evaluate(Time.time); // always 0
    Debug.Log($"Keys: {fadeCurve.length}, Alpha: {alpha}"); // Keys: 0
}

Fix: Add keyframes in the Inspector by clicking the curve field and adding points. Or initialize with keyframes in code:

// Initialize with a simple ease-in curve
[SerializeField] private AnimationCurve fadeCurve = new AnimationCurve(
    new Keyframe(0f, 0f),
    new Keyframe(1f, 1f)
);

Note: field initializers are only used when the component is first created. After that, Unity’s serialization system stores the Inspector value, which takes priority. If you added the initializer after the component already existed on a GameObject, you need to reset the component (right-click > Reset) or re-add it.

Cause 2: Time Outside Keyframe Range

Your keyframes span from time 0 to time 1, but you are passing Time.time (which increases indefinitely) or a value in a different range. With the default WrapMode.Clamp, the curve returns the value of the nearest edge keyframe for out-of-range times.

// Curve has keys at t=0 and t=1, but elapsed time goes to 5.0
float t = Time.time; // 0, 0.016, 0.033... 1.0, 1.5, 2.0, 5.0...
float val = curve.Evaluate(t); // returns last keyframe value after t=1

// Fix: normalize time to 0-1 range
float duration = 2f;
float normalized = Mathf.Clamp01(elapsed / duration);
float val = curve.Evaluate(normalized);

If the last keyframe has value 0 (common for fade-out curves), evaluating beyond the range returns 0 via clamping. Check your time mapping.

Cause 3: WrapMode Misunderstanding

AnimationCurve has preWrapMode and postWrapMode. The default is WrapMode.ClampForever, which holds the edge value. Other modes:

curve.preWrapMode = WrapMode.Loop;      // repeat before first key
curve.postWrapMode = WrapMode.PingPong;  // bounce after last key

If your curve goes from value 1 down to value 0 and the post-wrap mode is Clamp, evaluating past the end returns 0. If you expected looping behavior, set postWrapMode = WrapMode.Loop.

Cause 4: Serialization Overwrites Code Initialization

Unity serializes AnimationCurve fields. If the Inspector has an empty curve saved, changing the field initializer in code does not update existing instances. Unity loads the serialized (empty) curve, ignoring your code default.

// This initializer is IGNORED for existing GameObjects
[SerializeField] private AnimationCurve curve = AnimationCurve.EaseInOut(0, 0, 1, 1);

// Fix: use Reset() to apply defaults to existing components
void Reset()
{
    curve = AnimationCurve.EaseInOut(0, 0, 1, 1);
}

The Reset() method runs when a component is first added and when the user clicks Reset in the Inspector. It is the correct place to set default values for serialized fields on existing objects.

Debugging the Curve

Log the curve data to confirm what Unity actually has at runtime:

void Start()
{
    Debug.Log($"Curve has {curve.length} keyframes");
    for (int i = 0; i < curve.length; i++)
    {
        Keyframe kf = curve[i];
        Debug.Log($"  Key {i}: time={kf.time}, value={kf.value}");
    }
    Debug.Log($"Evaluate(0)={curve.Evaluate(0f)}, Evaluate(0.5)={curve.Evaluate(0.5f)}, Evaluate(1)={curve.Evaluate(1f)}");
}

This tells you exactly how many keyframes exist, where they are, and what the curve produces at key time values. If keyframes are 0, the curve was never populated. If values are 0 at edges, your keyframe values are 0 there.

“An AnimationCurve is just data. If Evaluate returns 0, the data is empty, or your time is in the wrong range. Check both before suspecting Unity.”

Related Issues

For AnimationCurve not updating in real-time when modified in the Inspector during Play mode, note that changes to serialized data during Play mode are discarded on exit. For Lerp/Slerp producing wrong values, verify your t parameter is in the 0–1 range. For animation events not firing, check that the AnimationClip has events at the correct normalized time.

Check keyframe count. Normalize your time. Reset() for defaults. Log before blaming Unity.