Strumenti Utente



tutorial_qt:opengl_01

Differenze

Queste sono le differenze tra la revisione selezionata e la versione attuale della pagina.

Link a questa pagina di confronto

Entrambe le parti precedenti la revisione Revisione precedente
Prossima revisione
Revisione precedente
Ultima revisione Entrambe le parti successive la revisione
tutorial_qt:opengl_01 [2015/01/21 06:43]
mickele
tutorial_qt:opengl_01 [2015/02/11 15:39]
mickele
Linea 1: Linea 1:
-~~NEWSFEED~~ +====== Qt OpenGL: Introduzione ======
-====== Qt5 Opengl #1 ====== +
-<news:Qt5 e Opengl #1>+
  
-Con la nuova release delle [[http://qt-project.org|Qt]] sono state introdotte delle nuove classi per l'impiego delle librerie grafiche [[http://www.opengl.org/|Opengl]].+Con la nuova release delle [[http://qt-project.org|Qt]] sono state introdotte nuove classi per l'impiego delle librerie grafiche [[http://www.opengl.org/|Opengl]].
  
-In questo articolo accenneremo brevemente le principali novità introdotte e vedremo un esempio in cui reimplementeremo la classe QWindow. Nel [[tutorial_qt:opengl_01bis|tutorial 1bis]] (?!) invece vedremo come realizzare lo stesso risultato reimplementando la classe QOpenGLWidget.+In questo articolo accenneremo brevemente alle principali novità introdotte e vedremo un esempio applicativo disegneremo un triangolo in una classe derivata da [[http://doc.qt.io/qt-5/qwindow.html|QWindow]]Nell'articolo [[tutorial_qt:opengl_01bis|Qt e OpenGL: Intro alla classe QOpenGLWidget]] potete invece vedere come realizzare lo stesso risultato reimplementando la classe QOpenGLWidget.
  
 ===== Il perché di tanti cambiamenti ===== ===== Il perché di tanti cambiamenti =====
Linea 14: Linea 12:
  
 ~~READMORE~~ ~~READMORE~~
-</news> 
  
-===== QGLWidget vs QWindow =====+===== QGLWidget vs QWindow/QOpenGLWidget =====
  
 La prima grande novità riguarda la classe base che useremo per creare la nostra superficie. Nel passato si faceva riferimento a [[http://qt-project.org/doc/qt-5.1/qtopengl/qglwidget.html|QGLWidget]]. La prima grande novità riguarda la classe base che useremo per creare la nostra superficie. Nel passato si faceva riferimento a [[http://qt-project.org/doc/qt-5.1/qtopengl/qglwidget.html|QGLWidget]].
  
-Per quanto sia sempre possibile usare QGLWidget anche con le Qt5, il nuovo approccio prevede l'impiego della classe [[http://qt-project.org/doc/qt-5.1/qtgui/qwindow.html|QWindow]].  +Per quanto sia sempre possibile usare QGLWidget anche con le Qt5, il nuovo approccio prevede l'impiego delle classi [[http://doc.qt.io/qt-5/qwindow.html|QWindow]] e [[http://doc.qt.io/qt-5/qopenglwidget.html|QOpenGLWidget]]
- +
-Quali le differenze tra le due classi? +
- +
-Una prima differenza è che QGLWidget deriva da QWidget, QWindow no, non avremo quindi a disposizione alcuni dei comodi strumenti presenti in QWidget. +
- +
-Un'altra differenza riguarda le modalità con cui andremo a scrivere le sottoclassi. Derivando QGLwidget era necessario reimplementare i metodi virtuali //initializeGL()//, //paintGL ()// e //resizeGL( int width, int height )//. Con la classe QWindow abbiamo invece una maggiore flessibilità: possiamo decidere noi come e con quali metodi fornire i vari comandi.+
  
 ===== Partiamo da QWindow... ===== ===== Partiamo da QWindow... =====
  
-Iniziamo con un esempio concreto, creando una classe derivata di QWindow nella quale vogliamo disegnare un triangolo.+Vediaemo come creare una classe derivata da QWindow per disegnare usando le API OpenGL. Nel farlo dobbiamo tener conto di due aspetti:  
 +  * QWindow non deriva da QWidget, non avremo quindi a disposizione alcuni dei comodi strumenti presenti in QWidget 
 +  * mentre con QGLWidget (e con QOpenGLWidget) è necessario ridefinire i metodi virtuali //initializeGL()//, //paintGL ()// e //resizeGL( int width, int height )//, con la classe QWindow abbiamo una maggiore flessibilità: possiamo decidere noi come e con quali metodi fornire i vari comandi.
  
-Creiamo la classe GLWindow che estende QWindow e [[http://qt-project.org/doc/qt-5.1/qtgui/qopenglfunctions.html|QOpenGLFunctions]]. Estendiamo anche ques'ultima classe per poter accedere facilmente a tutti i comandi Opengl in essa contenuti.+Creiamo la classe GLWindow che estende QWindow e [[http://qt-project.org/doc/qt-5.1/qtgui/qopenglfunctions.html|QOpenGLFunctions]]. Estendiamo anche quest'ultima classe per poter accedere facilmente a tutti i comandi Opengl in essa contenuti.
  
 Avremo un file header glwindow.h che conterrà Avremo un file header glwindow.h che conterrà
Linea 61: Linea 54:
   };   };
  
-Abbiamo introdotto alcuni attribute e metodi che analizzeremo strada facendo.+Abbiamo introdotto alcuni attributi e metodi che analizzeremo strada facendo.
  
-Il costruttore di GLWindow si limita ad inizializzare un attributo e a dire alle Qt che intendiamo disegnare sulla superficie con le opengl.+Il costruttore di GLWindow si limita ad inizializzare un attributo e a comunicare all'infrastruttura delle Qt che intendiamo disegnare sulla superficie impiegando le API OpenGL.
  
   GLWindow::GLWindow(QWindow *parent) :   GLWindow::GLWindow(QWindow *parent) :
Linea 73: Linea 66:
   }   }
  
-La gestione degli eventi nel nostro primo esempio è molto semplice, ci basta reimplementare due metodi virtuali: void exposeEvent(QExposeEvent *event) e void resizeEvent(QResizeEvent *event).  +Poichè le funzionalità che vogliamo implementare sono molto semplici, ci basta reimplementare due metodi virtuali: void exposeEvent(QExposeEvent *event) e void resizeEvent(QResizeEvent *event). Il primo viene chiamato ogni volta che cambia la visibilità della nostra superficie di modo che ogni qualvolta l'oggetto diventa visibile, il triangolo sia ridisegnato. Ecco il codice
- +
-Il primo viene chiamato ogni volta che cambia la visibilità della nostra superficie; se è visibile, dovremo ridisegnare il triangolo. Ecco il codice+
  
   void GLWindow::exposeEvent(QExposeEvent *event) {   void GLWindow::exposeEvent(QExposeEvent *event) {
Linea 82: Linea 73:
   }   }
  
-Il metodo paint(), che vedremo tra poco, è quello che disegna il triangolo.+Il metodo paint(), che vedremo tra poco, disegna il triangolo.
  
-Il metodo resizeEvent() viene chiamato in concomitanza dei ridimensionamenti della superficie. In tal caso dovremo cambiare le dimensioni della finestra opengl.+Il metodo resizeEvent() viene chiamato in concomitanza dei ridimensionamenti della superficie. In tal caso dovremo cambiare le dimensioni della finestra OpenGL.
  
   void GLWindow::resizeEvent(QResizeEvent *event) {   void GLWindow::resizeEvent(QResizeEvent *event) {
Linea 94: Linea 85:
   }   }
  
-===== ... e aggiungiamo un po' di Opengl =====+===== Gli shader =====
  
-I metodi che vedremo ora, sia come denominazione che come struttura che come compiti, sono il risultato di una scelta personale e come tali possono essere modificati. Perciò, acquisita un po' di dimestichezza con le opengl, modificateli pure!+Alla base della programmazione OpenGL moderna ci sono gli [[http://it.wikipedia.org/wiki/Shader|shader]].  
 + 
 +Le prime versioni dello standard OpenGL prevedevano pipeline grafiche fisse: i calcoli eseguiti dalla scheda grafica erano di una tipologia ben specifica. Le Opengl 2.0 hanno introdotte per un primo livello di personalizzazione delle operazioni compiute dalla GPU che sono così diventate programmabili. Gli shader sono i programmi che carichiamo sulle schede grafiche. 
 + 
 +Nella versione 5 delle Qt creiamo gli shader usando la classe [[http://qt-project.org/doc/qt-5/qopenglshaderprogram.html|QOpenGLShaderProgram]].  
 + 
 +===== Opengl secondo la Qt-way ===== 
 + 
 +I metodi che vedremo ora, sia come denominazione che come struttura che come compiti, sono il risultato di una scelta personale e come tali possono essere modificati. Perciò, acquisita un po' di dimestichezza con le OpenGL, modificateli pure!
  
 Analizziamo prima il metodo paint(), il cuore delle operazioni di disegno Analizziamo prima il metodo paint(), il cuore delle operazioni di disegno
Linea 103: Linea 102:
       if (!isExposed())       if (!isExposed())
           return;           return;
-  +      
       bool needsInitialize = false;       bool needsInitialize = false;
-  +      
       if (!context) {       if (!context) {
           m_context = new QOpenGLContext(this);           m_context = new QOpenGLContext(this);
Linea 113: Linea 112:
           needsInitialize = true;           needsInitialize = true;
       }       }
 +      
       m_context->makeCurrent(this);       m_context->makeCurrent(this);
 +      
       if(needsInitialize) {       if(needsInitialize) {
           initialize();           initialize();
       }       }
-  +      
       paintGL();       paintGL();
 +      
       m_context->swapBuffers(this);       m_context->swapBuffers(this);
   }   }
  
-Una volta sola, prima che avvenga il primo disegno, paint() inizializza m_context e chiama il metodo initialize() che si occupa di impostare l'ambiente opengl.+Una volta sola, prima che avvenga il primo disegno, paint() inizializziamo m_context chiamando il metodo initialize() che imposta il contesto OpenGL
  
   void GLWindow::initialize() {   void GLWindow::initialize() {
Linea 143: Linea 142:
  
  
-Il metodo initShaders() inizializza gli shaders. Più in particolare, nel metodo initShaders():+Il metodo initShaders() inizializza gli shaders eseguendo le seguenti operazioni:
   * creiamo un oggetto QOpenGLShaderProgram   * creiamo un oggetto QOpenGLShaderProgram
   * associamo a questo oggetto il codice degli shaders, contenuto in due file esterni   * associamo a questo oggetto il codice degli shaders, contenuto in due file esterni
Linea 150: Linea 149:
   void GLWindow::initShaders() {   void GLWindow::initShaders() {
       m_context->makeCurrent(this);       m_context->makeCurrent(this);
-  +      
       m_program = new QOpenGLShaderProgram(this);       m_program = new QOpenGLShaderProgram(this);
-  +      
       // Compila lo shader dei vertici       // Compila lo shader dei vertici
       if (!m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex.glsl"))       if (!m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex.glsl"))
           close();           close();
-  +      
       // Compile lo shader fragment       // Compile lo shader fragment
       if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment.glsl"))       if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment.glsl"))
           close();           close();
 +      
       // Linka shaders       // Linka shaders
       if (!m_program->link())       if (!m_program->link())
Linea 187: Linea 186:
  
  
-Ed infine i comandi per disegnare il nostro triangolo. In questo primo articolo ci limitiamo a passare ad ogni ridisegno i dati necessari. Per farlo usiamo prima il metodo enableAttributeArray() di QOpenglShaderProgram, con cui attiviamo l'attributo che ci interessa, e poi il metodo setAttributeArray() con cui passiamo i valori.+Ed infine vediamo i comandi per disegnare il nostro triangolo. In questo primo articolo ci limitiamo a passare ad ogni ridisegno i dati necessari. Per farlo usiamo prima il metodo QOpenglShaderProgram::enableAttributeArray(), con cui attiviamo l'attributo che ci interessa, e poi il metodo QOpenglShaderProgram::setAttributeArray() con cui passiamo i relativi valori
  
   void GLWindow::paintGL() {   void GLWindow::paintGL() {
       m_context->makeCurrent( this );       m_context->makeCurrent( this );
-  +      
       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);       glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT);
-  +      
       m_program->bind();       m_program->bind();
-  +      
       QMatrix4x4 matrix;       QMatrix4x4 matrix;
       matrix.perspective(60, 4.0/3.0, 0.1, 100.0);       matrix.perspective(60, 4.0/3.0, 0.1, 100.0);
       matrix.translate(0, 0, -2);       matrix.translate(0, 0, -2);
-  +      
       m_program->setUniformValue(m_matrixUniform, matrix);       m_program->setUniformValue(m_matrixUniform, matrix);
-  +      
       QVector2D vertices [] = {       QVector2D vertices [] = {
           QVector2D(0.0f, 0.707f),           QVector2D(0.0f, 0.707f),
Linea 207: Linea 206:
           QVector2D(0.5f, -0.5f)           QVector2D(0.5f, -0.5f)
       };       };
-  +      
       m_program->enableAttributeArray( m_posAttr );       m_program->enableAttributeArray( m_posAttr );
       m_program->setAttributeArray( m_posAttr, vertices );       m_program->setAttributeArray( m_posAttr, vertices );
-  +      
       QVector3D colors[] = {       QVector3D colors[] = {
           QVector3D(1.0f, 0.0f, 0.0f),           QVector3D(1.0f, 0.0f, 0.0f),
Linea 216: Linea 215:
           QVector3D(0.0f, 0.0f, 1.0f)           QVector3D(0.0f, 0.0f, 1.0f)
       };       };
-  +      
       m_program->enableAttributeArray( m_colAttr );       m_program->enableAttributeArray( m_colAttr );
       m_program->setAttributeArray( m_colAttr, colors );       m_program->setAttributeArray( m_colAttr, colors );
-  +      
       glDrawArrays(GL_TRIANGLES, 0, 3);       glDrawArrays(GL_TRIANGLES, 0, 3);
-  +      
       m_program->release();       m_program->release();
   }   }
  
-Per visualizzare quello che abbiamo creato ci serve un file mail.cpp+Per visualizzare quello che abbiamo creato ci serve un file main.cpp
  
   #include <QtGui/QGuiApplication>   #include <QtGui/QGuiApplication>
Linea 233: Linea 232:
   int main(int argc, char **argv) {   int main(int argc, char **argv) {
       QGuiApplication app(argc, argv);       QGuiApplication app(argc, argv);
-  +      
       GLWindow window;       GLWindow window;
       window.resize(640, 480);       window.resize(640, 480);
       window.show();       window.show();
-  +      
       return app.exec();       return app.exec();
   }   }
Linea 245: Linea 244:
 {{ :tutorial_qt:opengltut01.png?direct&400 |}} {{ :tutorial_qt:opengltut01.png?direct&400 |}}
  
-Tutti i file necessari sono contenuati nell'archivio [[http://ingegnerialibera.altervista.org/blog-file/opengltut01.zip|opengltut01.zip]]. +Tutti i file necessari sono contenuti nell'archivio [[http://ingegnerialibera.altervista.org/blog-file/opengltut01.zip|opengltut01.zip]].
  
-===== e poi... =====+===== Articoli correlati =====
  
-Nel prossimo articolo approfondiremo i comandi opengl sui quali in questo primo articolo non ci siamo molto soffermati. Vedremo quindi con maggior dettaglio cosa fanno i metodi setUniformValue(), enableAttributeArray() e setAttributeArray() della classe QOpenGLShaderProgram e ci concentreremo su metodi più efficienti di scambio delle informazioni con la GPU.+<blog related> 
 +  blog   default 
 +  tag    'tutorial qt opengl
 +</blog>
  
 ===== Per approfondire ===== ===== Per approfondire =====

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

Facebook Twitter Google+ Digg Reddit LinkedIn StumbleUpon Email