【问题标题】:How can i move an object along Spline with CONSTANT speed?如何以恒定的速度沿样条线移动对象?
【发布时间】:2017-04-22 00:18:34
【问题描述】:

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

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 发送到该曲线并获取该点,然后将对象移动到该点,但这给了我可变速度。我想以恒定的速度移动我的对象,我该如何实现?


是否有任何方程可以让我求解特定距离的 t?

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

我用过这个公式

【问题讨论】:

  • 因为您可以计算导数,所以将步长按因子 (desired speed)/(norm of derivative) 缩放。

标签: c# math unity3d bezier spline


【解决方案1】:

很遗憾,贝塞尔曲线的长度不能用封闭公式表示(它是椭圆积分)。但是对于移动,您可能会忽略精度并使用一些简单的近似值。

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

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

【讨论】:

  • 你甚至不需要分割,你只需要以足够接近的间隔对曲线进行采样,然后在每个采样点之间使用线性插值(pomax.github.io/bezierinfo/#tracing
【解决方案2】:

您正在寻找的是贝塞尔曲线的重新参数化,它是按时间参数化的,而不是距离,因此您可以计算“距离曲线点 (或比率)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)

随着沿曲线的距离单调增加,您可以通过编写 LUTkeyed on distance 让您的生活变得轻松,因此 LUT[0] 是开始,LUT[len/2] 是曲线经过中途,LUT[len-1] 是终点。

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

(因为您没有沿着曲线移动物体,所以您正在沿着曲线的多边形近似移动物体,这在 99.99% 的情况下正是您想要的)

这段代码没有指定findbeforefindafter函数,但是这样做的方法太多了——二分查找(i = len, v = len >> 1,检查LUT[iv];高于d=>@ 987654328@,低于d => i += v,通过v >> 1 修复v,重复直到v 变为零并且您找到了边界数组索引。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多