Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Game Development
  4. How to get scaling, rotation, and translation from a transformation matrix
Forum Updated to NodeBB v4.3 + New Features

How to get scaling, rotation, and translation from a transformation matrix

Scheduled Pinned Locked Moved Solved Game Development
2 Posts 1 Posters 1.4k Views 2 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • 8Observer88 Offline
    8Observer88 Offline
    8Observer8
    wrote on last edited by 8Observer8
    #1

    I want to get scaling, rotation, and translation from a transformation matrix in Qt C++ OpenGL ES 2.0 to make a keyframe animation with linear interpolation for Android and WebAssembly. I have the next example in JavaScript with the glMatrix (https://glmatrix.net/) library that creates the transformation matrix and gets scaling, rotation, and translation from the transformation matrix and prints them to the console:

    <!DOCTYPE html>
    <html>
    
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>How to get scaling, rotation, and translation from a transformation matrix using glMatrix and JavaScript</title>
    </head>
    
    <body>
        <!-- Since import maps are not yet supported by all browsers, its is
            necessary to add the polyfill es-module-shims.js -->
        <script async src="https://unpkg.com/es-module-shims@1.7.3/dist/es-module-shims.js">
        </script>
    
        <script type="importmap">
            {
                "imports": {
                    "gl-matrix": "https://cdn.jsdelivr.net/npm/gl-matrix@3.4.3/+esm"
                }
            }
        </script>
    
        <script type="module">
            import { mat4, quat, vec3 } from "gl-matrix";
    
            // Create a transformation matrix
            const matrix = mat4.create();
            mat4.translate(matrix, matrix, [20, 80, 0]);
            mat4.rotate(matrix, matrix, -90 * Math.PI / 180, [0, 0, 1]);
            mat4.scale(matrix, matrix, [20, 20, 1]);
            console.log("Transformation matrix: " + matrix);
            // Output:  0, -20, 0, 0,
            //         20,   0, 0, 0,
            //          0,   0, 1, 0,
            //         20,  80, 0, 1
            // "mat4" has a column-major order
    
            // Get scaling
            const scaling = vec3.create();
            mat4.getScaling(scaling, matrix);
            console.log(`Scaling: (sx: ${scaling[0]},` +
                ` sy: ${scaling[1]}, sz${scaling[2]})`);
            // Output: (sx: 20, sy: 20, sz: 1)
    
            // Get rotation
            const rotation = quat.create();
            mat4.getRotation(rotation, matrix);
            console.log(`Rotation: (rx: ${rotation[0]}, ry: ${rotation[1]}`,
                ` rz: ${rotation[2]}, rw: ${rotation[3]})`);
            // Output: (rx: 0, ry: 0  rz: -0.7071067690849304, rw: 0.7071067690849304)
    
            // Get translation
            const translation = vec3.create();
            mat4.getTranslation(translation, matrix);
            console.log(`Translation: (tx: ${translation[0]},` +
                ` ty: ${translation[1]}, tz: ${translation[2]})`);
            // Output: (tx: 20, ty: 80, tz: 0)
        </script>
    
    </body>
    
    </html>
    

    I want to rewrite it to Qt. I read a documentation and tried to google but I didn't find how to extract scaling from a transformation matrix.

    #include <QtGui/QMatrix4x4>
    #include <QtGui/QOpenGLFunctions>
    #include <QtGui/QQuaternion>
    #include <QtMath>
    #include <QtOpenGL/QOpenGLWindow>
    #include <QtWidgets/QApplication>
    #include <QtWidgets/QWidget>
    
    class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions
    {
    public:
        OpenGLWindow()
        {
            setTitle("OpenGL ES 2.0, Qt6, C++");
            resize(350, 350);
    
            QMatrix4x4 m;
            m.translate(20.f, 80.f, 0.f);
            m.rotate(-90.f, QVector3D(0.f, 0.f, 1.f));
            m.scale(20.f, 20.f);
            qDebug() << "Transformation matrix: " << m;
            // Output:  0,  20, 0, 20,
            //        -20,   0, 0, 80,
            //          0,   0, 1,  0,
            //          0,   0, 0,  1
            // "QMatrix4x4" has a row-major order
        }
    
        void initializeGL() override
        {
            initializeOpenGLFunctions();
            glClearColor(0.2f, 0.2f, 0.2f, 1.f);
        }
    
        void paintGL() override
        {
            glClear(GL_COLOR_BUFFER_BIT);
        }
    };
    
    int main(int argc, char *argv[])
    {
        QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
        QApplication app(argc, argv);
        OpenGLWindow w;
        w.show();
        return app.exec();
    }
    
    1 Reply Last reply
    0
    • 8Observer88 Offline
      8Observer88 Offline
      8Observer8
      wrote on last edited by 8Observer8
      #2

      I opened a source code of getScaling and saw how scaling is calculated there: https://glmatrix.net/docs/mat4.js.html#line1197

      export function getScaling(out, mat) {
        let m11 = mat[0];
        let m12 = mat[1];
        let m13 = mat[2];
        let m21 = mat[4];
        let m22 = mat[5];
        let m23 = mat[6];
        let m31 = mat[8];
        let m32 = mat[9];
        let m33 = mat[10];
        out[0] = Math.hypot(m11, m12, m13);
        out[1] = Math.hypot(m21, m22, m23);
        out[2] = Math.hypot(m31, m32, m33);
        return out;
      }
      

      I made the same with qHypot

      #include <QtGui/QMatrix3x3>
      #include <QtGui/QMatrix4x4>
      #include <QtGui/QOpenGLFunctions>
      #include <QtGui/QQuaternion>
      #include <QtMath>
      #include <QtOpenGL/QOpenGLWindow>
      #include <QtWidgets/QApplication>
      #include <QtWidgets/QWidget>
      
      class OpenGLWindow : public QOpenGLWindow, private QOpenGLFunctions
      {
      public:
          OpenGLWindow()
          {
              setTitle("OpenGL ES 2.0, Qt6, C++");
              resize(350, 350);
      
              QMatrix4x4 matrix;
              matrix.translate(20.f, 80.f, 0.f);
              matrix.rotate(-90.f, QVector3D(0.f, 0.f, 1.f));
              matrix.scale(20.f, 20.f);
              qDebug() << "Transformation matrix: " << matrix;
              // Output:  0,  20, 0, 20,
              //        -20,   0, 0, 80,
              //          0,   0, 1,  0,
              //          0,   0, 0,  1
              // "QMatrix4x4" has a row-major order
      
              // Get scaling
              float sx = qHypot(matrix.row(0)[0], matrix.row(1)[0], matrix.row(2)[0]);
              float sy = qHypot(matrix.row(0)[1], matrix.row(1)[1], matrix.row(2)[1]);
              float sz = qHypot(matrix.row(0)[2], matrix.row(1)[2], matrix.row(2)[2]);
              QVector3D scaling(sx, sy, sz);
              qDebug() << "Scaling:" << scaling;
              // Output: QVector3D(20, 20, 1)
      
              // Get rotation
              QMatrix3x3 rotationMatrix;
              rotationMatrix.data()[0] = matrix.column(0)[0] / sx;
              rotationMatrix.data()[1] = matrix.column(0)[1] / sy;
              rotationMatrix.data()[2] = matrix.column(0)[2] / sz;
              rotationMatrix.data()[3] = matrix.column(1)[0] / sx;
              rotationMatrix.data()[4] = matrix.column(1)[1] / sy;
              rotationMatrix.data()[5] = matrix.column(1)[2] / sz;
              rotationMatrix.data()[6] = matrix.column(2)[0] / sx;
              rotationMatrix.data()[7] = matrix.column(2)[1] / sy;
              rotationMatrix.data()[8] = matrix.column(2)[2] / sz;
              QQuaternion rotation = QQuaternion::fromRotationMatrix(rotationMatrix);
              qDebug() << "Rotation:" << rotation;
              // Output: QQuaternion(scalar:0.707107, vector:(0, 0, -0.707107))
      
              // Get translation
              float tx = matrix.row(0)[3];
              float ty = matrix.row(1)[3];
              float tz = matrix.row(2)[3];
              QVector3D translation(tx, ty, tz);
              qDebug() << "Translation:" << translation;
              // Output: QVector3D(20, 80, 0)
          }
      
          void initializeGL() override
          {
              initializeOpenGLFunctions();
              glClearColor(0.2f, 0.2f, 0.2f, 1.f);
          }
      
          void paintGL() override
          {
              glClear(GL_COLOR_BUFFER_BIT);
          }
      };
      
      int main(int argc, char *argv[])
      {
          QApplication::setAttribute(Qt::ApplicationAttribute::AA_UseDesktopOpenGL);
          QApplication app(argc, argv);
          OpenGLWindow w;
          w.show();
          return app.exec();
      }
      
      QT += core gui opengl widgets
      
      win32: LIBS += -lopengl32
      
      CONFIG += c++17
      
      SOURCES += \
          main.cpp
      

      P.S. The QMatrix4x4 constructor uses row-major order. The glMatrix fromValues method uses column-major order.

      1 Reply Last reply
      1
      • 8Observer88 8Observer8 has marked this topic as solved on

      • Login

      • Login or register to search.
      • First post
        Last post
      0
      • Categories
      • Recent
      • Tags
      • Popular
      • Users
      • Groups
      • Search
      • Get Qt Extensions
      • Unsolved