GLSL矩阵变换详解(二、旋转变换、平移变换以及QMatrix4x4)

33 篇文章 4 订阅
28 篇文章 3 订阅

本篇博客展示4个例子,都是关于旋转变换、平移变换和QMatrix的操作。

在QT的帮助中,提到QMatrix是行主序。


而opengl的矩阵是列主序的。乍一看,将QMatrix传入shader之前,qmatrix需要做转置处理。但是在实际的尝试中,我发现矩阵不应转置。

我们从前面的博客 

Qt结合GLSL贴出纹理(二、采用QOpenGLShaderProgram和QOpenGLTexture)

出发,在那篇博客里,我们贴出来一个纹理,并没有做其他任何操作。现在我们在其基础上添加旋转操作。

例子1.

先看最简单的情形:让物体旋转45度

h文件:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include <QOpenGLShader>
#include <QOpenGLShaderProgram>

class MainWindow : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = 0);
    ~MainWindow();

    GLuint                          m_uiVertLoc;
    GLuint                          m_uiTexNum;
    QOpenGLTexture          *       m_pTextures;
    QOpenGLShaderProgram    *       m_pProgram;
    GLfloat                 *       m_pVertices;

protected:
    void        initializeGL();
    void        paintGL();
    void        resizeGL(int w, int h);
};

#endif // MAINWINDOW_H

cpp文件:

#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QOpenGLWidget(parent)
{
}

MainWindow::~MainWindow()
{
    m_pTextures->release();
    delete m_pTextures;
    delete m_pProgram;
    delete [] m_pVertices;

}

void MainWindow::initializeGL()
{
    initializeOpenGLFunctions();

    m_uiTexNum = 0;
    m_pVertices = new GLfloat[18];
    //给顶点赋值
    GLfloat arrVertices[18] = {0.0, 1.0, 0.0,
                               0.0, 0.0, 0.0,
                               1.0, 0.0, 0.0,
                               1.0, 0.0, 0.0,
                               1.0, 1.0, 0.0,
                               0.0, 1.0, 0.0};
    m_pVertices = new GLfloat[18];
    memcpy(m_pVertices, arrVertices, 18 * sizeof(GLfloat));

    QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
    const char *vsrc =
                        "#version 330\n"
                        "in vec3 pos;\n"
                        "out vec2 texCoord;\n"
                        "uniform mat4 mat4MVP;\n"
                        "void main()\n"
                        "{\n"
                        "    gl_Position = mat4MVP * vec4(pos, 1.0);\n"
                        "    texCoord = pos.xy;\n"
                        "}\n";
    vshader->compileSourceCode(vsrc);

    QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
    const char *fsrc =
                        "#version 330\n"
                        "out vec4 color;\n"
                        "in vec2 texCoord;\n"
                        "uniform sampler2D Tex\n;"
                        "void main()\n"
                        "{\n"
                        "    color = texture(Tex, texCoord);\n"
                        //"      color = vec4(1.0, 0.0, 0.0, 0.0);\n"
                        "}\n";
    fshader->compileSourceCode(fsrc);

    m_pProgram = new QOpenGLShaderProgram;
    m_pProgram->addShader(vshader);
    m_pProgram->addShader(fshader);
    m_pProgram->link();
    m_pProgram->bind();

    m_uiVertLoc = m_pProgram->attributeLocation("pos");
    m_pProgram->enableAttributeArray(m_uiVertLoc);
    m_pProgram->setAttributeArray(m_uiVertLoc, m_pVertices, 3, 0);


    m_pTextures = new QOpenGLTexture(QImage(QString("earth.bmp")).mirrored());
    m_pTextures->setMinificationFilter(QOpenGLTexture::Nearest);
    m_pTextures->setMagnificationFilter(QOpenGLTexture::Linear);
    m_pTextures->setWrapMode(QOpenGLTexture::Repeat);
    m_pProgram->setUniformValue("Tex", m_uiTexNum);


    glEnable(GL_DEPTH_TEST);
    glClearColor(0,0,0,1);
}

void MainWindow::paintGL()
{
    //QMatrix4x4在声明时被默认为单位矩阵
    QMatrix4x4 m1, m2, m3, m;

    //m1.viewport(0,0,m_iWidth, m_iHeight,-15,15);//useless
    //m1.ortho(-1.0f, +1.0f, -1.0f, 1.0f, 0.0f, 25.0f);//right//generate projection matrix
    //m2.lookAt(QVector3D(20,0,10), QVector3D(0,0,0), QVector3D(0,1,0));//generate view matrix, right
    //qDebug()<<m2;
    //m3.translate(0,-0.707,0.0);//right, generate model matrices
    m3.rotate(45, 0.0f, 0.0f, 1.0f);//right, generate model matrices
    qDebug()<<m3;
    m = m1 * m2 * m3;

    m_pProgram->setUniformValue("mat4MVP", m);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    m_pTextures->bind(m_uiTexNum);
    glDrawArrays(GL_TRIANGLES, 0, 6);
    m_pTextures->release();
}

void MainWindow::resizeGL(int w, int h)
{
    glViewport(0,0,w,h);
}

效果:


可见,图片的确绕Z轴旋转了45度。同时注意qDebug()打印出的矩阵。

按照https://en.wikibooks.org/wiki/GLSL_Programming/Vertex_Transformations的说法:


将alpha = 45 ,x = 0, y = 0, z = 1代入公式,不难发现,qDebug打印的结果与公式相符。

这说明我们在例子里对m3.rotate()函数的运用是正确的。


例子2. 旋转与平移结合

这个程序与例子1只变化了一处:增加了m3.translate(0,-0.5,0)


这里有两处要注意:

1)尽管先调用rotate函数,再调用了translate函数,但是纹理表现出来的效果是先平移,再旋转。因为纹理左下角不再位于窗口的中轴线x=0上了。

2)假如先进行旋转,再平移,则qDebug打印的结果应该是

0.707   -0.707   0    0

0.707    0.707    0  -0.5

0             0        1    0

0             0         0   1

与实际结果不符。


例子3. 将translate和rotate函数交换


此时显示效果与qDebug输出结果都正确了。

分析:QMatrix声明时,m3被默认赋值为单位矩阵。调用translate函数后,translate矩阵右乘单位矩阵m3.随后调用rotate函数,旋转矩阵再一次右乘m3得到最终的结果。前一篇博客 

GLSL矩阵变换详解(一、总述)

中,我们提到,一串矩阵相乘,最先起作用的其实是最右面的矩阵。因此,尽管translate先调用,但是反而后起作用。


例子4. 

为了验证例子3的分析,我们用两个独立的矩阵各自代表旋转和平移操作,然后把两者相乘:


可见,结果与例子3一样。这也就验证了例子三的猜测:translate函数与rotate函数的调用次序与实际的操作次序相反。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值