3d 贝塞尔三次曲线:以均匀加速度移动
假设我有一个3d 贝塞尔三次曲线:以均匀加速度移动,3d,numerical-methods,bezier,runge-kutta,3d,Numerical Methods,Bezier,Runge Kutta,假设我有一个B(u),如果我以恒定速率增加u参数,我不会获得沿曲线的共线速度运动,因为u参数和评估曲线获得的点之间的关系不是线性的 我已经阅读并实现了David Ebery的。它解释了如何沿参数曲线以恒定速度移动 假设我有一个函数F(t),它以时间值t作为输入,还有一个速度函数sigma,它返回时间t的速度值,我可以获得沿曲线的共时速度运动,以恒定速率改变t参数:B(F(t)) 我正在使用的文章的核心是以下函数: float umin, umax; // The curve parameter
B(u)
,如果我以恒定速率增加u
参数,我不会获得沿曲线的共线速度运动,因为u
参数和评估曲线获得的点之间的关系不是线性的
我已经阅读并实现了David Ebery的。它解释了如何沿参数曲线以恒定速度移动
假设我有一个函数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;
}
假设我想知道时间t=3时沿曲线的位置。
如果我是等速:
float sigma(float t)
{
return 1f;
}
以及以下数据:
V0 = 1;
V1 = 1;
t0 = 0;
L = 10;
V0 = 1;
V1 = 2;
t0 = 0;
L = 10;
我可以分析计算位置:
px = v0 * t = 1 * 3 = 3
如果我使用贝塞尔样条曲线和上述算法,用n=5
解同一个方程,我得到:
px = 3.002595;
考虑到数值近似,该值非常精确(我做了很多测试。我省略了细节,但Bezier我的曲线实现很好,并且曲线本身的长度是使用非常精确的方法计算的)
现在,如果我试图将西格玛定义为一个均匀的加速度函数,我会得到糟糕的结果。
考虑以下数据:
V0 = 1;
V1 = 1;
t0 = 0;
L = 10;
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
我拥有定义西格玛函数的所有数据:
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
提供适合您的需求和资源的价值
无论如何,如果你真的有一个足够精确的恒速参数化X(u(t)),那么你可以将这个“时间”参数t
重命名为“空间”(距离)参数s
,这样你真正拥有的是一个X(s),你只需要插入s(t)你需要:X(s(t))。在你的例子(恒定加速度)中,s(t)=s0+ut+at2/2,其中u和a很容易从你的输入数据中确定。我认为你只是在实现中没有显示的函数中的某个地方有一个拼写错误,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来得到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
我调试过很多类似的程序,只需打印出大量变量,然后手工计算每个值,并确保它们是相同的。对于t=6.6666,算法会给你什么?是数值10,即L,还是另一个?谢谢你提供的数据。我会试着做更多的实验。实际上我用的是3D贝塞尔曲线。我将用代码编辑帖子。