QOpenGLWidget的resizeGL不是调用glViewport的地方吗?



我正在试验新的QOpenGLWidget类(注意,这是而不是 QGLWidget类)。

我在画三角形。我有一个平凡的顶点着色器,它在剪辑空间中接收坐标,所以不涉及矩阵或投影。其中一个顶点的坐标是-1, -1, 0, 1,另一个顶点的坐标是1, 1, 0, 1

当我没有调用任何glViewport时,程序呈现就好像我在resizeGL函数中调用glViewport(0, 0, w, h);一样,我不是。也就是说,无论我如何调整窗口的大小,三角形的两个顶点都附着在窗口的左下角和右上角。

当我实际上在我的resizeGL函数中添加glViewport的调用时,它显然被忽略了-如果我传递w/2, h/2或任何其他值都没关系,渲染与我调用glViewport(0, 0, w, h);完全相同(例如,我希望三角形出现在窗口的左下角glViewport(0, 0, w/2, h/2);的情况下)

当我在paingGL函数中调用glViewport(0, 0, width()/2, height()/2)时,呈现如预期的那样-所有内容都绘制在窗口的左下角。

因此,glViewport似乎在resizeGLpaintGL之间被覆盖。发生了什么,我该如何修复它?我是否必须在我的paintGL函数中进行视口转换?

文档中列出的QGLWidget和QOpenGLWidgets之间的区别之一是后者呈现到framebuffer而不是直接呈现到屏幕。这可能是解释的关键吗?

为了以防万一,我附上了完整的代码供参考。

//triangle.h

#ifndef TRIANGLE_H
#define TRIANGLE_H
#include <QOpenGLBuffer>
#include <QOpenGLFunctions>
class Triangle
{
public:
    Triangle();
    void render();
    void create();
private:
    QOpenGLBuffer position_vbo;
    QOpenGLFunctions *glFuncs;
};
#endif // TRIANGLE_H
//triangle.cpp

#include "triangle.h"
Triangle::Triangle()
    :position_vbo(QOpenGLBuffer::VertexBuffer)
{    
}
void Triangle::create()
{
    glFuncs = QOpenGLContext::currentContext()->functions();
    position_vbo.create();
    float val[] = {
           -1.0f,   -1.0f, 0.0f, 1.0f,
            0.0f, -0.366f, 0.0f, 1.0f,
            1.0f,    1.0f, 0.0f, 1.0f,
            1.0f,    0.0f, 0.0f, 1.0f,
            0.0f,    1.0f, 0.0f, 1.0f,
            0.0f,    0.0f, 1.0f, 1.0f,
        };
    position_vbo.setUsagePattern(QOpenGLBuffer::StaticDraw);
    position_vbo.bind();
    position_vbo.allocate(val, sizeof(val));
    position_vbo.release();
}
void Triangle::render()
{
    position_vbo.bind();
    glFuncs->glEnableVertexAttribArray(0);
    glFuncs->glEnableVertexAttribArray(1);
    glFuncs->glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0);
    glFuncs->glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, 0, (void*)(3*4*sizeof(float)));
    glFuncs->glDrawArrays(GL_TRIANGLES, 0, 3);
    glFuncs->glDisableVertexAttribArray(0);
    glFuncs->glDisableVertexAttribArray(1);
    position_vbo.release();
}
//widget.h

#ifndef WIDGET_H
#define WIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include "triangle.h"
class Widget : public QOpenGLWidget
             , protected QOpenGLFunctions
{
    Q_OBJECT
public:
    Widget(QWidget *parent = 0);    
    ~Widget();
protected:
    virtual void initializeGL() override;
    virtual void paintGL() override;
    virtual void resizeGL(int w, int h) override;
private:
    QOpenGLShaderProgram* program;
    Triangle t;
};
#endif // WIDGET_H
//widget.cpp

#include "widget.h"
#include <exception>
#include <QDebug>
Widget::Widget(QWidget *parent)
    : QOpenGLWidget(parent)
{
}
Widget::~Widget()
{
}
void Widget::initializeGL()
{
    initializeOpenGLFunctions();
    program = new QOpenGLShaderProgram(this);
    if(!program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/vertexshader.vert"))
    {
       throw std::exception(("Vertex Shader compilation error: " + program->log()).toLocal8Bit().constData());
    }
    if(!program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/fragmentshader.frag"))
    {
       throw std::exception(("Fragment Shader compilation error: " + program->log()).toLocal8Bit().constData());
    }
    if(!program->link())
    {
       throw std::exception(("Program Link error: " + program->log()).toLocal8Bit().constData());
    }
    t.create();
}

void Widget::paintGL()
{
    glClearColor(0.f, 0.15f, 0.05f, 0.f);
    glClear(GL_COLOR_BUFFER_BIT);
    //glViewport(0, 0, width()/2, height()/2); //works!!
    program->bind();
    t.render();
    program->release();
}
void Widget::resizeGL(int w, int h)
{
    glViewport(0, 0, w/2, h/2); //doesn't work
}
//main.cpp

#include "widget.h"
#include <exception>
#include <QApplication>
#include <QMessageBox>
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    try
    {
        Widget w;
        w.show();
        return a.exec();
    }
    catch(std::exception const & e)
    {
        QMessageBox::warning(nullptr, "Error", e.what());
    }
}

//顶点着色器

#version 330
layout (location = 0) in vec4 position;
layout (location = 1) in vec4 color;
smooth out vec4 theColor;
void main()
{
    gl_Position = position;
    theColor = color;
}

//片段着色器

#version 330
out vec4 fragColor;
smooth in vec4 theColor;
void main()
{
    fragColor = theColor;
}

所以看起来glViewport在resizeGL和paintGL之间被覆盖了。发生了什么,我该如何修复它?我是否必须在我的paintGL函数中进行视口转换?

Qt5可以使用OpenGL进行自己的绘图。同时,作为QOpenGLWindow子窗口的小部件的内容也会呈现给fbo。所以这意味着,在你的代码和Qt之间做了很多glViewport调用。

当我实际添加调用glViewport在我的resizeGL函数,它显然被忽略了(…)

是的。你的期望到底是什么?要使OpenGL程序健壮,调用glViewport的唯一有效位置是在绘图代码中。每一个教程,把glViewport在窗口大小调整处理程序是错误的,应该烧掉。

当我在paingGL函数中调用glViewport(0,0, width()/2, height()/2)时,渲染如预期的那样

相关内容

  • 没有找到相关文章

最新更新