为什么QGLWidget只呈现空白屏幕?

Wil*_*ver 14 c++ opengl ubuntu qt qglwidget

我以前在SDL中使用过OpenGL,但我刚开始学习QT.在QT中,使用OpenGL证明有点痛苦.我有以下两个文件:

main.cpp中

#include <stdio.h>
#include <QApplication>
#include "glwidget.hpp"
#include <QGLFormat>

int main(int args, char *argv[]) {
    QApplication app(args, argv);

    GLWidget openGLWidget;
    openGLWidget.show();

    return app.exec();
}
Run Code Online (Sandbox Code Playgroud)

glwidget.hpp

#include <GL/glew.h>
#include <QGLWidget>
class GLWidget : public QGLWidget {
    protected:
        void initializeGL();
        void paintGL();
};

void GLWidget::initializeGL() {
    if(glewInit() != GLEW_OK) {
        fprintf(stderr, "GLEW failed to initialize.");
    }   
}
void GLWidget::paintGL() {
    glClearColor(1, 0, 0, 1); 
    glClear(GL_COLOR_BUFFER_BIT);
    QGLWidget::swapBuffers();
}
Run Code Online (Sandbox Code Playgroud)

helloworld.pro

TEMPLATE = app 
INCLUDEPATH += .
LIBS += -lGL -lGLEW

# Input
SOURCES += main.cpp
HEADERS += glwidget.hpp
QT += widgets opengl
Run Code Online (Sandbox Code Playgroud)

当我编译并运行它时,我会得到一个窗口,其中包含创建时印在其上的任何内容.我期待的是红屏.我错过了什么?

UPDATE

我已经编辑了我的GLWidget实现,我得到了它的工作.但是,它只在我调用glDrawArrays时才有效(参见下面的paintGL函数).在SDL中,glDrawArrays不需要看到空白的彩色屏幕.没有glDrawArrays,qt似乎由于某种原因忽略了glClear().有谁知道为什么?

GLWidget::GLWidget(QGLWidget* parent) : QGLWidget(QGLFormat(), parent) {
}

void GLWidget::initializeGL() {
    if(glewInit() != GLEW_OK) {
        fprintf(stderr, "GLEW failed to initialize.");
    }   
    glClearColor(1, 0, 0, 1); 
    glClear(GL_COLOR_BUFFER_BIT);
    shaderProgram.addShaderFromSourceFile(QGLShader::Vertex, 
                                          "vertexShader.vert");
    shaderProgram.addShaderFromSourceFile(QGLShader::Fragment, 
                                          "fragmentShader.frag");
    shaderProgram.link();
    GLuint vertexBuffer; 
    glGenBuffers(1, &vertexBuffer);
}

void GLWidget::paintGL() {
    shaderProgram.bind();
    glClearColor(1, 0, 0, 1); 
    glClear(GL_COLOR_BUFFER_BIT);
    setAutoBufferSwap(false);
    //glDrawArrays(GL_TRIANGLES, 0, 1);
    swapBuffers();
    shaderProgram.release();
}

void GLWidget::resizeGL(int width, int height) {
    if(height == 0) {
        height = 1;
    }   

    if(width == 0) {
        width = 1;
    }   

    glViewport(0, 0, width, height);
}
Run Code Online (Sandbox Code Playgroud)

更新2

我想也许Qt正在做一些鬼鬼祟祟的事情,如果我手动完成所有事情,我就会摆脱这个问题.但qt仍然以某种方式知道我是否使用程序,以及我是否使用glDrawArrays.在下面的代码中,取出glDrawArrays或glUseProgram会使代码无效.它必须与QGLContext中发生的事情有关.

#include <stdio.h>
#include <fstream>
#include <string>
#include "glwidget.hpp"

GLWidget::GLWidget(QWidget* parent) : QGLWidget(QGLFormat(), parent) {
}

void GLWidget::initializeGL() {
    if(glewInit() != GLEW_OK) {
        fprintf(stderr, "GLEW failed to initialize.");
    }
    glContext = this->context();
    if(!glContext->create()) {
        fprintf(stderr, "Failed to create context.\n");
    }
    glContext->makeCurrent();
    program = glCreateProgram();
    addShader(program, GL_VERTEX_SHADER, "vertexShader.vert");
    addShader(program, GL_FRAGMENT_SHADER, "fragmentShader.frag");
    linkProgram(program);
    setAutoBufferSwap(false);
}

void GLWidget::paintGL() {
    glUseProgram(program);
    glClearColor(1, 0, 0, 1);
    glClear(GL_COLOR_BUFFER_BIT);

    glDrawArrays(GL_TRIANGLES, 0, 1);
    glContext->swapBuffers();
    glUseProgram(0);
}

void GLWidget::resizeGL(int width, int height) {
    if(height == 0) {
        height = 1;
    }

    if(width == 0) {
        width = 1;
    }

    glViewport(0, 0, width, height);
}  

GLuint GLWidget::addShader(GLuint programID, GLuint shaderType, std::string fileName) {
    GLuint shader = glCreateShader(shaderType);
    std::ifstream file(fileName.c_str());
    std::string source = "";

    if(file.is_open()) {
        std::string line;
        while(getline(file, line)) {
            source += line + "\n";
        }
    } else {
        fprintf(stderr, "File %s failed to open.\n", fileName.c_str());
    }
    const char* sourceC = source.c_str();
    glShaderSource(shader, 1, &sourceC, NULL);

    glCompileShader(shader);
    GLint compileStatus;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compileStatus);
    if(compileStatus == GL_FALSE) {
        fprintf(stderr, "Shader %s failed to compile.\n", fileName.c_str());
        return 0;
    }
    glAttachShader(programID, shader);
    return shader;
}

void GLWidget::linkProgram(GLuint programID) {
    glLinkProgram(programID);
    GLint linkStatus;
    glGetProgramiv(programID, GL_LINK_STATUS, &linkStatus);
    if(linkStatus == GL_FALSE) {
        fprintf(stderr,"Failed to link program.\n");
    }
}
Run Code Online (Sandbox Code Playgroud)

Wil*_*ver 6

我找到了解决问题的方法.不推荐使用QGLWidget.任何在将来看到这个问题的人都应该使用QOpenGLWidget.

#include "GLShaderWidget.hpp"
GLShaderWidget::GLShaderWidget(QWidget* parent) : QOpenGLWidget(parent)
{
}

GLShaderWidget::~GLShaderWidget() {
}


void GLShaderWidget::initializeGL() {
        glClearColor(1, 0, 0, 1);

}

void GLShaderWidget::paintGL() {
        glClear(GL_COLOR_BUFFER_BIT);
}
Run Code Online (Sandbox Code Playgroud)

这段代码工作得很好.唯一的区别是我使用的是QOpenGLWidget而不是QGLWidget.它远比QGLWidget好得多,因为它会自动重新调整视图端口的大小,实际上在内部使用两个帧缓冲区(显然QGLWidget只是假装使用两个缓冲区).