Diciamo ho un Bezier curveB(u)
, se Incremento u
parametro a una velocità costante non ottengo un movimento velocità costante lungo la curva, perché il rapporto tra u
parametro e il punto ottenuto valutando la curva non è lineare.Bezier curve cubiche: muove con accelerazione uniforme
Ho letto e implementato il article di David Eberly. Spiega come muoversi a velocità costante lungo una curva parametrica.
Supponiamo Ho una funzione F(t)
che prende in ingresso un valore di tempo t
e una funzione di velocità sigma
che restituisce il valore della velocità al momento t
, che possono ottenere un movimento velocità costante lungo la curva, parametro che varia t a velocità costante : B(F(t))
il nucleo di questo articolo che sto utilizzando è il seguente funzione:
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;
}
mi permette di ottenere il parametro della curva u
calcolato usando il tempo in dotazione t
e funzione sigma. Ora la funzione funziona correttamente quando la sigma della velocità è costante. Se sigma rappresenta un'accelerazione uniforme, ricevo valori sbagliati.
Ecco un esempio di curva lineare di Bézier, dove P0 e P1 sono i punti di controllo, T0 T1 la tangente. La curva è definita:
[x,y,z]= B(u) =(1–u)3P0 + 3(1–u)2uT0 + 3(1–u)u2T1 + u3P2
Diciamo che voglio conoscere la posizione lungo la curva al momento t = 3
. Se una velocità costante:
float sigma(float t)
{
return 1f;
}
ed i seguenti dati:
V0 = 1;
V1 = 1;
t0 = 0;
L = 10;
posso analiticamente calcolare la posizione:
px = v0 * t = 1 * 3 = 3
Se risolvere la stessa equazione utilizzando la spline Bezier e l'algoritmo sopra con n =5
ottengo:
px = 3.002595;
Considerando l'approssimazione numerica il valore è abbastanza preciso (ho fatto un sacco di test su questo. Tralascio i dettagli ma Bezier l'implementazione delle mie curve va bene e la lunghezza della curva è calcolata in modo abbastanza preciso usando Gaussian Quadrature).
Ora se provo a definire sigma come funzione di accelerazione uniforme, ottengo risultati negativi. consideri i seguenti dati:
V0 = 1;
V1 = 2;
t0 = 0;
L = 10;
posso calcolare il tempo una particella raggiungerà P1 utilizzando le equazioni di movimento lineare:
L = 0.5 * (V0 + V1) * t1 =>
t1 = 2 * L/(V1 + V0) = 2 * 10/3 = 6.6666666
Avendo t
posso calcolare l'accelerazione:
a = (V1 - V0)/(t1 - t0) = (2 - 1)/6.6666666 = 0.15
Ho tutti i dati per definire la mia funzione sigma:
float sigma (float t)
{
float speed = V0 + a * t;
}
Se analiticamente risolvere questo mi aspetto le seguenti velocità di una particella dopo il tempo t =3
:
Vx = V0 + a * t = 1 + 0.15 * 3 = 1.45
e la posizione sarà:
px = 0.5 * (V0 + Vx) * t = 0.5 * (1 + 1.45) * 3 = 3.675
Ma se calcolarlo con il Aloritmo sopra, i risultati di posizione:
px = 4.358587
che è abbastanza diverso da om che cosa mi aspetto
Scusate per il post lungo, se qualcuno ha abbastanza pazienza per leggerlo, sarei felice.
Avete qualche suggerimento? Cosa mi sto perdendo? Qualcuno può dirmi cosa sto facendo male?
EDIT: Sto cercando con curva di Bezier 3D. Definito in questo modo:
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;
}
e la derivata:
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;
}
e cosa ti dà l'algoritmo per t = 6.6666 ...? È il valore 10, cioè L o un altro? – lmsteffan