Strumenti Utente



tutorial_qt:opengl_01bis

Questa è una vecchia versione del documento!


Qt5 e Opengl #1bis

Nel primo tutorial su Qt5 e le Opengl abbiamo visto come utilizzare la nuova infrastruttura Opengl introdotta nelle Qt5. Abbiamo lavorato in particolare con la classe QWindow, essendo la precedente classe QGLWidget ormai obsoleta e non essendo disponibile nelle prime release delle Qt5 niente di analogo. 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. Al contrario, se invece non abbiamo bisogno di QWidget, ad esempio perché stiamo lavorando con QtQuick, allora preferiremo utilizzare 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 il programmatore nella programmazione Opengl, al contrario della classe QWindow che è più generica.

Sporchiamoci le mani con QOpenGLWidget

Analogamente a quanto già accadeva con QGLWidget, sarà necessario derivare la classe QOpenGLWidget, implementando tre metodi virtuali:

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

Partiamo con initializeGL(), che si occupa di inizializzare il nostro programma

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

    // Compiliamo lo shader dei vertici
    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
    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(), che 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();
}

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 a questo tipo di impiego.

Mescoliamo un po' le cose...

E' possibile disegnare oggetti grafici 2D con QPainter sul nostro Widget.

In tal caso nel metodo paintGL() creiamo un oggetto QPainter. A questo punto i comandi opengl veri e propri dovranno essere compresi tra i due metodi

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

Al di fuori di fuori di tali comandi è possibile utilizzare la classe QPainter come siamo abituati a fare in qualunque QWidget.


tutorial_qt/opengl_01bis.1421818176.txt.gz · Ultima modifica: 2015/01/21 06:29 da mickele

Facebook Twitter Google+ Digg Reddit LinkedIn StumbleUpon Email