2015-01-17 19 views
13

Używam OpenGL w SDL, ale dopiero zacząłem uczyć się QT. W QT korzystanie z OpenGL okazuje się nieco uciążliwe. Mam następujące dwa pliki:Dlaczego QGLWidget renderuje tylko pusty ekran?

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 

Kiedy skompilować i uruchomić ten, mam okno, które ma wszystko, co było za nim w momencie nadrukowania na nim. Oczekuję tylko czerwonego ekranu. czego mi brakuje?

UPDATE

Mam edytowany moje wykonanie GLWidget, i mam go do pracy. Działa to jednak tylko wtedy, gdy wywołuję glDrawArrays (zobacz poniżej funkcję paintGL). W SDL glDrawArrays nie był konieczny, aby zobaczyć pusty kolorowy ekran. Bez glDrawArrays qt wydaje się ignorować glClear() z jakiegoś powodu. Czy ktoś wie, dlaczego?

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

Myślałem, że może Qt robił coś ukrytych pod maską, i że jeśli zrobiłem wszystko ręcznie, chciałbym pozbyć się tego problemu. Ale qt nadal jakoś wie, czy używam programu, czy nie, i czy używam glDrawArrays, czy nie. W poniższym kodzie wyjęcie programu glDrawArrays lub glUseProgram powoduje, że kod nie działa. Musi mieć coś wspólnego z tym, co dzieje się wewnątrz 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"); 
    } 
} 
+0

Przyczyna może być następująca: Dokumentacja QT dla pustej QGLWidget :: swapBuffers(): > Zamienia zawartość ekranu za pomocą bufora poza ekranem. Działa to tylko wtedy, gdy format widżetu określa tryb podwójnego bufora. > Zazwyczaj nie ma potrzeby jawnego wywoływania tej funkcji, ponieważ jest ona wykonywana automatycznie po odświeżeniu widżetu, tj. Za każdym razem po wykonaniu malowania GL(). – rpress

+0

@rpress Grałem z tym pomysłem trochę, ale nie sądzę, że to jest problem. Zobacz aktualizację, aby uzyskać więcej szczegółów. –

+0

@WilliamOliver był pierwotnym problemem - przynajmniej mogę odtworzyć "pusty ekran" w twoim oryginalnym kodzie, i ustawić żądany czerwony ekran * albo * usuwając wywołanie 'swapBuffers' lub dodając wywołanie' setAutoBufferSwap (false) '. Czy to nie zadziałało? – Lack

Odpowiedz

5

znalazłem rozwiązania mojego problemu. QGLWidget jest przestarzałe. Każdy, kto zobaczy to pytanie w przyszłości, powinien zamiast tego użyć 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); 
} 

Ten kod działa dobrze. Jedyną różnicą jest to, że używam QOpenGLWidget zamiast QGLWidget. Jest on znacznie lepszy niż QGLWidget, ponieważ automatycznie zmienia rozmiar portu widoku, a w rzeczywistości wykorzystuje wewnętrznie dwa bufory ramki (podobno QGLWidget po prostu udawał, że używa dwóch buforów).

+1

Nie wspomniałeś, że używasz Qt5. –

+0

@FabienR I nie był, ale dokumentacja mówi, aby unikać używania 4.8 –

+1

Powiedziałbym, że [QOpenGLWidget] (http://doc.qt.io/qt-5/qopenglwidget.html) pojawił się w Qt5.4. –

0

Być może masz problem z konfiguracją na swoim komputerze.

Oto przykład, którego używam na debian amd64/stable z Qt4.8.

nagłówek

#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 

realizacja

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

    } 

Jedyny problem widzę jest stworzenie innego okna należącego GLEW. Ale możesz to zamknąć. Instancja QGLWidget jest promowana w prawym dolnym rogu.

QGLWidget

Powiązane problemy