Processing math: 100%

2011-07-11

Rotacja wokół arbitrarnej osi.

Musimy znaleźć macierz obracającą o kąt θ wokół wektora A(u,v,w).

Zakładamy, że nasz układ współrzędnych jest lewoskrętny.

Macierz wynikowa będzie złożeniem 5 macierzy:
  1. obrót wokół wybranej osi sprowadzający wektor A do płaszczyzny osi układu współrzędnych (np. wokół osi Z do płaszczyzny XZ)
  2. obrót wokół osi układu współrzędnych tak by sprowadzić wektor A do jednej z osi układ współrzędnych (np. wokół osi Y do osi Z)
  3. 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 θ
  4. obrót odwrotny do 2
  5. obrót odwrotny do 1
Zróbmy dokładnie tak jak jest napisane w nawiasach. Jednakże możemy wybrać dowolnie inne osie układu współrzędnych jako osie obrotu, wynik musi być ten sam.

image/svg+xml x y P α z v w u
Najpierw robimy obrót o kąt α wokół osi Z sprowadzając wektor A do płaszczyzny XY.

α=arctan(vu)
image/svg+xml x y P β z w s
Teraz robimy obrót o kąt β wokół osi Y sprowadzając wektor A do osi Z.

s=v2+u2
β=arctan(sw)
Teraz nie pozostaje nam nic innego jak dokonać obrotu o kąt θ wokół osi Z.

Kompletna macierz ma postać:

M=M1Z(α)M1Y(β)MZ(θ)MY(β)MZ(α)
Zakładając, że wektor A jest wektorem jednostkowym (co znacząco upraszcza i przyspiesza obliczenia), po wytrwałym mnożeniu powinniśmy dostać:

t=1cosθ

M=[tuu+cosθtuvwsinθtuw+vsinθ0tuv+wsinθtvv+cosθtvwusinθ0tuwvsinθtvw+usinθtww+cosθ00001]
Przykład w C# prosto z definicji:
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