c++qtopenglglslqopenglwidget

Qmatrix4x4 translate does not take any effect


I didn't have a lot experience in opengl, so excuse me if the question is silly.

I'm trying to move triangle with the mouseMoveEvent by translating Qmatrix4x4 field in my class glView. When i did not do anything (perspective, translate with matrix) and just call m_program->setUniformValue(m_matrixUniform, m_matrix) everything works fine, but if i just do this->m_matrix=matrix; (where matrix is just Qmatrix4x4 variable) and then m_program->setUniformValue(m_matrixUniform, m_matrix) method does not work.

To my mind, i have some problems either with updating widget (i just call update()) or with all shader logic. Thank you!

//Here is glView.h
#ifndef GLVIEW_H
#define GLVIEW_H
#include <QtOpenGL>
#include <QGLWidget>
#include <QOpenGLWidget>

#include <QtGui/QWindow>
#include <QtGui/QOpenGLFunctions>
#include <QMouseEvent>

//Class for drawing triangles
class glView : public QOpenGLWidget, public QOpenGLFunctions
{
public:
    glView(float left, float right, float bot, float top, float minz, float maxz)
        : QOpenGLWidget(), QOpenGLFunctions(), f_left(left), f_right(right), f_bot(bot), f_top(top), f_minz(minz), f_maxz(maxz)
    {}
    virtual~glView()
    {}
    void initializeGL() override;
    void resizeGL(int w, int h)override;
    void paintGL()override;

    void mousePressEvent(QMouseEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void keyPressEvent(QKeyEvent* pe) Q_DECL_OVERRIDE;
private:

    struct CFace{
        int v1,v2,v3;
    };

    GLuint m_posAttr;
    GLuint m_colAttr;
    GLuint m_matrixUniform;
    QOpenGLShaderProgram *m_program;
    int m_frame = 0;
    QMatrix4x4 m_matrix;

    QPoint mPrevMousePos;
};

#endif // GLVIEW_H

And cpp

//Here is glView.cpp
#include <qopengl.h>
#include "glView.h"

#include <QtGui/QGuiApplication>
#include <QtGui/QMatrix4x4>
#include <QtGui/QOpenGLShaderProgram>

#include <QMouseEvent>

static const char *vertexShaderSource =
    "attribute highp vec4 posAttr;\n"
    "attribute lowp vec4 colAttr;\n"
    "varying lowp vec4 col;\n"
    "uniform highp mat4 matrix;\n"
    "void main() {\n"
    "   col = colAttr;\n"
    "   gl_Position = matrix*posAttr;\n"
    "}\n";

static const char *fragmentShaderSource =
    "varying lowp vec4 col;\n"
    "void main() {\n"
    "   gl_FragColor = col;\n"
    "}\n";

//------------------------------------------------------------------------------
void glView::initializeGL()
{   
    m_program = new QOpenGLShaderProgram(this);
    m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, vertexShaderSource);
    m_program->addShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShaderSource);
    m_program->link();
    m_posAttr = m_program->attributeLocation("posAttr");
    m_colAttr = m_program->attributeLocation("colAttr");
    m_matrixUniform = m_program->uniformLocation("matrix");
}
//------------------------------------------------------------------------------

void glView::paintGL()
{   
    QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();

    const qreal retinaScale = devicePixelRatio();
    f->glViewport(0, 0, width() * retinaScale, height() * retinaScale);

    f->glClear(GL_COLOR_BUFFER_BIT);
    m_program->bind();

    QMatrix4x4 matrix;
//Here is the problem!
    //matrix.perspective(0.0f, 4.0f/3.0f, 0.1f, 100.0f);
    //matrix.translate(-5, -5, 0);

    //???
    this->m_matrix=matrix;
    m_program->setUniformValue(m_matrixUniform, m_matrix);


    GLfloat vertices[] = {
        0.0f, 0.707f,
        -0.5f, -0.5f,
        0.5f, -0.5f
    };

    GLfloat colors[] = {
        1.0f, 0.0f, 0.0f,
        0.0f, 1.0f, 0.0f,
        0.0f, 0.0f, 1.0f
    };

    f->glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, 0, vertices);
    f->glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors);

    f->glEnableVertexAttribArray(0);
    f->glEnableVertexAttribArray(1);

    f->glDrawArrays(GL_TRIANGLES, 0, 3);

    f->glDisableVertexAttribArray(1);
    f->glDisableVertexAttribArray(0);

    m_program->release();

    ++m_frame;
}

void glView::mousePressEvent(QMouseEvent *event)
{
    mPrevMousePos = event->pos();
    QOpenGLWidget::mousePressEvent(event);
}

void glView::mouseMoveEvent(QMouseEvent *event)
{
    auto diff = event->pos() - mPrevMousePos;
    //??
    this->m_matrix.translate(diff.x()/(width()*0.5), -diff.y()/(height()*0.5));

    mPrevMousePos = event->pos();

    //?? m_program->setUniformValue(m_matrixUniform, m_matrix);
    update();
    QOpenGLWidget::mouseMoveEvent(event);
}

void glView::mouseReleaseEvent(QMouseEvent *event)
{

    QOpenGLWidget::mouseReleaseEvent(event);
}

void glView::keyPressEvent(QKeyEvent *pe)
{
    switch (pe->key())
       {
          case Qt::Key_Up:
             this->m_matrix.scale(QVector3D(2.0f,2.0f,1.0f));
          break;

          case Qt::Key_Down:
             this->m_matrix.translate(QVector3D(0,-1,0));
          break;
       }
    update();
    QOpenGLWidget::keyPressEvent(pe); // Передать событие дальше
}

Solution

  • The 1st parameter of QMatrix4x4::perspective is the vertical field angle in degrees. If the angle is 0, the the filed of view is infinite small, it is a point. For example use 90.0 degrees.

    The 3D parameter is the distance to the near plane and the 4th parameter is the distance to the far plane. The near and the far plane define the limit the view frustum. All the geometry has to be in this area. So in your case near is 0.1 and far is 100.0.
    Since the z axis points out of the viewport in viewspace, you have to set a z translation which is grater than -0.1 and smaller than *-100.0.

    Since the view volume at perspective projection is a frustum (truncated pyramid), the amount of the x and y translation, in the projection o the viewport, depends on the depth (view space z coordinate) of the geometry and field of view angle. Anyway (-5, -5) is to much with this setup and will shift the triangle out of the view. But you can use (-1, -1) for example.

    QMatrix4x4 matrix;
    matrix.perspective(90.0f, 4.0f/3.0f, 0.1f, 100.0f);
    matrix.translate(-1.0, -1.0, -2.0);
    
    this->m_matrix=matrix;
    m_program->setUniformValue(m_matrixUniform, m_matrix);
    

    Note, in common a view matrix is used to define the point of view and the look at the scene.
    The projection matrix defines the projection of the 3 dimensional scene on the 2 dimensional view port. At Perspective Projection the projection matrix describes the mapping from 3D points in the world as they are seen from of a pinhole camera, to 2D points of the viewport.
    The view matrix defines the point of view and the direction of view. The model matrix defines the scale orientation and position of the object in the scene (world).

    The model view projection matrix is the concatenation of the projection, view and model matirx and defines the transformation of a vertex coordinates form model s pace to clip space:

    mvp = projection * view * model
    

    In your case this means:

    QMatrix4x4 projection;
    projection.perspective(90.0f, 4.0f/3.0f, 0.1f, 100.0f);
    
    QMatrix4x4 view;
    view.translate(0, 0, -2.0);
    
    QMatrix4x4 model = this->m_matrix;
    
    QMatrix4x4 mvp = projection * view * model;
    m_program->setUniformValue(m_matrixUniform, mvp);
    

    But note, at perspective projection the amount of displacement depends on the depth of the object which is dragged on the viewport.

    If the object is close to the eye position, then a translation on the viewport leads to a small displacement of the eye and target positions:

    If the distance from the object to the eye is far, then a translation on the viewport leads to a large displacement of the eye and target positions:

    See the demo:

    In this case, the amount will be "equal" with a filed of view of 90 degrees and an depth of 1:

    QMatrix4x4 projection;
    projection.perspective(90.0f, 4.0f/3.0f, 0.1f, 100.0f);
    
    QMatrix4x4 view;
    view.translate(0, 0, -1.0);