Powiedzmy mam Bezier curveB(u)
, jeśli przyrost u
parametr w stałym tempie nie uzyskania prędkości przepływu costant wzdłuż krzywej, ponieważ relacja między u
parametru a punktem otrzymana ocena krzywej nie jest liniowa.Beziera Cubic Krzywe: przeniesienie z jednolitego przyspieszenie
Przeczytałem i zaimplementowałem wersję Davida Eberly'ego article. Wyjaśnia, jak poruszać się ze stałą prędkością wzdłuż krzywej parametrycznej.
Załóżmy, że pełnią funkcję F(t)
którego wprowadzany wartość czasu t
i funkcją prędkości sigma
, która zwraca wartość prędkości w czasie t
, można uzyskać prędkości przepływu costant wzdłuż krzywej różnych t parametr ze stałą szybkością : B(F(t))
trzon artykule używam jest następująca funkcja:
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;
}
to pozwala mi uzyskać krzywą u
obliczoną z użyciem czasu dostarczonego t
i funkcja sigma. Teraz funkcja działa poprawnie, gdy sigma prędkości jest kosztowna. Jeśli sigma reprezentuje jednolity accelartion, otrzymuję z niego błędne wartości.
Oto przykład prostej krzywej Beziera, gdzie P0 i P1 są punktami kontrolnymi, T0 T1 styczną. Krzywa zdefiniowana:
[x,y,z]= B(u) =(1–u)3P0 + 3(1–u)2uT0 + 3(1–u)u2T1 + u3P2
Powiedzmy chcę wiedzieć pozycję wzdłuż krzywej w czasie t = 3
. Jeśli I stałą prędkość:
float sigma(float t)
{
return 1f;
}
oraz następujące dane:
V0 = 1;
V1 = 1;
t0 = 0;
L = 10;
mogę analitycznie obliczenia pozycji:
px = v0 * t = 1 * 3 = 3
Gdybym rozwiązania tego samego równania, używając mojego Beziera splajn a powyższy algorytm z n =5
otrzymuję:
px = 3.002595;
Biorąc pod uwagę numeryczne przybliżenie, wartość jest dość dokładna (wykonałem na nim wiele testów. Pomijam szczegóły, ale Beziera, moja implementacja krzywych jest w porządku, a długość samej krzywej obliczana jest dość dokładnie przy użyciu Gaussian Quadrature).
Teraz Jeśli spróbuję zdefiniować sigmę jako jednolitą funkcję przyspieszenia, otrzymam złe wyniki. rozważyć następujące dane:
V0 = 1;
V1 = 2;
t0 = 0;
L = 10;
można obliczyć czas cząstka osiągnie P1 stosując liniowe równanie ruchu:
L = 0.5 * (V0 + V1) * t1 =>
t1 = 2 * L/(V1 + V0) = 2 * 10/3 = 6.6666666
Having t
można obliczyć przyspieszeniu
a = (V1 - V0)/(t1 - t0) = (2 - 1)/6.6666666 = 0.15
Mam wszystkie dane do zdefiniowania mojej funkcji sigma:
float sigma (float t)
{
float speed = V0 + a * t;
}
Gdybym analitycznie rozwiązać ten Spodziewam następujące prędkości cząstki po raz t =3
:
Vx = V0 + a * t = 1 + 0.15 * 3 = 1.45
i pozycja będzie:
px = 0.5 * (V0 + Vx) * t = 0.5 * (1 + 1.45) * 3 = 3.675
Ale gdybym go obliczyć z alorithm powyżej, pozycja wyniki:
px = 4.358587
, który jest zupełnie inny fr om tego, czego się spodziewam.
Przepraszam za długi post, jeśli ktoś ma dość cierpliwości, by go przeczytać, byłbym zadowolony.
Masz jakieś sugestie? Czego mi brakuje? Ktoś może mi powiedzieć, co robię źle?
EDIT: Próbuję z krzywej 3D Beziera. Zdefiniowane w ten sposób:
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;
}
i pochodna:
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;
}
i co daje algorytm dla t = 6.6666 ...? Czy jest to wartość 10, tj. L, czy inna? – lmsteffan