如何沿着Spline以CONSTANT速度移动对象?

时间:2016-12-07 06:38:55

标签: c# math unity3d bezier spline

我有一个样条曲线我可以沿着曲线以可变速度移动一个物体,但我想以恒定速度移动我该如何实现呢?

public static class SplineCurve {

public static Vector3 GetPoint (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
    t = Mathf.Clamp01(t);
    float oneMinusT = 1f - t;
    return
        oneMinusT * oneMinusT * oneMinusT * p0 +
        3f * oneMinusT * oneMinusT * t * p1 +
        3f * oneMinusT * t * t * p2 +
        t * t * t * p3;
}

public static Vector3 GetFirstDerivative (Vector3 p0, Vector3 p1, Vector3 p2, Vector3 p3, float t) {
    t = Mathf.Clamp01(t);
    float oneMinusT = 1f - t;
    return
        3f * oneMinusT * oneMinusT * (p1 - p0) +
        6f * oneMinusT * t * (p2 - p1) +
        3f * t * t * (p3 - p2);
}

}

我将恒定参数t发送到此曲线并获取该点,然后将对象移动到该点,但这给了我可变速度。我想以恒定的速度移动我的物体,我怎么能实现这个目标?

我能解决特定距离的任何等式吗?

B(t) = (1 - t)^3 * P0 + 3  * (1 - t)^2 * t * P1 + 3 * (1 - t) * t^2* P2 + t^3* P3

我用过这个等式

2 个答案:

答案 0 :(得分:2)

您正在寻找的是贝塞尔曲线的重新参数化,该参数化是按时间参数化的,而不是“时间t的曲线点”,您可以计算“曲线点”距离(或比率)d“。这实际上是一个非常困难的问题,它是迄今为止最有效的实现你正在为“计算机屏幕”工作:构建一个LUT(查找表)点,其中每个点记录x / y(/ z)以这种方式覆盖的曲线起点的坐标,时间值和线性距离,这样您就可以沿着曲线移动(而不是曲线在数学上精确) )基于具有简单功能的LUT:

getCoordinate(d):
  // get a known coordinate at, or before, distance 'd'
  s = findBefore(d)

  // get a known coordinate after distance 'd',
  // or 'false' if 'd' is actually a real LUT point
  e = findAfter(d)

  // if it was a real LUT point, we're done.
  if (e is false): return LUT[d]

  // if it wasn't, perform linear interpolation
  // between the known before/after coordinates,
  // and treat that as the coordinate-for-distance.
  return interpolate(d, e, s)

随着曲线上的距离单调增加,您可以通过写入距离的LUT 来让您的生活更轻松,因此LUT [0]是开始,LUT [len / 2]是曲线中途行走,LUT [len-1]结束。

要确保牢记的一件事是,为了正确使用它,您需要将曲线标记为两个长度:基于类似传奇的东西的真正的数学弧长-assass正交计算,以及此LUT的近似长度,基于您计算的坐标之间的所有线性距离的总和。您将第一个用于通用“告诉用户曲线长度”,但您使用 second 实际沿曲线移动东西。

(因为你沿着曲线移动东西,你沿着曲线的多边形近似移动东西,其中99.99%的时间正是你想要的)

此代码未指定findbeforefindafter函数,但有太多方法可以执行此操作 - 二进制搜索(i = len, v = len >> 1,检查LUT [iv];高于d => i -= v,低于d => i += v,修正v到v >> 1,重复直到v变为零,然后你找到了你的边界数组索引。

答案 1 :(得分:0)

不幸的是,Bezier曲线长度不能表示为闭合公式(它是椭圆积分)。但是对于移动你可能会忽略精度并使用一些简单的近似。

Arbitrary found example - “我做了什么”部分。

使用这种方法,您可以将曲线分成小段,为这些段获取长度并定义每个段的t变化速度。