以相对于弧长的恒定速度评估功能

时间:2017-11-02 09:41:39

标签: function math polynomial-math

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

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

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

我有点迷失在哪里开始,所以即使是任何思路都会受到高度赞赏!

2 个答案:

答案 0 :(得分:0)

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

#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(例如基于二阶导数)或通过二进制搜索优化端点来改进。

答案 1 :(得分:0)

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

第一个方法(由Alnitak在评论中提出,后来由coproc回答)我实现了,它通过微小的迭代逼近实际的arclength积分。这个版本在大多数情况下工作得非常好,但是在非常陡峭的角度下并不可靠,并且在平面角度下使用了太多的迭代。正如coproc在答案中已经指出的那样,一个可能的解决方案是将dx建立在二阶导数上。

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

第二方法(也受到Alnitak的启发)正在利用&#34;推动&#34;沿计算斜率的车辆(等于当前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)的情况而言足够准确,因为对象总是沿着具有取决于所述帧时间的长度的直线被推动。