Zakładamy, że nasz układ współrzędnych jest lewoskrętny.
Macierz wynikowa będzie złożeniem 5 macierzy:
- obrót wokół wybranej osi sprowadzający wektor $\mathbf{\vec A}$ do płaszczyzny osi układu współrzędnych (np. wokół osi Z do płaszczyzny XZ)
- obrót wokół osi układu współrzędnych tak by sprowadzić wektor $\mathbf{\vec A}$ do jednej z osi układ współrzędnych (np. wokół osi Y do osi Z)
- obrót wokół tej osi (tym samym wokół wektora w jego lokalnym układzie współrzędnych od którego sprowadziliśmy go obrotami) o kąt $\mathbf{\theta}$
- obrót odwrotny do 2
- obrót odwrotny do 1
Najpierw robimy obrót o kąt $\mathbf{-\alpha}$ wokół osi Z sprowadzając wektor $\mathbf{\vec A}$ do płaszczyzny XY.
$\alpha=-\arctan(\displaystyle\frac{v}{u})$
Teraz robimy obrót o kąt $\mathbf{-\beta}$ wokół osi Y sprowadzając wektor $\mathbf{\vec A}$ do osi Z.
$s=\sqrt{v^2+u^2}$
$\beta=-arctan(\displaystyle\frac{s}{w})$
Teraz nie pozostaje nam nic innego jak dokonać obrotu o kąt $\mathbf{\theta}$ wokół osi Z. $\beta=-arctan(\displaystyle\frac{s}{w})$
Kompletna macierz ma postać:
$M=M_Z^{-1}(\alpha)M_Y^{-1}(\beta)M_Z(\theta)M_{Y}(\beta)M_Z(\alpha)$
Zakładając, że wektor $\mathbf{\vec A}$ jest wektorem jednostkowym (co znacząco upraszcza i przyspiesza obliczenia), po wytrwałym mnożeniu powinniśmy dostać:$t=1-cos\theta$
$M=\begin{bmatrix}
tuu+cos\theta & tuv-wsin\theta & tuw+vsin\theta & 0\\
tuv+wsin\theta & tvv+cos\theta & tvw-usin\theta & 0 \\
tuw-vsin\theta & tvw+usin\theta & tww+cos\theta & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}$
Przykład w C# prosto z definicji:$M=\begin{bmatrix}
tuu+cos\theta & tuv-wsin\theta & tuw+vsin\theta & 0\\
tuv+wsin\theta & tvv+cos\theta & tvw-usin\theta & 0 \\
tuw-vsin\theta & tvw+usin\theta & tww+cos\theta & 0 \\
0 & 0 & 0 & 1
\end{bmatrix}$
public static Matrix4 CreateRotateAroundVector(Vector3 a_rotate_around, double a_angle) { a_rotate_around = a_rotate_around.Normalized; double u = a_rotate_around.X; double v = a_rotate_around.Y; double w = a_rotate_around.Z; var m_alpha = Matrix4.CreateRotateZ(-Math.Atan2(v, u)); var m_beta = Matrix4.CreateRotateY( -Math.Atan2(Math.Sqrt(v*v + u*u), w))); var m_angle = Matrix4.CreateRotateZ(a_angle); return m_alpha.Inverted * m_beta.Inverted * m_angle * m_beta * m_alpha; }I wersja szybka:
public static Matrix4 CreateRotateAroundVector(Vector3 a_rotate_around, double a_angle) { a_rotate_around = a_rotate_around.Normalized; double cos = Math.Cos(a_angle); double sin = Math.Sin(a_angle); double t = 1 - cos; double u = a_rotate_around.X; double v = a_rotate_around.Y; double w = a_rotate_around.Z; return new Matrix4( t * u * u + cos, t * u * v - sin * w, t * u * w + sin * v, 0, t * u * v + sin * w, t * v * v + cos, t * v * w - sin * u, 0, t * u * w - sin * v, t * v * w + sin * u, t * w * w + cos, 0, 0, 0, 0, 1 ); }
Brak komentarzy:
Prześlij komentarz