Ho già usato OpenGL in SDL, ma ho appena iniziato a imparare QT. In QT, l'uso di OpenGL si sta rivelando un po 'un problema. Ho le seguenti due file:Perché QGLWidget esegue solo il rendering di uno schermo vuoto?
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
Quando compilo e si esegue questo, ottengo una finestra che ha tutto ciò che c'era dietro, al momento della creazione, impressa su di essa. Quello che mi aspetto è uno schermo rosso. Cosa mi manca?
UPDATE
ho modificato il mio implementazione GLWidget, e ho preso a lavorare. Tuttavia, funziona solo quando chiamo glDrawArrays (vedere la funzione paintGL di seguito). In SDL, glDrawArrays non era necessario per visualizzare uno schermo colorato vuoto. Senza glDrawArrays, qt sembra ignorare glClear() per qualche ragione. Qualcuno sa perché?
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
ho pensato che forse Qt stava facendo qualcosa subdolo sotto il cofano, e che se ho fatto tutto manualmente, vorrei sbarazzarsi del problema. Ma qt ancora in qualche modo sa se sto usando un programma o meno, e se sto usando glDrawArrays o no. Nel codice sottostante, eliminare glDrawArrays o glUseProgram rende il codice non funzionante. Deve avere qualcosa a che fare con ciò che accade all'interno di 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");
}
}
Il motivo potrebbe essere questo: QT docs per void QGLWidget :: swapBuffers(): > Scambia il contenuto dello schermo con un buffer fuori schermo. Funziona solo se il formato del widget specifica la modalità doppio buffer. > Normalmente, non è necessario chiamare questa funzione in modo esplicito perché viene eseguita automaticamente dopo ogni ridisegno del widget, ad esempio ogni volta dopo che paintGL() è stato eseguito. – rpress
@rpress Ho giocato un po 'con questa idea, ma non penso che sia questo il problema. Vedi l'aggiornamento per maggiori dettagli. –
@WilliamOliver era il problema originale - almeno, posso riprodurre lo "schermo vuoto" nel codice originale, e rendere lo schermo rosso desiderato * * * rimuovendo la chiamata a 'swapBuffers' o aggiungendo una chiamata a' setAutoBufferSwap (false) '. Non funzionava? – Lack