为什么 QGLWidget 只渲染一个空白屏幕?
Why does QGLWidget only render a blank screen?
以前在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();
}
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();
}
helloworld.pro
TEMPLATE = app
INCLUDEPATH += .
LIBS += -lGL -lGLEW
# Input
SOURCES += main.cpp
HEADERS += glwidget.hpp
QT += widgets opengl
当我编译并运行这个时,我得到一个window,上面印有创建时背后的任何内容。我期待的是一个红色屏幕。我错过了什么?
更新
我已经编辑了我的 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);
}
更新 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");
}
}
您的 PC 上可能存在配置问题。
这是我在 debian amd64/stable 和 Qt4.8 上使用的示例。
header
#ifndef GLWIDGET_HPP
#define GLWIDGET_HPP
#include <QGLWidget>
class GlWidget:
public QGLWidget
{
public:
GlWidget(QWidget *parent=0);
~GlWidget();
protected:
void initializeGL();
void paintGL();
};
#endif // GLWIDGET_HPP
实施
#include "glwidget.hpp"
GlWidget::GlWidget(QWidget* parent)
: QGLWidget(QGLFormat(), parent)
{
}
GlWidget::~GlWidget()
{
}
void GlWidget::initializeGL()
{
}
void GlWidget::paintGL()
{
glClearColor(1.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
}
我看到的唯一问题是创建另一个由 GLEW 拥有的 window。但是你可以关闭它。
QGLWidget
实例在右下角提升。
我找到了解决问题的办法。 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);
}
这段代码工作得很好。唯一的区别是我使用的是 QOpenGLWidget 而不是 QGLWidget。它无论如何都比 QGLWidget 好得多,因为它会自动调整视口的大小,并且 实际上 在内部使用两个帧缓冲区(显然 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();
}
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();
}
helloworld.pro
TEMPLATE = app
INCLUDEPATH += .
LIBS += -lGL -lGLEW
# Input
SOURCES += main.cpp
HEADERS += glwidget.hpp
QT += widgets opengl
当我编译并运行这个时,我得到一个window,上面印有创建时背后的任何内容。我期待的是一个红色屏幕。我错过了什么?
更新
我已经编辑了我的 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);
}
更新 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");
}
}
您的 PC 上可能存在配置问题。
这是我在 debian amd64/stable 和 Qt4.8 上使用的示例。
header
#ifndef GLWIDGET_HPP
#define GLWIDGET_HPP
#include <QGLWidget>
class GlWidget:
public QGLWidget
{
public:
GlWidget(QWidget *parent=0);
~GlWidget();
protected:
void initializeGL();
void paintGL();
};
#endif // GLWIDGET_HPP
实施
#include "glwidget.hpp"
GlWidget::GlWidget(QWidget* parent)
: QGLWidget(QGLFormat(), parent)
{
}
GlWidget::~GlWidget()
{
}
void GlWidget::initializeGL()
{
}
void GlWidget::paintGL()
{
glClearColor(1.f, 0.f, 0.f, 1.f);
glClear(GL_COLOR_BUFFER_BIT);
}
我看到的唯一问题是创建另一个由 GLEW 拥有的 window。但是你可以关闭它。
QGLWidget
实例在右下角提升。
我找到了解决问题的办法。 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);
}
这段代码工作得很好。唯一的区别是我使用的是 QOpenGLWidget 而不是 QGLWidget。它无论如何都比 QGLWidget 好得多,因为它会自动调整视口的大小,并且 实际上 在内部使用两个帧缓冲区(显然 QGLWidget 只是假装使用两个缓冲区)。