OpenGL和Qt5(QGLWidget)中具有固定纵横比(1:1)的透视图

Perspective with fixed aspect ratio (1:1) in OpenGL and Qt5 (QGLWidget)

本文关键字:透视图 Qt5 QGLWidget OpenGL      更新时间:2023-10-16

我正试图将一个多维数据集渲染到QSpliter内的QGLWidgetput中。我希望它有一个1:1的比例,所以它是一个立方体,无论窗口尺寸如何,都保持这个比例。不过,我还没能把它发挥作用。无论我做什么,立方体都会随着窗户伸展。

关于代码的工作方式,我还有两个额外的问题。

  • matrix.setToIdentity()重置了除在initializeGL()结束时发生的投影和平移之外的所有内容,因此当我在resizeGL()中调用它时,投影与前一个相结合,即使在此之前我将矩阵设置为恒等式。

  • matrix.perspective()的论点aspect ratio似乎毫无作用。我尝试了几个值,但没有效果。

  • 出于某种原因,投影是正交的,而不是透视的。

  • 矩阵在perspective()之后仍然是一个恒等式,但前提是我按顺序调用resizeGL中的setToIdentity()perspective()

  • CCD_ 10和CCD_。如果我不在initializeGL()中调用translate()perspective(),则即使稍后在resizeGL()中调用,多维数据集也不会出现。

有人能向我解释一下吗?我认为QMatrix4x4类是用来将矩阵保持为3D转换的,所以我不必自己实现它们。

我看过一些教程,但它们要么以类似的方式使用某种矩阵,要么似乎使用了不推荐使用的OpenGL函数。尝试将宽度和高度转换为浮动,并使用单独的矩阵进行转换。

如何使1:1的比例发挥作用

我的一段相关代码:

void ModelView::initializeGL()
{
    m_program = new QGLShaderProgram(this);
    m_program->addShaderFromSourceCode(QGLShader::Vertex, vertexShaderSource);
    m_program->addShaderFromSourceCode(QGLShader::Fragment, fragmentShaderSource);
    m_program->link();
    GLuint shader_id = glCreateShader(GL_VERTEX_SHADER);
    glShaderSource(shader_id, 1, vertexShaderSource, NULL);
    glCompileShader(shader_id);
    ShaderIds[2] = shader_id;
    shader_id = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(shader_id, 1, fragmentShaderSource, NULL);
    glCompileShader(shader_id);
    ShaderIds[1] = shader_id;
    glAttachShader(ShaderIds[0], ShaderIds[1]);
    glAttachShader(ShaderIds[0], ShaderIds[2]);
    glLinkProgram(ShaderIds[0]);*/
    matrix.setToIdentity(); //--------------------------------------
    float aspect = (((float)width())/((float)height()));
    matrix.perspective(60, aspect, 0.1, 100.0);
    matrix.translate(0, 0, -2);
}
void ModelView::paintGL()
{
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_LESS);
    glClearColor(.5f, .5f, .5f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glViewport(0, 0, width(), height());
    m_program->bind();
    m_posAttr = m_program->attributeLocation("posAttr");
    m_colAttr = m_program->attributeLocation("colAttr");
    m_matrixUniform = m_program->uniformLocation("matrix");
    m_program->setUniformValue(m_matrixUniform, matrix); //-----------------
    glGenBuffers(1, &BufferId);
    glGenBuffers(1, &IndexBufferId);
    glBindBuffer(GL_ARRAY_BUFFER, BufferId);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, IndexBufferId);
    glBufferData(GL_ARRAY_BUFFER, BufferSize, Vertices, GL_STATIC_DRAW);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices), Indices, GL_STATIC_DRAW);
    glVertexAttribPointer(m_posAttr, 3, GL_FLOAT, GL_FALSE, VertexSize, 0);
    glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, VertexSize, (GLvoid *)RgbOffset);
    glEnableVertexAttribArray(0);
    glEnableVertexAttribArray(1);
    glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_BYTE, NULL);
    glDisableVertexAttribArray(1);
    glDisableVertexAttribArray(0);
    m_program->release();
}
void ModelView::resizeGL(int w, int h)
{
    glViewport(0, 0, w, h);
    matrix.setToIdentity();  //------------------------------------
    matrix.translate(0, 0, -2);
    matrix.perspective(60, ((float)w)/((float)h), 0.1, 100.0);
    updateGL();
}

终于发现了问题所在。

首先,矩阵运算不应该在initializeGL()中。不太清楚为什么。正确的(想想看也是合理的(位置是在resizeGL()中,因为它在第一帧渲染的某个地方被调用。

其次,矩阵乘法有其定义的顺序,类似于透视>平移>旋转。否则就会搞砸。

因此,resizeGL()中正确(或至少有效(的代码如下所示:

glViewport(startX, startY, width, height);    //resize the viewport
matrix.setToIdentity();             //reset the uniform value (matrix)
perspectiveMatrix.setToIdentity();   //reset the projection matrix
                                       //set new projection (aspect ratio)
perspectiveMatrix.perspective(angle, (float)width/(float)height, nearPlane, farPlane);
matrix *= perspectiveMatrix;    //apply transformations
matrix *= translationMatrix;
matrix *= rotationMatrix;
updateGL();                  //re-render