Strumenti Utente



tutorial_qt:opengl_01bis

Qt e OpenGL - Intro alla classe QOpenGLWidget

Nel precedente articolo su Qt5 e le Opengl abbiamo cominciato a vedere come utilizzare la nuova infrastruttura Opengl introdotta nelle Qt5 derivando dalla classe QWindow. Abbiamo anche evidenziato che la classe QGLWidget già presente nelle Qt4, benché ancora presente in Qt5, è stata dichiarata obsoleta, senza che ne venisse fornito un vero e proprio sostituto. Questo è stato vero fino alla versione 5.4 con cui finalmente la vecchia QGLWidget è stata aggiornata alla nuova infrastruttura, diventando QOpenGLWidget.

Quando usare QWindow e quando QOpenGLWidget

QOpenGLWidget deriva da QWidget, quindi se abbiamo realizzato la nostra interfaccia usando oggetti derivati da QWidget, ci sarà più comodo usare QOpenGLWidget che potrà essere inserito direttamente nel layout come qualsiasi altro QWidget. Se invece non abbiamo bisogno di QWidget, ad esempio perché stiamo lavorando con QtQuick, allora preferiremo QWindow.

In realtà tale distinzione nasce semplicemente da motivi di comodità, perché è comunque possibile inserire una QWindow all'interno di un QWidget, utilizzando il metodo QWidget::createWindowContainer(), scrivendo qualcosa del tipo

QWidget *container = QWidget::createWindowContainer(glWindow);
container->setMinimumSize(...);
container->setMaximumSize(...);
container->setFocusPolicy(Qt::TabFocus);

Per approfondire il metodo statico QWidget::createWindowContainer() vi rimando al relativo annuncio sul blog ufficiale delle Qt.

Vedremo però che l'impiego della classe QOpenGLWidget è decisamente più semplice, anche perché tale classe è pensata per agevolare la programmazione opengl, al contrario della classe QWindow che è più generica.

Un esempio applicativo con QOpenGLWidget

Nel file di progetto è necessario attivare il modulo widgets

Qt += widgets

Chi viene dalle Qt4 noterà che non è più necessario il modulo opengl.

Per quanto riguarda il codice C++, analogamente a quanto accadeva con QGLWidget, è necessario derivare la classe QOpenGLWidget, implementando i tre metodi virtuali:

  • initializeGL()
  • resizeGL()
  • paintGL()

Partiamo con initializeGL(), che si occupa di inizializzare le funzionalità opengl del programma

void GLWidget::initializeGL() {
    // Creiamo l'oggetto QOpenGLShaderProgram
    m_program = new QOpenGLShaderProgram(this);

    // Compiliamo il vertex shader
    if (!m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex.glsl"))
        close();

    // Compiliamo il fragment shader
    if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment.glsl"))
        close();

    // Linkiamo gli shaders
    if (!m_program->link())
        close();

    // Attiviamo alcuni stati opengl
    glEnable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

    // Localizzaziamo gli attributi negli shader
    m_posAttr = m_program->attributeLocation("posAttr");
    m_colAttr = m_program->attributeLocation("colAttr");
    m_matrixUniform = m_program->uniformLocation("matrix");
  }

Il metodo resizeGL si occupa di ridefinire la matrice viewport quando il widget viene ridimensionato

void GLWidget::resizeGL(int w, int h) {
    glViewport(0, 0, w, h);
}

Ed infine il metodo paintGL() si occupa del disegno vero e proprio

void GLWidget::paintGL() {
    makeCurrent();

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);

    m_program->bind();

    QMatrix4x4 matrix;
    matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
    matrix.translate(0, 0, -2);

    m_program->setUniformValue(m_matrixUniform, matrix);

    QVector2D vertices [] = {
        QVector2D(0.0f, 0.707f),
        QVector2D(-0.5f, -0.5f),
        QVector2D(0.5f, -0.5f)
    };

    m_program->enableAttributeArray( m_posAttr );
    m_program->setAttributeArray( m_posAttr, vertices );

    QVector3D colors[] = {
        QVector3D(1.0f, 0.0f, 0.0f),
        QVector3D(0.0f, 1.0f, 0.0f),
        QVector3D(0.0f, 0.0f, 1.0f)
    };

    m_program->enableAttributeArray( m_colAttr );
    m_program->setAttributeArray( m_colAttr, colors );

    glDrawArrays(GL_TRIANGLES, 0, 3);

    m_program->release();
}

Otterremo così il seguente risultato

 Il risultato del codice riportato nel paragrafo

Se confrontiamo il codice appena scritto con |quello necessario con la classe QWindow notiamo una decisa semplificazione, che nasce principalmente dalla maggiore specializzazione della classe QOpenGLWidget.

Mescoliamo le opengl con QPainter...

Con QOpenGLWidget, è possibile sovrapporre al disegno opengl altri oggetti grafici realizzati con la classe QPainter.

In tal caso nel metodo paintGL() inseriamo i comandi opengl tra i metodi beginNativePainting() ed endNativePainting() di un oggetto QPainter. Al di fuori di fuori di tali metodi utilizziamo la classe QPainter come siamo abituati a fare di solito.

QPainter painter;
painter.begin(this);
...
<<comandi disegno QPainter>>
...
painter.beginNativePainting();
...
<<comandi disegno Opengl>>
...
painter.endNativePainting();
...
<<comandi disegno QPainter>>
...
painter.end();

Un esempio di cosa si può fare mescolando comandi opengl alla classe QPainter

Nell'usare tale tecnica bisgona tener conto di un dettaglio: ogni volta che creiamo QPainter, viene reimpostato il contesto opengl. Questo vuol dire che eventuali stati che sono stati impostati nel metodo initializeGL() vengono resettati.

Al link ingegnerialibera.altervista.org/blog-file/opengltut01bis.zip trovate un progetto riassuntivo di quanto visto nell'articolo.

Potrebbero interessarti anche...

Comments


tutorial_qt/opengl_01bis.txt · Ultima modifica: 2015/05/05 14:43 da mickele

Facebook Twitter Google+ Digg Reddit LinkedIn StumbleUpon Email