private float EvalForTwoKeys(FRichCurveKey key1, FRichCurveKey key2, float inTime) { var diff = key2.Time - key1.Time; if (diff > 0f && key1.InterpMode != RCIM_Constant) { var alpha = (inTime - key1.Time) / diff; var p0 = key1.Value; var p3 = key2.Value; if (key1.InterpMode == RCIM_Linear) { return(MathUtils.Lerp(p0, p3, alpha)); } if (IsItNotWeighted(key1, key2)) { const float oneThird = 1f / 3f; var p1 = p0 + key1.LeaveTangent * diff * oneThird; var p2 = p3 - key2.ArriveTangent * diff * oneThird; return(BezierInterp(p0, p1, p2, p3, alpha)); } // it's weighted return(WeightedEvalForTwoKeys(key1, key2, inTime)); } return(key1.Value); }
private static bool IsItNotWeighted(FRichCurveKey key1, FRichCurveKey key2) { return(key1.TangentWeightMode is RCTWM_WeightedNone or RCTWM_WeightedArrive && key2.TangentWeightMode is RCTWM_WeightedNone or RCTWM_WeightedLeave); }
private float WeightedEvalForTwoKeys(FRichCurveKey key1, FRichCurveKey key2, float inTime) { var diff = key2.Time - key1.Time; var alpha = (inTime - key1.Time) / diff; var p0 = key1.Value; var p3 = key2.Value; var oneThird = 1f / 3f; var time1 = key1.Time; var time2 = key2.Time; var x = time2 - time1; var angle = Math.Atan(key1.LeaveTangent); var cosAngle = Math.Cos(angle); var sinAngle = Math.Sin(angle); double leaveWeight = key1.LeaveTangentWeight; if (key1.TangentWeightMode is RCTWM_WeightedNone or RCTWM_WeightedArrive) { var leaveTangentNormalized = key1.LeaveTangent; var y = leaveTangentNormalized * x; leaveWeight = Math.Sqrt(x * x + y * y) * oneThird; } var key1TanX = cosAngle * leaveWeight + time1; var key1TanY = sinAngle * leaveWeight + key1.Value; angle = Math.Atan(key2.ArriveTangent); cosAngle = Math.Cos(angle); sinAngle = Math.Cos(angle); double arriveWeight = key2.ArriveTangentWeight; if (key2.TangentWeightMode is RCTWM_WeightedNone or RCTWM_WeightedLeave) { var arriveTangentNormalized = key2.ArriveTangent; var y = arriveTangentNormalized * x; arriveWeight = Math.Sqrt(x * x + y * y) * oneThird; } var key2TanX = -cosAngle * arriveWeight + time2; var key2TanY = -sinAngle * arriveWeight + key2.Value; // Normalize the time range var rangeX = time2 - time1; var dx1 = key1TanX - time1; var dx2 = key2TanX - time1; // Normalize values var normalizedX1 = dx1 / rangeX; var normalizedX2 = dx2 / rangeX; var results = new double[3]; BezierToPower(0.0, normalizedX1, normalizedX2, 1.0, out double[] coeff); coeff[0] -= alpha; var numResults = CubicCurve2D.SolveCubic(ref coeff, ref results); float newInterp; if (numResults == 1) { newInterp = (float)results[0]; } else { newInterp = float.MinValue; foreach (var result in results) { if (result is >= 0.0f and <= 1.0f) { if (newInterp < 0.0f || result > newInterp) { newInterp = (float)result; } } } if (newInterp == float.MinValue) { newInterp = 0f; } } var outVal = BezierInterp(p0, (float)key1TanY, (float)key2TanY, p3, newInterp); return(outVal); }