2015-01-17 7 views
13

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"); 
    } 
} 
+0

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

+0

@rpress Ich spielte mit dieser Idee ein bisschen, aber ich denke nicht, dass das das Problem ist. Weitere Informationen finden Sie im Update. –

+0

@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

Antwort

5

fand ich die Lösung für mein Problem. QGLWidget ist veraltet. Jeder, der diese Frage in der Zukunft sieht, sollte stattdessen QOpenGLWidget verwenden.

#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); 
} 

Dieser Code funktioniert einwandfrei. Der einzige Unterschied ist, dass ich QOpenGLWidget anstelle von QGLWidget verwende. Es ist sowieso viel besser als QGLWidget, da es automatisch den View-Port vergrößert und eigentlich intern zwei Frame-Buffer verwendet (offensichtlich hat QGLWidget nur vorgetäuscht, zwei Buffer zu verwenden).

+1

Sie haben nicht erwähnt, dass Sie Qt5 verwendet haben. –

+0

@FabienR war ich nicht, aber die Dokumentation sagt mit 4,8 –

+1

zu vermeiden, würde ich sagen, dass [QOpenGLWidget] (http://doc.qt.io/qt-5/qopenglwidget.html) in Qt5.4 erschienen. –

0

Möglicherweise liegt ein Konfigurationsproblem auf Ihrem PC vor.

Hier ist das Beispiel, das ich auf debian amd64/stable mit Qt4.8 verwende.

Kopf

#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 

Implementierung

#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); 

    } 

Das einzige Problem, das ich ist die Schaffung eines anderen Fensters von GLEW Besitz zu sehen. Aber Sie können es schließen. Die QGLWidget Instanz wird unten rechts befördert.

QGLWidget