Qmatrix4x4转换不起作用 [英] Qmatrix4x4 translate does not take any effect

查看:263
本文介绍了Qmatrix4x4转换不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在opengl上没有很多经验,所以请问如果这个问题很愚蠢.

我正在尝试通过在类glView中转换Qmatrix4x4字段来使用mouseMoveEvent移动三角形.当我什么也不做(透视,用矩阵翻译)并且只调用m_program->setUniformValue(m_matrixUniform, m_matrix)时,一切都很好,但是如果我只是做this->m_matrix=matrix;(其中矩阵只是Qmatrix4x4变量),则m_program->setUniformValue(m_matrixUniform, m_matrix)方法不起作用. /p>

在我看来,我在更新小部件(我只是调用update())或所有着色器逻辑时都遇到了一些问题.谢谢!

//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

和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); // Передать событие дальше
}

解决方案

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);

注意,通常,视图矩阵用于定义视点和场景外观.
投影矩阵定义了3D场景在2D视口上的投影.在透视投影"中,投影矩阵描述了从针孔相机中看到的世界3D点到视口的2D点的映射.
视图矩阵定义了视点和方向. 模型矩阵定义对象在场景(世界)中的比例方向和位置.

模型视图投影矩阵是投影,视图和模型母体的串联,并定义了从模型步速到剪切空间的顶点坐标的转换:

 mvp = projection * view * model
 

在您的情况下,这意味着:

 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);
 

但是请注意,在透视投影时,位移量取决于在视口上拖动的对象的深度.

如果对象靠近眼睛位置,则视口上的平移会导致眼睛和目标位置的位移较小:

如果从物体到眼睛的距离很远,则视口上的平移会导致眼睛和目标位置的大位移:

观看演示

在这种情况下,视场为90度,深度为1:该量将相等".

 QMatrix4x4 projection;
projection.perspective(90.0f, 4.0f/3.0f, 0.1f, 100.0f);

QMatrix4x4 view;
view.translate(0, 0, -1.0);
 

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); // Передать событие дальше
}

解决方案

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);

这篇关于Qmatrix4x4转换不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆