Rotationsmatrizen



  • Hallo zusammen!

    Ich hänge mich zur Zeit irgendwie an Rotationsmatrizen auf. Entweder verstehe ich sie nicht richtig oder ich mache etwas bei der Umsetzung falsch.

    Sollte jemand wissen was ich falsch mache, bitte melden 🙂

    Das Problem:

    Matrix3D matrix (Matrix3D::IDENTITY);
    
    float32 x1 = matrix.getRotationX(); // 0  richtig
    float32 y1 = matrix.getRotationY(); // 0  richtig
    float32 z1 = matrix.getRotationZ(); // 0  richtig
    
    matrix.rotateX (1);
    
    float32 x2 = matrix.getRotationX(); // 1  richtig
    float32 y2 = matrix.getRotationY(); // 0  richtig
    float32 z2 = matrix.getRotationZ(); // 0  richtig
    
    matrix.rotateY (1);
    
    float32 x3 = matrix.getRotationX(); // 1           richtig
    float32 y3 = matrix.getRotationY(); // 1.2368643   falsch
    float32 z3 = matrix.getRotationZ(); // 0.91898924  falsch
    

    Matrix3D.hpp

    class Matrix3D
    {
    
    public:
    
       static Matrix3D IDENTITY;
    
       float32 xx, xy, xz, xo,
               yx, yy, yz, yo,
               zx, zy, zz, zo;
    
       Matrix3D ();
       Matrix3D (float32 xx, float32 xy, float32 xz, float32 xo,
                 float32 yx, float32 yy, float32 yz, float32 yo,
                 float32 zx, float32 zy, float32 zz, float32 zo);
    
       Vector3 getPosition  () const;
       float32 getRotationX () const;
       float32 getRotationY () const;
       float32 getRotationZ () const;
       void    rotateX      (float32 angle);
       void    rotateY      (float32 angle);
       void    rotateZ      (float32 angle);
       void    set          (float32 xx, float32 xy, float32 xz, float32 xo,
                             float32 yx, float32 yy, float32 yz, float32 yo,
                             float32 zx, float32 zy, float32 zz, float32 zo);
       void    setPosition  (const Vector3& position);
    
       Matrix3D& operator *= (const Matrix3D& matrix);
    
    };
    

    Matrix3D.cpp

    #include "General.hpp"
    
    #include "Westwood/Matrix3D.hpp"
    
    Matrix3D Matrix3D::IDENTITY (1, 0, 0, 0,
                                 0, 1, 0, 0,
                                 0, 0, 1, 0);
    
    Matrix3D::Matrix3D()
    {
    }
    
    Matrix3D::Matrix3D
       (float32 xx, float32 xy, float32 xz, float32 xo,
        float32 yx, float32 yy, float32 yz, float32 yo,
        float32 zx, float32 zy, float32 zz, float32 zo)
        : xx(xx), xy(xy), xz(xz), xo(xo),
          yx(yx), yy(yy), yz(yz), yo(yo),
          zx(zx), zy(zy), zz(zz), zo(zo)
    {
    }
    
    Vector3 Matrix3D::getPosition() const
    {
       return Vector3 (xo, yo, zo);
    }
    
    float32 Matrix3D::getRotationX() const
    {
       return ::atan2 (zy, yy);
    }
    
    float32 Matrix3D::getRotationY() const
    {
       return ::atan2 (xz, zz);
    }
    
    float32 Matrix3D::getRotationZ() const
    {
       return ::atan2 (yx, xx);
    }
    
    void Matrix3D::rotateX
       (float32 angle)
    {
       float32 ca = ::cos (angle);
       float32 sa = ::sin (angle);
    
       *this *= Matrix3D (1,   0,   0,  0,
                          0,  ca, -sa,  0,
                          0,  sa,  ca,  0);
    }
    
    void Matrix3D::rotateY
       (float32 angle)
    {
       float32 ca = ::cos (angle);
       float32 sa = ::sin (angle);
    
       *this *= Matrix3D ( ca,  0,  sa,  0,
                            0,  1,   0,  0,
                          -sa,  0,  ca,  0);
    }
    
    void Matrix3D::rotateZ
       (float32 angle)
    {
       float32 ca = ::cos (angle);
       float32 sa = ::sin (angle);
    
       *this *= Matrix3D (ca, -sa,  0,  0,
                          sa,  ca,  0,  0,
                           0,   0,  1,  0);
    }
    
    void Matrix3D::set
       (float32 xx, float32 xy, float32 xz, float32 xo,
        float32 yx, float32 yy, float32 yz, float32 yo,
        float32 zx, float32 zy, float32 zz, float32 zo)
    {
       this->xx = xx;
       this->xy = xy;
       this->xz = xz;
       this->xo = xo;
       this->yx = yx;
       this->yy = yy;
       this->yz = yz;
       this->yo = yo;
       this->zx = zx;
       this->zy = zy;
       this->zz = zz;
       this->zo = zo;
    }
    
    void Matrix3D::setPosition
       (const Vector3& position)
    {
       xo = position.x;
       yo = position.y;
       zo = position.z;
    }
    
    Matrix3D& Matrix3D::operator *=
       (const Matrix3D& matrix)
    {
       this->set (xx * matrix.xx + xy * matrix.yx + xz * matrix.zx,
                  xx * matrix.xy + xy * matrix.yy + xz * matrix.zy,
                  xx * matrix.xz + xy * matrix.yz + xz * matrix.zz,
                  xo,
                  yx * matrix.xx + yy * matrix.yx + yz * matrix.zx,
                  yx * matrix.xy + yy * matrix.yy + yz * matrix.zy,
                  yx * matrix.xz + yy * matrix.yz + yz * matrix.zz,
                  yo,
                  zx * matrix.xx + zy * matrix.yx + zz * matrix.zx,
                  zx * matrix.xy + zy * matrix.yy + zz * matrix.zy,
                  zx * matrix.xz + zy * matrix.yz + zz * matrix.zz,
                  zo);
    
       return *this;
    }
    


  • Dürft ich mal erfahren, was du mit scheppen 3x4 matrizen vorhast??? 😮
    Du kannst nicht mal zwei von den matrizen miteinander multiplizieren, wo bleibt dann überhaupt der witz? kannst es gleich mit einem verschiebungvektor und drei winkeln darstellen, und dann jahrelang dranhocken und nachdenken, wie du zwei abbildungen miteinander kombinierst.

    Tipp: machs gleich mit 3x3 für 2D oder mit 4x4 für 3D. Oder nimm zur not/zum spaß/für größere genauigkeit quaternions... Aber vergiss die 3x4 matrizen, die gibts nur im theoretischen matheunterricht...



  • Das Format 4x3 ist vorgegeben und da kann ich nicht das geringste dran machen (Westwood hat es halt so umgesetzt). Für die Rotationsberechnungen wird ohnehin nur der 3x3-Teil genutzt und die 4. Spalte ist ein Positionsvektor, den kannst du hier ignorieren.



  • ähm... kP... inwiefern ist es denn so "vorgegeben" (bzw. wer kommt auf dermaßen seltsame ideen? Was ist dann mit komposition von linearen abbildungen? und was ist mit der projektion? und vor allem: welche graKa soll sowas verdauen können, die funktionieren doch afaik alle nur mit 4x4 transformation-pipelines??? 😮 )



  • Wieso gehst du davon aus, dass Objekte dieser Klasse an die Grafikkarte gegeben werden? Man kann mit Rotationsmatrizen auch so arbeiten.
    Matrix3D ist Teil der Westwood 3D Engine. Frag mich nicht wieso sie es so umgesetzt haben, die Engine hat ne saumäßige Qualität.

    Zurück zum Problem - wie komme ich an die Rotationswinkel?



  • Neku schrieb:

    Wieso gehst du davon aus, dass Objekte dieser Klasse an die Grafikkarte gegeben werden? Man kann mit Rotationsmatrizen auch so arbeiten.
    Matrix3D ist Teil der Westwood 3D Engine. Frag mich nicht wieso sie es so umgesetzt haben, die Engine hat ne saumäßige Qualität.

    Zurück zum Problem - wie komme ich an die Rotationswinkel?

    Hallo Neku,

    es kommt drauf an, was Du unter "Rotationswinkel" verstehst. Die Methoden getRotationX/Y/Z machen so keinen Sinn. Schau Dir mal die Eulerwinkel an. Bedenke, dass es auch auf die Reihenfolge der Drehungen ankommt. Ein RotX und RotY ist nicht identisch mit einem RotY und anschließenden RotX.

    Gruß
    Werner



  • atan

    atan=arkusfunktion=performancekiller

    Zurück zum Problem - wie komme ich an die Rotationswinkel?

    "getRotation" macht an sich keinen sinn, weil es niemals jemand interessieren dürfte, wenn man die winkel einmal eingegeben hat:

    1. Winkel eingeben.
    2. Vektoren transformieren.
    3. Matrix wegschmeissen.

    Matrix3D ist Teil der Westwood 3D Engine. Frag mich nicht wieso sie es so umgesetzt haben, die Engine hat ne saumäßige Qualität.

    dann schmeiss die eben auch weg oder schreib die ordentlich um...

    Wieso gehst du davon aus, dass Objekte dieser Klasse an die Grafikkarte gegeben werden? Man kann mit Rotationsmatrizen auch so arbeiten.

    aha. alles klar. Du baust dir zuerst eine mathematisch nicht korrekte, saulahme und unflexible matrix klasse zum "einfach nur so arbeiten", und fängst danach damit an, eine normale matrix klasse zu schreiben, die auch von der grafikarte akzeptiert wird? oder willst du vielleicht das alles mit einem WinAPI-Buntstift punkt für punkt zeichen?
    🙄



  • Andrey schrieb:

    atan

    atan=arkusfunktion=performancekiller

    Zurück zum Problem - wie komme ich an die Rotationswinkel?

    "getRotation" macht an sich keinen sinn, weil es niemals jemand interessieren dürfte, wenn man die winkel einmal eingegeben hat:

    1. Winkel eingeben.
    2. Vektoren transformieren.
    3. Matrix wegschmeissen.

    Dennoch hätte ich gerne die Winkel aus der Matrix.

    Andrey schrieb:

    Matrix3D ist Teil der Westwood 3D Engine. Frag mich nicht wieso sie es so umgesetzt haben, die Engine hat ne saumäßige Qualität.

    dann schmeiss die eben auch weg oder schreib die ordentlich um...

    Dann kann ich Renegade auch gleich neu schreiben 😃

    Andrey schrieb:

    Wieso gehst du davon aus, dass Objekte dieser Klasse an die Grafikkarte gegeben werden? Man kann mit Rotationsmatrizen auch so arbeiten.

    aha. alles klar. Du baust dir zuerst eine mathematisch nicht korrekte, saulahme und unflexible matrix klasse zum "einfach nur so arbeiten", und fängst danach damit an, eine normale matrix klasse zu schreiben, die auch von der grafikarte akzeptiert wird? oder willst du vielleicht das alles mit einem WinAPI-Buntstift punkt für punkt zeichen?
    🙄

    Wie gesagt, ich habe es so vorliegen und ich kann es nicht einfach ändern, ich kann es nur nutzen (Reverse Engineering eben ;)).



  • na gut, überredet^^ kannst es halt nicht ändern... was solls...

    float32 x3 = matrix.getRotationX(); // 1           richtig 
    float32 y3 = matrix.getRotationY(); // 1.2368643   falsch 
    float32 z3 = matrix.getRotationZ(); // 0.91898924  falsch
    

    Warum bist du dir da eigentlich so sicher, dass das falsch ist?
    1 rad entspricht 57.2957° imho nicht so schön für die tests wie zB PI oder PI/4, das kann sich doch kein mensch vorstellen was da rauskommt...

    wenn du dein koordinatensystem zuerst um diese 57° um die x-Achse drehst und dann nochmal um 57° um die y-achse drehst, werden da definitiv keine schönen zahlen mehr rauskommen...

    Ich würde auf jedn fall empfehlen, nochmal gaanz kräftig drüber nachzudenken, ob du die winkel wirklich so dringend brauchst, oder ob du vielleicht mit einer Achsentransformationsmatrix schon zufrieden wärst. Ich kann mir nähmlich nach wie vor nicht vorstellen, wozu man winkel gebrauchen könnte...



  • Ich möchte, wenn ich ich z.B. auf eine Einheitsmatrix eine Rotation von (1,1,1) anwende, auch wieder diese (1,1,1) auslesen können.

    Was ich auch noch suche ist, die Rotation um eine Achse festzulegen, anstatt um einen bestimmten Wert weiter zu rotieren:

    Matrix3D matrix = <unbekannt>; // irgendeine Matrix3D
    matrix.setRotationZ (0); // Rotation in Z-Achse auf 0 setzen
    


  • Das ist (logischerweise) nicht möglich. Dazu brauchst du schon die inversen um von dem neuen Koordinatensystem zurück in das alte wechseln zu können.



  • okay, wenn es nicht möglich ist brauche ich nicht weiter suchen, danke



  • Ich möchte, wenn ich ich z.B. auf eine Einheitsmatrix eine Rotation von (1,1,1) anwende, auch wieder diese (1,1,1) auslesen können.

    so geht es aber nicht. um sich das zu verdeutlichen, nimm einfach iregndeinen würfel mit markierten flächen, und dreh den jeweils um 90° um die drei achsen. Was kommt raus? In meiner dreidimensionalen wert kommt da einen einzige drehung um 90° raus, um nur eine einzige achse.

    Oder noch einfacher: 3 mal um dieselbe achse um 90° drehen. Da wird dir die atan funktion höchstwahrscheinlich -90 statt 270 rausspucken, die drehungen werden doch miteinander kombiniert.

    Bei den matrizen ist es halt so...
    Du kannst irgendwas ungleich null mit irgendwas ungleich null multiplizieren, und kriegst da möglicherweise trotzdem null raus...



  • Ich rede von Rotationen um mehrere Achsen, nicht um eine.



  • Ich rede von Rotationen um mehrere Achsen, nicht um eine.

    Ja, genau, und das ist um einiges schlimmer. Und dann hast du noch ausgerechnet einen dermaßen krummen winkel wie ~57° für deine tests ausgesucht...

    willst du mir ernsthaft erzählen, dass du im kopf abschätzen kannst, was da rauskommt, wenn du dein koordinatensystem nacheinander um alle drei achsen um 57° drehst?

    Ich kanns es zumindest nicht, und ich habe noch nirgendwo einen gesehen, der es kann, deswegen würde ich mich mit solchen behauptungen:

    float32 y3 = matrix.getRotationY(); // 1.2368643   falsch 
    float32 z3 = matrix.getRotationZ(); // 0.91898924  falsch
    

    auch nicht beeilen. Woher willst du denn wissen, dass es falsch ist? hast du es mit irgendeinem anderen programm überprüft?


Anmelden zum Antworten