Ich habe OpenGL in SDL zuvor verwendet, aber ich habe gerade begonnen, QT zu lernen. In QT erweist sich die Verwendung von OpenGL als etwas schmerzhaft. Ich habe die folgenden zwei Dateien:Warum rendert QGLWidget nur einen leeren Bildschirm?
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
Als ich das kompilieren und ausführen, ich ein Fenster, das zum Zeitpunkt der Schöpfung alles, was dahinter stand, eingeprägt hat. Was ich erwarte, ist ein roter Bildschirm. Was vermisse ich?
UPDATE
Ich habe meine GLWidget Implementierung bearbeitet, und ich habe es zu arbeiten. Es funktioniert jedoch nur, wenn ich glDrawArrays aufrufen (siehe die Funktion paintGL unten). In SDL war glDrawArrays nicht erforderlich, um einen leeren farbigen Bildschirm zu sehen. Ohne glDrawArrays scheint qt aus irgendeinem Grund glClear() zu ignorieren. Weiß jemand warum?
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);
}
UPDATE 2
Ich dachte, dass vielleicht etwas hinterhältig unter der Haube Qt tat, und dass, wenn ich alles von Hand tat ich das Problem loswerden würde. Aber qt weiß irgendwie immer noch, ob ich ein Programm benutze oder nicht und ob ich glDrawArrays verwende oder nicht. Wenn Sie im folgenden Code glDrawArrays oder glUseProgram verwenden, funktioniert der Code nicht. Es muss etwas damit zu tun haben, was in QGLContext passiert.
#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");
}
}
Der Grund kann dies sein: QT-Dokumentation für void QGLWidget :: swapBuffers(): > Vertauscht den Bildschirminhalt mit einem Offscreen-Puffer. Dies funktioniert nur, wenn das Format des Widgets den doppelten Puffermodus angibt. > Normalerweise muss diese Funktion nicht explizit aufgerufen werden, da dies automatisch nach jedem Widget-Repaint erfolgt, d. H. Jedes Mal, nachdem paintGL() ausgeführt wurde. – rpress
@rpress Ich spielte mit dieser Idee ein bisschen, aber ich denke nicht, dass das das Problem ist. Weitere Informationen finden Sie im Update. –
@WilliamOliver, dass das ursprüngliche Problem war - zumindest kann ich den „leeren Bildschirm“ in Ihrem Original-Code, reproduzieren und den gewünschten roten Bildschirm * entweder *, indem es den Aufruf 'swapBuffers' entfernen oder durch einen Anruf an' setAutoBufferSwap Hinzufügen (falsch) '. Hat das nicht funktioniert? – Lack