假设我有一个贝塞尔曲线
我已经阅读并实现了David Eberly的文章。它解释了如何沿参数曲线以恒定速度移动。
假设我有一个函数
它允许我使用提供的时间t和sigma函数计算曲线参数u。如果sigma代表均匀加速度,那么该函数在速度sigma恒定时运行良好。但是,如果sigma表示均匀加速度,则从中获取错误值。
以下是一个例子,它是一条直线Bezier曲线,其中P0和P1是控制点,T0 T1是切线。该曲线定义如下:
我有所有数据来定义我的sigma函数:
如果我解析地求解,我期望在时间
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;
}
它允许我使用提供的时间t和sigma函数计算曲线参数u。如果sigma代表均匀加速度,那么该函数在速度sigma恒定时运行良好。但是,如果sigma表示均匀加速度,则从中获取错误值。
以下是一个例子,它是一条直线Bezier曲线,其中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
如果我使用我的贝塞尔样条和上述算法解决相同的方程,并且n=5
,我会得到:
px = 3.002595;
考虑数值逼近,该值相当精确(我进行了很多测试。我省略了细节,但是我的贝塞尔曲线实现很好,并且使用高斯积分计算曲线的长度非常准确)。
现在,如果我尝试将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
这与我所期望的非常不同。
对于这篇长文,如果有人耐心阅读,我会很高兴。
你有什么建议吗?我错过了什么?有人能告诉我我做错了什么吗?
编辑: 我正在尝试使用三维贝塞尔曲线。定义如下:
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;
}