/// <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; }