/// <summary>
    /// Computes keyframe times to ensure a constant speed along the given spline.
    /// </summary>
    /// <remarks>
    /// If the speed is 0 or omitted, it will be auto-computed so the animation completes in 1s.
    /// </remarks>
    public static float[] ComputeSplineTimes(Vector3[] positions, float speed = 0f)
    {
        bool isUnitLength = (speed == 0f);
          if (isUnitLength)
        speed = 1f;

          int frameCount = positions.Length;
          float[] times = new float[frameCount];
          times[0] = 0f;

          if (frameCount < 4)
          {
          for (int i = 1; i < frameCount; ++i)
              times[i] = times[i - 1] + (positions[i] - positions[i - 1]).magnitude / speed;
          }
          else
          {
          times[1] = (positions[1] - positions[0]).magnitude / speed;

          int samplesPerSegment = 16;
          Vector3 oldPosition = positions[1];
          for (int j = 2; j < frameCount - 1; ++j)
          {
              SplineSegment segment = new SplineSegment(positions[j-2], positions[j-1], positions[j], positions[j+1]);
              float segmentLength = 0f;
              for (int i = 0; i < samplesPerSegment; ++i)
              {
                  float t = (float)i / (float)(samplesPerSegment - 1);
                  Vector3 position = segment.GetPosition(t);

                  segmentLength += (position - oldPosition).magnitude;

                  oldPosition = position;
              }

              times[j] = times[j-1] + segmentLength / speed;
          }

          float endDistance = (positions[frameCount - 1] - positions[frameCount - 2]).magnitude;
          times[frameCount - 1] = times[frameCount - 2] + endDistance / speed;
          }

          if (isUnitLength)
          {
        float totalTime = 0f;
        foreach (float time in times)
            totalTime += time;

        for (int i = 0; i < times.Length; ++i)
            times[i] /= totalTime;
          }

          return times;
    }