我正在可视化一级方程式比赛中赛车提供的 GPS 数据,并试图为它们在路径上的位置设置动画。 Formula 1 API 提供矢量坐标和时间戳,但时间戳各不相同:它们大约在 100 到 400 毫秒之间更新:
timestamp x y z
2023-03-19 18:23:39.562 -1396 503 118
2023-03-19 18:23:39.842 -1443 630 118
2023-03-19 18:23:40.142 -1531 868 117
2023-03-19 18:23:40.342 -1589 1028 117
2023-03-19 18:23:40.501 -1636 1157 117
2023-03-19 18:23:40.842 -1772 1527 117
2023-03-19 18:23:41.101 -1813 1640 117
2023-03-19 18:23:41.361 -1932 1964 117
2023-03-19 18:23:41.782 -2015 2190 117
2023-03-19 18:23:42.002 -2080 2368 117
...
可视化数据点如下所示:
我正在使用协程在向量之间进行 Lerp 并更新时间增量,但由于间隙不同,它会产生相当不稳定的动画:
我的协程看起来像这样(感谢@derHugo 这个答案):
private IEnumerator AnimationRoutine()
{
if (alreadyAnimating) yield break;
alreadyAnimating = true;
var lastSample = _samples[0];
Car.transform.position = lastSample.Position;
yield return null;
for (var i = 1; i < _samples.Count; i++)
{
var lastPosition = lastSample.Position;
var currentSample = _samples[i];
var targetPosition = currentSample.Position;
var duration = currentSample.TimeDelta;
var timePassed = 0f;
while (timePassed < duration)
{
var factor = timePassed / duration;
Car.transform.position = Vector3.Lerp(lastPosition, targetPosition, factor);
yield return null;
timePassed += Time.deltaTime;
}
Car.transform.position = targetPosition;
lastSample = currentSample;
}
alreadyAnimating = false;
}
有没有一种方法可以维护我拥有的时间数据,但对点之间的过渡进行插值,使它们看起来更平滑?
你计算物体在两点之间的平均速度并相应地移动球体而不是加速度。您需要跟踪球体的速度,以便在两点之间应用线性加速度。将加速度累积到球体的速度中,并随着时间的推移将该速度应用到它的位置应该会减少它的波动。
要计算平均加速度,您需要将 B 点的速度减去 A 点的速度除以距离:
(v2 - v1) / d
。要知道球体到达 B 点时的速度,它只是随时间变化的距离。
这里发生的事情是点集只定义了汽车的路径而不是汽车的速度。您将需要额外的信息来了解汽车在一圈内的速度。除了空间遥测之外,这还需要时间遥测。
理想情况下,您采用一组(x,y,z)点和对应的时间(t)并定义一个空间三次样条曲线,允许您在节点之间进行插值。
Vector3.Lerp
在这里是不够的,因为坡度在节点处不匹配,你将有不连续的速度。
样条参数化了一些参数
t = 0 .. t_lap
描述汽车沿着一圈的位置
float[] t_data, float[] x_data, float[] y_data, float[] z_data;
...
Spline spline_x = new Spline(t_data, x_data);
Spline spline_y = new Spline(t_data, y_data);
Spline spline_z = new Spline(t_data, z_data);
for( int i=0; i<spline.Count; i++)
{
float t = (t_end/(spline.Count-1))*i;
posVector = new Vector(
spline_x.Value(t),
spline_y.Value(t),
spline_z.Value(t));
// draw position Vector
}
你可以找到很多在线帖子关于 C# 中的三次样条甚至我自己在 Fortan 中的例子
如果你的问题是你没有时间遥测,如果你可以通过假设沿着轨道的某种速度分布(比如常数,这是不现实的)来弥补它,那么这是一个不同的数学问题。
您需要节点之间的总行进距离(样条曲线的长度),它总是大于
Vector3.Distance()
给出的直线段。
这个距离是用每个距离段的数值积分器评估的
Δs
,它对应于一个小的时间步长Δt
使用样条斜率(速度)函数
float speed_x = spline_x.Slope(t);
float speed_y = spline_y.Slope(t);
float speed_z = spline_z.Slope(t);
float speed = Math.SqrtF( speed_x*speed_x + speed_y*speed_y + speed_z*speed_z);
float distInterval = Δt / speed;
完整的数学处理相当复杂,所以我不确定你是否想沿着这条路走下去,你在这里只需快速估计就足够了。
我在这里找到了一个类似的我的答案关于在 3D 飞机数据之间平滑插值。
[Math.NET] Spline
对象你可以使用。