Beispiel #1
0
        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);
        }
Beispiel #2
0
 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);
 }
Beispiel #3
0
        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);
        }