如何从变换矩阵获得缩放、旋转和平移

问题描述 投票:0回答:1

我想从 Qt C++ OpenGL ES 2.0 中的变换矩阵获取缩放、旋转和平移,以便为 Android 和 WebAssembly 制作具有线性插值的关键帧动画。我在 JavaScript 中有下一个示例,其中包含 glMatrix (https://glmatrix.net/) 库,该库创建变换矩阵并从变换矩阵获取缩放、旋转和平移,并将它们打印到控制台:

<!DOCTYPE html>
<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>How to get a 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/[email protected]/dist/es-module-shims.js">
    </script>

    <script type="importmap">
        {
            "imports": {
                "gl-matrix": "https://cdn.jsdelivr.net/npm/[email protected]/+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
        // "QMatrix4x4" 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>

我想将其重写为Qt。我阅读了文档并尝试谷歌,但我没有找到如何从转换矩阵中提取缩放比例。

#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
        // It 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();
}
c++ qt linear-algebra
1个回答
0
投票

我打开了

getScaling
的源代码,看到了如何计算缩放比例: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;
}

我用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
        // "mat4" 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();
}

附注QMatrix4x4 构造函数 使用行优先顺序。 glMatrix fromValues 方法使用列优先顺序。

© www.soinside.com 2019 - 2024. All rights reserved.