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
tutorial_qt:opengl_01 [2013/09/14 17:42]
mickele [Il perché di tanti cambiamenti]
tutorial_qt:opengl_01 [2015/05/05 14:43] (versione attuale)
mickele
Linea 1: Linea 1:
-====== Tutorial Qt5 Opengl #1 ======+====== Qt OpenGL - Introduzione ======
  
-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 questa serie di articoli vedremo brevemente quali sono le novità introdotte analizzando alcuni esempi pratici.+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 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 =====
  
-I motivi di quello che sembrerebbe un restyling in realtà sono molto più profondi. Con le Qt5 si è cercato di utilizzare maggiormente le GPU per renderizzare la grafica delle interfacce. Per fare questo molte funzionalità che prima erano all'interno del modulo QtOpengl sono state estese al modulo QtGui. +Chi di voi proviene dalla versione 4 delle Qt noterà molti cambiamenti nell'impiego delle librerie Opengl all'interno del framework. I motivi di quello che sembrerebbe un restyling in realtà sono molto più profondi. Con le Qt5 si è cercato di utilizzare maggiormente la GPU per renderizzare la grafica delle interfacce. Per fare questo molte funzionalità che prima erano all'interno del modulo QtOpengl sono state estese al modulo QtGui. 
  
-Con l'occasione sono state scritte nuova classi: ad esempio QGlContext è diventata QOpenglContext, QGlShaderProgram p diventato QOpenglShaderProgam. Le nuova classi, rispetto alle precedenti hanno prestazioni leggermente migliori, hanno delle API più semplici e permettono l'impiego di un QOpenglContext su più superfici. Per approfondire l'argomento vi consiglio di leggere cosa dice in merito uno degli sviluppatori delle Qt all'indirizzo [[http://permalink.gmane.org/gmane.comp.lib.qt.devel/9065]].+Con l'occasione però sono state scritte nuova classi: ad esempio la classe QGlContext è stata riscritta nella classe QOpenglContext, QGlShaderProgram è diventata QOpenglShaderProgam etc. Le nuova classi, rispetto alle precedentihanno prestazioni leggermente migliori, hanno delle API più semplici e permettono l'impiego di un QOpenglContext su più superfici. Per approfondire l'argomento vi consiglio di leggere cosa dice in merito uno degli sviluppatori delle Qt all'indirizzo [[http://permalink.gmane.org/gmane.comp.lib.qt.devel/9065]].
  
-===== QGLWidget vs QWindow =====+~~READMORE~~
  
-La prima grande novità riguarda la classe base che useremo per creare la nostra superficie. Nel passato si faceva riferimento alla classe [[http://qt-project.org/doc/qt-5.1/qtopengl/qglwidget.html|QGLWidget]]. Poiché, che come dice il nome stesso, QGLWidget deriva dalla classe [[http://qt-project.org/doc/qt-5.1/qtwidgets/qwidget.html|QWidget]], eredita da questo i segnali e i metodi.+===== QGLWidget vs QWindow/QOpenGLWidget =====
  
-Per disegnare il nostro progetto dobbiamo creare una sottoclasse di QGLWIdget che reimplementa i metodi virtuali //initializeGL()//, //paintGL ()// //resizeGL( int width, int height )//.+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]].
  
-Posto che è comunque sempre possibile ricorrere alla classe QGLWidget anche con le Qt5, il nuovo approccio proposto prevede l'impiego della classe [[http://qt-project.org/doc/qt-5.1/qtgui/qwindow.html|QWindow]]. Si tratta di una classe di livello più basso rispetto a QWidget, ma non per questo con meno potenzialità.+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]]
  
-Con la classe QWindow abbiamo invece una flessibilità molto maggiore: possiamo decidere noi come e con quali metodi fornire i vari comandi. 
 ===== Partiamo da QWindow... ===== ===== Partiamo da QWindow... =====
  
-Iniziamo con un esempio concreto, creando un oggetto QWindow nel quale vogliamo disegnare un triangolo sfruttando le librerie opengl+Vediaemo come creare una classe derivata da QWindow per disegnare usando le API OpenGLNel farlo dobbiamo tener conto di due aspetti:  
- +  QWindow non deriva da QWidget, non avremo quindi a disposizione alcuni dei comodi strumenti presenti in QWidget 
-Creiamo la classe GLWindow che estende la classe QWindow (ovviamente) la classe [[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 contenuti in quest'ultima classe, indipendentemente dalla piattaforma su cui lavoriamo.+  * 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 vari comandi.
  
-Avremo allora un file header glwindow.h che conterrà+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à
  
 +  class QOpenGLShaderProgram;
   #include <QtGui/QWindow>   #include <QtGui/QWindow>
   #include <QtGui/QOpenGLFunctions>   #include <QtGui/QOpenGLFunctions>
Linea 34: Linea 37:
   public:   public:
       explicit GLWindow(QWindow *parent = 0);       explicit GLWindow(QWindow *parent = 0);
-  ... 
      
   private:   private:
       QOpenGLShaderProgram * m_program;       QOpenGLShaderProgram * m_program;
       QOpenGLContext * m_context;       QOpenGLContext * m_context;
-      QOpenGLPaintDevice * m_device; 
      
       GLuint m_posAttr;       GLuint m_posAttr;
       GLuint m_colAttr;       GLuint m_colAttr;
       GLuint m_matrixUniform;       GLuint m_matrixUniform;
 +      
 +      void exposeEvent(QExposeEvent *event);
 +      void resizeEvent(QResizeEvent *event);
 +      virtual void initialize();
 +      virtual void initShaders();
 +      virtual void paint();
 +      virtual void paintGL();      
   };   };
  
-Definiamo inoltre alcuni attributi.+Abbiamo introdotto alcuni attributi e metodi che analizzeremo strada facendo.
  
-Nel file glwindow.cpp avremo il costruttore+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) :
       QWindow(parent):       QWindow(parent):
-      context(0), +      m_context(0) { 
-      device(0) {+      
       setSurfaceType(QWindow::OpenGLSurface);       setSurfaceType(QWindow::OpenGLSurface);
 +      
   }   }
  
-nel quale ci limitiamo ad inizializzare due attributi e a dire alle Qt che intendiamo usare le opengl. +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
- +
-La gestione degli eventi in una QWindow è molto semplice, ci basta reimplementare due metodi virtuali: void exposeEvent(QExposeEvent *event) e void resizeEvent(QResizeEvent *event).  +
- +
-Il primo metodo viene chiamato ogni volta che cambia la visibilità della nostra superficie. Se è visibile, dovremo ridisegnare il triangolo+
  
   void GLWindow::exposeEvent(QExposeEvent *event) {   void GLWindow::exposeEvent(QExposeEvent *event) {
Linea 68: Linea 73:
   }   }
  
-Il metodo paint(), che vedremo tra poco, è quello che disegna il nostro triangolo.+Il metodo paint(), che vedremo tra poco, disegna il triangolo.
  
-Il metodo resizeEvent() viene chiamato ogni qualvolta la superficie viene ridimensionata. In tal caso doivremo 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) {
-      glViewport(0, 0, width(), height());+      if( m_context !=  0 ) 
 +          glViewport(0, 0, width(), height());
      
       if (isExposed())       if (isExposed())
Linea 79: Linea 85:
   }   }
  
-===== ... e aggiungiamo un po' di Opengl =====+===== Gli shader ===== 
 + 
 +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 =====
  
-Passiamo ora al metodo paint(), che è quello che disegna il triangolo.+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 modificatiPerciò, acquisita un po' di dimestichezza con le OpenGL, modificateli pure!
  
-I metodi che vedremo orasia come denomiinazione che come struttura e compiti possono cambiare, perciò se ritenete di doverli modificare, fate pure!+Analizziamo prima il metodo paint()il cuore delle operazioni di disegno
  
   void GLWindow::paint() {   void GLWindow::paint() {
       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 98: Linea 112:
           needsInitialize = true;           needsInitialize = true;
       }       }
 +      
       m_context->makeCurrent(this);       m_context->makeCurrent(this);
 +      
       if(needsInitialize) {       if(needsInitialize) {
           initialize();           initialize();
       }       }
-   +      
-      if (!m_device) +
-          m_device = new QOpenGLPaintDevice; +
- +
-      m_device->setSize( size() ); +
-  +
       paintGL();       paintGL();
 +      
       m_context->swapBuffers(this);       m_context->swapBuffers(this);
   }   }
  
-Alcuni comandi devono essere eseguiti una sola volta prima del primo disegno; li mettiamo nel metodo initialize()+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 127: Linea 136:
       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);       glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      
-      m_posAttr = m_d->program->attributeLocation("posAttr"); +      m_posAttr = m_program->attributeLocation("posAttr"); 
-      m_colAttr = m_d->program->attributeLocation("colAttr"); +      m_colAttr = m_program->attributeLocation("colAttr"); 
-      m_matrixUniform = m_d->program->uniformLocation("matrix");+      m_matrixUniform = m_program->uniformLocation("matrix");
   }   }
  
  
-Effettuaimo l'inizializzazione degli shaders nel metodo initShaders(). Abbiamo agigunto tra gli attributi di GLWindow un QOpenGLShaderProgram; ora gli associamo il codice degli shaders, contenuto in due file esterni+Il metodo initShaders() inizializza gli shaders eseguendo le seguenti operazioni: 
 +  * creiamo un oggetto QOpenGLShaderProgram 
 +  * associamo a questo oggetto il codice degli shaders, contenuto in due file esterni 
 +  * linkiamo il codice
  
   void GLWindow::initShaders() {   void GLWindow::initShaders() {
       m_context->makeCurrent(this);       m_context->makeCurrent(this);
-   +      
-      // Sovrasvcrive la codifica fintantoche' non sono compilati gli shaders +
-      setlocale(LC_NUMERIC, "C"); +
-  +
       m_program = new QOpenGLShaderProgram(this);       m_program = new QOpenGLShaderProgram(this);
-  +      
       // Compila lo shader dei vertici       // Compila lo shader dei vertici
-      if (!m_d->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_d->program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment.glsl"))+      if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment.glsl"))
           close();           close();
 +      
       // Linka shaders       // Linka shaders
-      if (!m_d->program->link())+      if (!m_program->link())
           close();           close();
-   
-      // Ripristina la codifica del sistema 
-      setlocale(LC_ALL, ""); 
   }   }
  
Linea 180: Linea 186:
  
  
-Ed infine i comandi per disegnare il nostro triangolo+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_d->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_d->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_d->program->setUniformValue(m_d->matrixUniform, matrix); +      m_program->setUniformValue(m_matrixUniform, matrix); 
-   +       
-      GLfloat vertices[] = { +      QVector2D vertices [] = { 
-          0.0f, 0.707f, +          QVector2D(0.0f, 0.707f)
-          -0.5f, -0.5f, +          QVector2D(-0.5f, -0.5f)
-          0.5f, -0.5f+          QVector2D(0.5f, -0.5f)
       };       };
-      GLfloat colors[] = { +       
-          1.0f, 0.0f, 0.0f, +      m_program->enableAttributeArray( m_posAttr ); 
-          0.0f, 1.0f, 0.0f, +      m_program->setAttributeArray( m_posAttr, vertices ); 
-          0.0f, 0.0f, 1.0f+       
 +      QVector3D colors[] = { 
 +          QVector3D(1.0f, 0.0f, 0.0f)
 +          QVector3D(0.0f, 1.0f, 0.0f)
 +          QVector3D(0.0f, 0.0f, 1.0f)
       };       };
-   +       
-      glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, 0, vertices); +      m_program->enableAttributeArraym_colAttr ); 
-      glVertexAttribPointer(m_colAttr, 3, GL_FLOAT, GL_FALSE, 0, colors); +      m_program->setAttributeArray( m_colAttr, colors ); 
-   +      
-      glEnableVertexAttribArray(0); +
-      glEnableVertexAttribArray(1); +
-  +
       glDrawArrays(GL_TRIANGLES, 0, 3);       glDrawArrays(GL_TRIANGLES, 0, 3);
 +      
 +      m_program->release();
 +  }
 +
 +Per visualizzare quello che abbiamo creato ci serve un file main.cpp
 +
 +  #include <QtGui/QGuiApplication>
      
-      glDisableVertexAttribArray(1); +  #include "glwindow.h"
-      glDisableVertexAttribArray(0);+
      
-      m_program->release();+  int main(int argc, char **argv) { 
 +      QGuiApplication app(argc, argv); 
 +       
 +      GLWindow window; 
 +      window.resize(640, 480); 
 +      window.show(); 
 +       
 +      return app.exec();
   }   }
  
Linea 224: Linea 244:
 {{ :tutorial_qt:opengltut01.png?direct&400 |}} {{ :tutorial_qt:opengltut01.png?direct&400 |}}
  
-Tutti i file necessari sono contenuati nell'archivio opengltut01.zip.+Tutti i file necessari sono contenuti nell'archivio [[http://ingegnerialibera.altervista.org/blog-file/opengltut01.zip|opengltut01.zip]].
  
-===== Per approfondire la programmazione opengl =====+===== Articoli correlati ===== 
 + 
 +<blog related> 
 +  blog   default 
 +  tag    'tutorial qt opengl' 
 +</blog> 
 + 
 +===== Per approfondire ===== 
 + 
 +==== opengl ====
  
   * [[http://en.wikibooks.org/wiki/OpenGL_Programming]]   * [[http://en.wikibooks.org/wiki/OpenGL_Programming]]
-  * [[http://www.songho.ca/opengl/gl_transform.html]]+  * [[http://www.songho.ca/opengl/]]
   * [[http://ogldev.atspace.co.uk/index.html]]   * [[http://ogldev.atspace.co.uk/index.html]]
 +  * [[http://antongerdelan.net/opengl/]]
 +
 +==== Qt e opengl ====
 +
   * [[http://www.kdab.com/opengl-in-qt-5-1-part-5/]] (contiene i link alle parti precedenti)   * [[http://www.kdab.com/opengl-in-qt-5-1-part-5/]] (contiene i link alle parti precedenti)
 +  * [[http://professor.ufabc.edu.br/~joao.gois/index.php?n=Courses.ComputerGraphicsWithQt]]
 +
 +===== Potrebbero interessarti anche... =====
 +
 +Un elenco degli altri articoli disponibili sull'argomento:
 +<blog related>
 +</blog>
  

tutorial_qt/opengl_01.1379173379.txt.gz · Ultima modifica: 2013/09/14 17:42 da mickele

Facebook Twitter Google+ Digg Reddit LinkedIn StumbleUpon Email