Bezier Cubic Curves:以均匀的加速度移动

时间:2013-03-06 18:13:20

标签: 3d numerical-methods bezier runge-kutta

假设我有一个Bezier curve B(u),如果我以恒定速率递增u参数,我不会沿着曲线获得恒定的速度移动,因为{之间的关系{1}}参数和评估曲线得到的点不是线性的。

我已阅读并实施了David Eberly的article。它解释了如何沿参数曲线以恒定速度移动。

假设我有一个函数u,它将时间值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; } 和sigma函数获取计算的曲线参数u。 现在,当速度西格玛是常数时,该功能正常工作。如果sigma代表一个统一的加速,我会从中得到错误的值。

这是一个直线贝塞尔曲线的例子,其中P0和P1是控制点,T0 T1是切线。曲线的定义:

t

enter image description here

假设我想知道[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;

如果我使用我的Bezier样条和上面的算法px = v0 * t = 1 * 3 = 3 求解相同的等式,我得到:

n =5

考虑到数值近似,这个值非常精确(我做了很多测试。我省略了细节,但Bezier我的曲线实现很好,曲线本身的长度使用Gaussian Quadrature非常精确地计算)。

现在如果我尝试将sigma定义为一个统一的加速函数,我会得到不好的结果。 请考虑以下数据:

px = 3.002595;

我可以使用线性运动方程计算粒子到达P1的时间:

V0 = 1;
V1 = 2;
t0 = 0;
L = 10;

L = 0.5 * (V0 + V1) * t1 => t1 = 2 * L / (V1 + V0) = 2 * 10 / 3 = 6.6666666 我可以计算加速度:

t

我有所有数据来定义我的sigma函数:

a = (V1 - V0) / (t1 - t0) = (2 - 1) / 6.6666666  = 0.15

如果我在分析上解决这个问题,我会期望粒子在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

与我期待的完全不同。

很抱歉这篇长篇文章,如果有人有足够的耐心阅读它,我会很高兴。

你有什么建议吗?我错过了什么?谁能告诉我我做错了什么?


编辑: 我正在尝试使用3D贝塞尔曲线。这样定义:

px = 4.358587

和衍生物:

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;
}

2 个答案:

答案 0 :(得分:1)

我的猜测是n=5根本无法为您手头的问题提供足够的精确度。对于恒速情况来说这是可以的事实并不意味着它也适用于恒定加速情况。不幸的是,您必须自己定义折衷方案,为您提供符合您需求和资源的n价值。

无论如何,如果你真的有一个恒定速度参数化 X (u(t)),它具有足够的精度,那么你可以将这个“时间”参数t重命名为“空格” “(距离)参数s,所以你真正拥有的是 X (s),你只需要插入你需要的s(t): X (S(t))的。在你的情况下(恒定加速度),s(t)= s 0 + ut + at 2 / 2,其中u和a很容易根据输入数据确定。< / p>

答案 1 :(得分:1)

我认为你在实现中没有显示的函数Y和DY中只有一个拼写错误。我尝试了一维曲线,P0 = 0,T0 = 1,T1 = 9,P1 = 10,得到3.6963165,n = 5,n = 30时提高到3.675044,n = 100时提高到3.6750002。

如果您的实现是二维的,请尝试使用P0 =(0,0),T0 =(1,0),T1 =(9,0)和P1 =(10,0)。然后再次尝试P0 =(0,0),T0 =(0,1),T1 =(0,9),P1 =(0,10)。

如果你正在使用C,请记住^运算符并不意味着指数。你必须使用pow(u,3)或u * u * u来获得你的立方体。

尝试在每次迭代中打印出尽可能多的东西的值。这就是我得到的:

i=1
    h=0.6
    t=0.0
    u=0.0
    LengthDY(u)=3.0
    sigma(t)=1.0
    k1=0.2
    sigma(t+h/2)=1.045
    LengthDY(u+k1/2)=6.78
    k2=0.09247787
    LengthDY(u+k2/2)=4.8522377
    k3=0.12921873
    sigma(t+h)=1.09
    LengthDY(u+k3)=7.7258916
    k4=0.08465043
    t_new=0.6
    u_new=0.12134061
i=2
    h=0.6
    t=0.6
    u=0.12134061
    LengthDY(u)=7.4779167
    sigma(t)=1.09
    k1=0.08745752
    sigma(t+h/2)=1.135
    LengthDY(u+k1/2)=8.788503
    k2=0.0774876
    LengthDY(u+k2/2)=8.64721
    k3=0.078753725
    sigma(t+h)=1.1800001
    LengthDY(u+k3)=9.722377
    k4=0.07282171
    t_new=1.2
    u_new=0.20013426
i=3
    h=0.6
    t=1.2
    u=0.20013426
    LengthDY(u)=9.723383
    sigma(t)=1.1800001
    k1=0.072814174
    sigma(t+h/2)=1.225
    LengthDY(u+k1/2)=10.584761
    k2=0.069439456
    LengthDY(u+k2/2)=10.547299
    k3=0.069686085
    sigma(t+h)=1.27
    LengthDY(u+k3)=11.274727
    k4=0.06758479
    t_new=1.8000001
    u_new=0.26990926
i=4
    h=0.6
    t=1.8000001
    u=0.26990926
    LengthDY(u)=11.276448
    sigma(t)=1.27
    k1=0.06757447
    sigma(t+h/2)=1.315
    LengthDY(u+k1/2)=11.881528
    k2=0.06640561
    LengthDY(u+k2/2)=11.871877
    k3=0.066459596
    sigma(t+h)=1.36
    LengthDY(u+k3)=12.375444
    k4=0.06593703
    t_new=2.4
    u_new=0.3364496
i=5
    h=0.6
    t=2.4
    u=0.3364496
    LengthDY(u)=12.376553
    sigma(t)=1.36
    k1=0.06593113
    sigma(t+h/2)=1.405
    LengthDY(u+k1/2)=12.7838
    k2=0.06594283
    LengthDY(u+k2/2)=12.783864
    k3=0.0659425
    sigma(t+h)=1.45
    LengthDY(u+k3)=13.0998535
    k4=0.06641296
    t_new=3.0
    u_new=0.4024687

我通过打印出大量变量,然后手动计算每个值,并确保它们是相同的,调试了许多这样的程序。