public static void RepositionKeyframesForConstantSpeed(SpherePointKeyframeGroup group)
        {
            if (group.GetKeyFrameCount() < 2)
            {
                return;
            }

            // Because time is always 1, no need to divide by it.
            float totalDistance = GetTotalDistanceBetweenKeyframes(group);
            float targetSpeed   = totalDistance;

            int keyFrameCount = group.GetKeyFrameCount();

            for (int j = 0; j < keyFrameCount; j++)
            {
                for (int i = keyFrameCount - 2; i >= 0; i--)
                {
                    int nextIndex = i + 1;
                    SpherePointKeyframe keyframe     = group.keyframes[i];
                    SpherePointKeyframe nextKeyframe = group.keyframes[nextIndex];

                    MoveKeyframeTimeToMatchSpeed(keyframe, nextKeyframe, targetSpeed);
                }

                // This is a hack, we resort and re-calculated edges since durations were changed.
                group.SortKeyframes();
            }
        }
        public static float GetTotalDistanceBetweenKeyframes(SpherePointKeyframeGroup group)
        {
            float total = 0;

            for (int i = 0; i < group.GetKeyFrameCount(); i++)
            {
                int nextIndex = (i + 1) % group.GetKeyFrameCount();
                SpherePointKeyframe currentKeyframe = group.keyframes[i];
                SpherePointKeyframe nextKeyframe    = group.keyframes[nextIndex];

                total += GetDistanceBetweenKeyframes(currentKeyframe, nextKeyframe);
            }
            return(total);
        }
        // Color based on last edge speed.
        public static List <Vector4> GenerateColorSpeedPoints(SpherePointKeyframeGroup group)
        {
            List <Vector4> colorPoints = new List <Vector4>();

            if (group.GetKeyFrameCount() <= 1)
            {
                colorPoints.Add(new Vector4(0.0f, m_AvgColor.r, m_AvgColor.g, m_AvgColor.b));
                colorPoints.Add(new Vector4(1.0f, m_AvgColor.r, m_AvgColor.g, m_AvgColor.b));
                return(colorPoints);
            }

            float       gradientOffset = .02f;
            const float maxSpeed       = 1200.0f;

            for (int i = 0; i < group.keyframes.Count; i++)
            {
                int nextIndex = (i + 1) % group.GetKeyFrameCount();
                SpherePointKeyframe currentKeyframe = group.keyframes[i];
                SpherePointKeyframe nextKeyframe    = group.keyframes[nextIndex];

                // Last keyframe has special rules
                if (i == group.keyframes.Count - 1)
                {
                    float speed      = GetSpeedBetweenKeyframes(currentKeyframe, nextKeyframe);
                    Color speedColor = Color.Lerp(m_AvgColor, m_MaxColor, speed / maxSpeed);

                    float gradientBeginTime = currentKeyframe.time + gradientOffset;
                    float gradientEndTime   = 1.0f;

                    if (gradientBeginTime >= 1.0f)
                    {
                        gradientBeginTime = currentKeyframe.time;
                    }

                    colorPoints.Add(
                        new Vector4(gradientBeginTime, speedColor.r, speedColor.g, speedColor.b));
                    colorPoints.Add(
                        new Vector4(gradientEndTime, speedColor.r, speedColor.g, speedColor.b));

                    // Now bridge gap if any to first keyframe.
                    if (!SkyEditorUtility.IsKeyFrameAtStart(nextKeyframe))
                    {
                        gradientBeginTime = 0.0f;
                        gradientEndTime   = nextKeyframe.time - gradientOffset;
                        if (gradientEndTime < 0)
                        {
                            gradientEndTime = nextKeyframe.time;
                        }

                        colorPoints.Insert(0,
                                           new Vector4(gradientEndTime, speedColor.r, speedColor.g, speedColor.b));
                        colorPoints.Insert(0,
                                           new Vector4(gradientBeginTime, speedColor.r, speedColor.g, speedColor.b));
                    }
                    else
                    {
                        colorPoints.Insert(
                            0,
                            new Vector4(0, speedColor.r, speedColor.g, speedColor.b));
                    }
                }
                else
                {
                    float gradientBeginTime = currentKeyframe.time + gradientOffset;
                    float gradientEndTime   = nextKeyframe.time - gradientOffset;

                    // Need to play with these to see how they look. Maybe use a percentage between them instead?
                    if (gradientBeginTime >= nextKeyframe.time)
                    {
                        gradientBeginTime = currentKeyframe.time;
                    }

                    if (gradientEndTime <= currentKeyframe.time)
                    {
                        gradientEndTime = nextKeyframe.time;
                    }


                    float speed      = GetSpeedBetweenKeyframes(currentKeyframe, nextKeyframe);
                    Color speedColor = Color.Lerp(m_AvgColor, m_MaxColor, speed / maxSpeed);

                    colorPoints.Add(
                        new Vector4(gradientBeginTime, speedColor.r, speedColor.g, speedColor.b));
                    colorPoints.Add(
                        new Vector4(gradientEndTime, speedColor.r, speedColor.g, speedColor.b));
                }
            }

            return(colorPoints);
        }