在OpenGL和Qt5(QGLWidget)中具有固定宽高比(1:1)的透视图

时间:2013-03-08 21:52:53

标签: c++ opengl qt5 qglwidget

我正在尝试将多维数据集渲染到QSplitter内的QGLWidgetput中。我希望它具有1:1的比例,因此它是一个立方体并保持该比率而不管窗口尺寸。但是,我无法让它发挥作用。无论我做什么,立方体都会随着窗户延伸。

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

  • matrix.setToIdentity()会重置initializeGL()末尾发生的除投影和翻译之外的所有内容,因此当我在resizeGL()中调用它时,投影会与之前的投影相结合,即使我在此之前将矩阵设置为身份。

  • aspect ratio的论据matrix.perspective()似乎无能为力。我已经尝试了几个没有效果的值。

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

  • perspective()之后,矩阵仍然是一个身份,但只有当我按此顺序在setToIdentity()中呼叫perspective()resizeGL时才会这样。

    < / LI>
  • initializeGL()resizeGL()中的矩阵运算会得到不同的处理。如果我未在translate()中致电perspective()initializeGL(),即使我稍后在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();
}

1 个答案:

答案 0 :(得分:1)

终于发现了什么问题。

首先,矩阵运算不应该在initializeGL()。不确定为什么。正确(并且合理地,想到它)的位置在resizeGL(),因为它在第一帧渲染的某处被调用。

其次,矩阵乘法有它们定义的顺序,就像透视&gt;翻译&gt;旋转。否则就搞砸了。

因此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