float FRichCurve::Eval(float InTime, float DefaultValue) const { // Remap time if extrapolation is present and compute offset value to use if cycling float CycleValueOffset = 0; RemapTimeValue(InTime, CycleValueOffset); const int32 NumKeys = Keys.Num(); float InterpVal = DefaultValue; if (NumKeys == 0) { // If no keys in curve, return the Default value we passed in. InterpVal = DefaultValue; } else if (NumKeys < 2 || (InTime <= Keys[0].Time)) { if (PreInfinityExtrap == RCCE_Linear && NumKeys > 1) { float DT = Keys[1].Time - Keys[0].Time; if (FMath::IsNearlyZero(DT)) { InterpVal = Keys[0].Value; } else { float DV = Keys[1].Value - Keys[0].Value; float Slope = DV / DT; InterpVal = Slope * (InTime - Keys[0].Time) + Keys[0].Value; } } else { // Otherwise if constant or in a cycle or oscillate, always use the first key value InterpVal = Keys[0].Value; } } else if (InTime < Keys[NumKeys - 1].Time) { // perform a lower bound to get the second of the interpolation nodes int32 first = 1; int32 last = NumKeys - 1; int32 count = last - first; while (count > 0) { int32 step = count / 2; int32 middle = first + step; if (InTime > Keys[middle].Time) { first = middle + 1; count -= step + 1; } else { count = step; } } int32 InterpNode = first; const float Diff = Keys[InterpNode].Time - Keys[InterpNode - 1].Time; if (Diff > 0.f && Keys[InterpNode - 1].InterpMode != RCIM_Constant) { const float Alpha = (InTime - Keys[InterpNode - 1].Time) / Diff; const float P0 = Keys[InterpNode - 1].Value; const float P3 = Keys[InterpNode].Value; if (Keys[InterpNode - 1].InterpMode == RCIM_Linear) { InterpVal = FMath::Lerp(P0, P3, Alpha); } else { const float OneThird = 1.0f / 3.0f; const float P1 = P0 + (Keys[InterpNode - 1].LeaveTangent * Diff*OneThird); const float P2 = P3 - (Keys[InterpNode].ArriveTangent * Diff*OneThird); InterpVal = BezierInterp(P0, P1, P2, P3, Alpha); } } else { InterpVal = Keys[InterpNode - 1].Value; } } else { if (PostInfinityExtrap == RCCE_Linear) { float DT = Keys[NumKeys - 2].Time - Keys[NumKeys - 1].Time; if (FMath::IsNearlyZero(DT)) { InterpVal = Keys[NumKeys - 1].Value; } else { float DV = Keys[NumKeys - 2].Value - Keys[NumKeys - 1].Value; float Slope = DV / DT; InterpVal = Slope * (InTime - Keys[NumKeys - 1].Time) + Keys[NumKeys - 1].Value; } } else { // Otherwise if constant or in a cycle or oscillate, always use the last key value InterpVal = Keys[NumKeys - 1].Value; } } return InterpVal+CycleValueOffset; }
float FRichCurve::Eval(const float InTime, float DefaultValue) const { const int32 NumKeys = Keys.Num(); float InterpVal = DefaultValue; if (NumKeys == 0) { // If no keys in curve, return the Default value we passed in. InterpVal = DefaultValue; } else if (NumKeys < 2 || (InTime <= Keys[0].Time)) { // If only one point, or before the first point in the curve, return the first points value. InterpVal = Keys[0].Value; } else if (InTime < Keys[NumKeys - 1].Time) { // perform a lower bound to get the second of the interpolation nodes int32 first = 1; int32 last = NumKeys - 1; int32 count = last - first; while (count > 0) { int32 step = count / 2; int32 middle = first + step; if (InTime > Keys[middle].Time) { first = middle + 1; count -= step + 1; } else { count = step; } } int32 InterpNode = first; const float Diff = Keys[InterpNode].Time - Keys[InterpNode - 1].Time; if (Diff > 0.f && Keys[InterpNode - 1].InterpMode != RCIM_Constant) { const float Alpha = (InTime - Keys[InterpNode - 1].Time) / Diff; const float P0 = Keys[InterpNode - 1].Value; const float P3 = Keys[InterpNode].Value; if (Keys[InterpNode - 1].InterpMode == RCIM_Linear) { InterpVal = FMath::Lerp(P0, P3, Alpha); } else { const float OneThird = 1.0f / 3.0f; const float P1 = P0 + (Keys[InterpNode - 1].LeaveTangent * Diff*OneThird); const float P2 = P3 - (Keys[InterpNode].ArriveTangent * Diff*OneThird); InterpVal = BezierInterp(P0, P1, P2, P3, Alpha); } } else { InterpVal = Keys[InterpNode - 1].Value; } } else { // If beyond the last point in the curve, return its value. InterpVal = Keys[NumKeys - 1].Value; } return InterpVal; }