Question

I'm trying to render a cube into a QGLWidgetput inside a QSplitter. I'd like it to have a 1:1 ratio so it is a cube and keeps that ratio regardless of window dimensions. I haven't been able to get this to work, though. No matter what I do, the cube stretches with the window.

I have two additional problems with how the code works.

  • matrix.setToIdentity() resets everything except projection and translation which happen at the end of initializeGL(), and so when I invoke it in resizeGL(), the projection combines with the previous one, even if I set the matrix to identity before that.

  • The argument aspect ratio of matrix.perspective() seems to be doing nothing. I've tried several values with no effect.

  • For some reason, the projection is orthographic, not perspective.

  • The matrix is still an identity after perspective(), but only if I call setToIdentity() and perspective() in resizeGL in that order.

  • Matrix operations in initializeGL() and resizeGL() get different treatment. If I don't call translate() and perspective() in initializeGL(), the cube will not appear even if I do it later in resizeGL().

Can anyone explain this to me? I thought that QMatrix4x4 class was here to hold the matrices to 3D transformations so I don't have to implement them myself.

I've looked at some tutorials, but either they use some kind of matrices in a similar way or they seem to use deprecated OpenGL functions. Tried casting width and height to floats and using separate matrices for transformations.

How do I make the 1:1 ratio work?

A relevant piece of my code:

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();
}
Was it helpful?

Solution

Finally found what was wrong.

First, matrix operations shouldn't be in initializeGL(). Not exactly sure why. The correct (and reasonable, come to think of it) place is in resizeGL(), as it gets called somewhere about the first frame render.

Second, matrix multiplications have their defined order, which goes like perspective > translate > rotate. Otherwise it screws up.

So the correct (or at least working) code in resizeGL() goes like this:

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top