Hei*_*bug 12 3d bezier numerical-methods runge-kutta
假设我有一个贝塞尔曲线 B(u),如果我u以恒定速率增加参数,我不会沿着曲线获得恒定的速度运动,因为u参数和评估曲线的点之间的关系不是线性的.
我已阅读并实施了David Eberly的文章.它解释了如何沿参数曲线以恒定速度移动.
假设我有一个函数F(t),它将时间值t和速度函数作为输入,在时间sigma返回速度值t,我可以获得沿曲线的恒定速度运动,以恒定速率改变t参数:B(F(t))
我正在使用的文章的核心是以下功能:
float umin, umax; // The curve parameter interval [umin,umax].
Point Y (float u); // The position Y(u), umin <= u <= umax.
Point DY (float u); // The derivative dY(u)/du, umin <= u <= umax.
float LengthDY (float u) { return Length(DY(u)); }
float ArcLength (float t) { return Integral(umin,u,LengthDY()); }
float L = ArcLength(umax); // The total length of the curve.
float tmin, tmax; // The user-specified time interval [tmin,tmax]
float Sigma (float t); // The user-specified speed at time t.
float GetU (float t) // tmin <= t <= tmax
{
  float h = (t - tmin)/n; // step size, `n' is application-specified
  float u = umin; // initial condition
  t = tmin; // initial condition
  for (int i = 1; i <= n; i++)
  {
    // The divisions here might be a problem if the divisors are
    // nearly zero.
    float k1 = h*Sigma(t)/LengthDY(u);
    float k2 = h*Sigma(t + h/2)/LengthDY(u + k1/2);
    float k3 = h*Sigma(t + h/2)/LengthDY(u + k2/2);
    float k4 = h*Sigma(t + h)/LengthDY(u + k3);
    t += h;
    u += (k1 + 2*(k2 + k3) + k4)/6;
  }
  return u;
}
它允许我u使用提供的时间t和西格玛函数计算曲线参数.现在,当速度西格玛是常数时,该功能正常工作.如果sigma代表一个统一的加速,我会从中得到错误的值.
这是一个直线贝塞尔曲线的例子,其中P0和P1是控制点,T0 T1是切线.曲线的定义:
[x,y,z]= B(u) =(1–u)3P0 + 3(1–u)2uT0 + 3(1–u)u2T1 + u3P2 

假设我想知道曲线上的位置t = 3.如果我是一个恒定的速度:
float sigma(float t)
{
  return 1f;
}
以及以下数据:
V0 = 1;
V1 = 1;
t0 = 0;
L = 10;
我可以通过分析计算位置:
px = v0 * t = 1 * 3 = 3
如果我使用我的Bezier样条和上面的算法求解相同的方程,n =5我得到:
px = 3.002595;
考虑到数值近似,这个值非常精确(我做了很多测试.我省略了细节,但Bezier我的曲线实现很好,曲线本身的长度使用高斯求积法非常精确地计算).
现在,如果我尝试将sigma定义为一个统一的加速函数,我会得到不好的结果.请考虑以下数据:
V0 = 1;
V1 = 2;
t0 = 0;
L = 10;
我可以使用线性运动方程计算粒子到达P1的时间:
L = 0.5 * (V0 + V1) * t1 =>
t1 = 2 * L / (V1 + V0) = 2 * 10 / 3 = 6.6666666
有t我可以计算加速度:
a = (V1 - V0) / (t1 - t0) = (2 - 1) / 6.6666666  = 0.15
我有所有数据来定义我的sigma函数:
float sigma (float t)
{
  float speed = V0 + a * t;
}
如果我在解剖学上解决这个问题,我会期待粒子的跟随速度t =3:
Vx = V0 + a * t = 1 + 0.15 * 3 = 1.45
并且职位将是:
px = 0.5 * (V0 + Vx) * t = 0.5 * (1 + 1.45) * 3 = 3.675
但如果我用上面的算法计算它,那么位置会产生:
px = 4.358587
这与我的期望完全不同.
对于这篇长篇文章感到抱歉,如果有人有足够的耐心阅读它,我会很高兴的.
你有什么建议吗?我错过了什么?谁能告诉我我做错了什么?
编辑:我正在尝试使用3D贝塞尔曲线.这样定义:
public Vector3 Bezier(float t)
{
    float a = 1f - t;
    float a_2 = a * a;
    float a_3 = a_2 *a;
    float t_2 = t * t;
    Vector3 point = (P0 * a_3) + (3f * a_2 * t * T0) + (3f * a * t_2 * T1) + t_2 * t * P1 ;
    return point;
}
和衍生物:
public Vector3 Derivative(float t)
{
    float a = 1f - t;
    float a_2 = a * a;
    float t_2 = t * t;
    float t6 = 6f*t;
    Vector3 der = -3f * a_2 * P0 + 3f * a_2 * T0 - t6 * a * T0 - 3f* t_2 * T1 + t6 * a * T1 + 3f * t_2 * P1;
    return der;
}
我的猜测是,这n=5根本无法为您提供足够的精度来解决当前的问题。事实上,它适用于恒定速度情况并不意味着它也适用于恒定加速度情况。不幸的是,您必须自己定义一个折衷方案,以提供n适合您的需求和资源的价值。
无论如何,如果你确实有一个具有足够精度的恒速参数化Xt (u(t)),那么你可以将这个“时间”参数重命名为“空间”(距离)参数s,这样你真正拥有的是一个X (s),您只需代入您需要的 s(t):X (s(t))。在您的情况(恒定加速度)中,s(t) = s 0 + ut + at 2 / 2,其中 u 和 a 可以根据您的输入数据轻松确定。