以相对于弧长的恒定速度评估函数

Evaluate function at constant speed relative to arc length

我正在实现一个实时图形引擎 (C++ / OpenGL),它可以随着时间的推移沿着由多项式函数描述的指定路线移动车辆。该函数本身是在应用程序外部以编程方式生成的,并且是高阶的(我相信 >25),所以我不能在这里 post 它(无论如何我认为这不重要)。在运行时函数不会改变,因此很容易计算一次和二阶导数,以便以后快速使用它们。

我的问题是我必须以恒定速度(比如每秒 10 个单位)沿着曲线移动,所以我的函数参数不直接等于时间,因为两点 x1 和 x2 之间的弧长因函数值而异。例如,f(a+1) - f(a) 的差值可能远大于或小于 f(b+1) - f(b),具体取决于函数如何查看点 a 和 b。

我不需要 100% 准确的解决方案,因为运动只是视觉上的,不会进一步处理,所以任何近似值都可以。另外请记住,整个事情必须在运行时每帧 (60fps) 计算,因此根据计算时间,用复杂的数学求解大型方程可能是不可能的。

我有点不知道从哪里开始,所以即使是任何思路都会受到高度赞赏!

给定恒定速度和帧间时间,可以计算帧间所需的弧长。所以下面的函数应该可以完成这项工作:

#include <cmath>
typedef double (*Function)(double);

double moveOnArc(Function f, const double xStart, const double desiredArcLength, const double dx = 1e-2)
{
  double arcLength = 0.;
  double fPrev = f(xStart);
  double x = xStart;
  double dx2 = dx*dx;
  while (arcLength < desiredArcLength)
  {
    x += dx;
    double fx = f(x);
    double dfx = fx - fPrev;
    arcLength += sqrt(dx2 + dfx*dfx);
    fPrev = fx;
  }
  return x;
}

既然您说准确性不是首要标准,那么选择一个合适的 dx 上述功能可能会立即起作用。当然,它可以通过自动调整 dx(例如基于二阶导数)或通过二分搜索优化端点来改进。

由于标准不是要有一个精确的解决方案,而是要有一个视觉上吸引人的近似值,因此有多种可能的解决方案可供尝试。


我实现的 first 方法(由 Alnitak 在评论中建议,后来由 coproc 回答),它通过微小的迭代来近似实际的弧长积分。这个版本在大多数时候都工作得很好,但在非常陡峭的角度上并不可靠,并且在平坦角度上使用了太多的迭代。正如 coproc 在答案中已经指出的那样,一个可能的解决方案是将 dx 基于二阶导数。

可以进行所有这些调整,但是,我需要一个运行时友好的算法。有了这个很难预测迭代次数,这就是我不满意的原因。


second 方法(也受到 Alnitak 的启发)利用 "pushing" 车辆沿计算斜率的一阶导数(等于当前 x 值)。计算下一个 x 值的函数非常紧凑和快速。视觉上没有明显的不准确,结果始终一致。 (这就是我选择它的原因)

float current_x = ...; //stores current x
float f(x) {...}
float f_derv(x) {...}

void calc_next_x(float units_per_second, float time_delta) {
  float arc_length = units_per_second * time_delta;
  float derv_squared = f_derv(current_x) * f_derv(current_x);
  current_x += arc_length / sqrt(derv_squared + 1);
}

然而,这种方法可能只对高帧时间的情况足够准确(我的是 >60fps),因为物体将始终沿着直线推动,其长度取决于所述帧时间。