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
Prossima revisione Entrambe le parti successive la revisione
tutorial_qt:opengl_01 [2013/09/14 17:50]
mickele [Partiamo da QWindow...]
tutorial_qt:opengl_01 [2015/02/10 07:21]
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 delle 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.
  
 ===== 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]]. 
 + 
 +~~READMORE~~
  
 ===== QGLWidget vs QWindow ===== ===== QGLWidget vs QWindow =====
  
-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]].+La prima grande novità riguarda la classe base che useremo per creare la nostra superficie. Nel passato si faceva riferimento [[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]]. +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]]. 
  
-Una prima differenza è nel fatto che QGLWidget deriva da QWidget, QWindow no. Non avremo uindi a disposizione alcuni dei comodi metodi presenti in QWidget.+Quali le differenze tra le due classi?
  
-Un altra differenza riguarda le modalità di impiego. Derivando QGLwidget era necessario reimplementare i metodi virtuali //initializeGL()////paintGL ()// e //resizeGL( int widthint height )//. Con la classe QWindow abbiamo invece una flessibilità molto maggiore: possiamo decidere noi come e con quali metodi fornire i vari comandi. +Una prima differenza è che QGLWidget deriva da QWidgetQWindow nonon avremo quindi a disposizione alcuni dei comodi strumenti presenti in QWidget.
-===== Partiamo da QWindow..=====+
  
-Iniziamo con un esempio concretocreando una classe derivata di QWindow nel quale vogliamo disegnare un triangolo.+Un'altra differenza riguarda le modalità con cui andremo a scrivere le sottoclassi. Derivando QGLwidget era necessario ridefinire 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..=====
  
-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.+Iniziamo con un esempio concreto, creando una classe derivata di QWindow nella quale vogliamo disegnare un triangolo.
  
-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 41:
   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();      
   };   };
  
-Inoltre, come potete vedere, introduciamo alcuni attributi che analizzeremo strada facendo.+Abbiamo introdotto alcuni attributi e metodi che analizzeremo strada facendo.
  
-Il costruttore di GLWindow si limita ad inizializzare due attributi 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 dire alle Qt che intendiamo disegnare sulla superficie con le 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);
 +      
   }   }
  
 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).  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). 
  
-Il primo iene chiamato ogni volta che cambia la visibilità della nostra superficie. Se è visibile, dovremo ridisegnare il triangolo. 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 68: Linea 81:
 Il metodo paint(), che vedremo tra poco, è quello che disegna il triangolo. Il metodo paint(), che vedremo tra poco, è quello che 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 77: Linea 91:
   }   }
  
-===== ... 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. A partire dalle Opengl 2.0  le operazioni compiute dalla GPU sono divenute personalizzabili: ora le GPU sono programmabili, e gli shader sono i programmi che carichiamo sulle nostre 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() {
Linea 102: Linea 124:
           initialize();           initialize();
       }       }
-   
-      if (!m_device) 
-          m_device = new QOpenGLPaintDevice; 
- 
-      m_device->setSize( size() ); 
      
       paintGL();       paintGL();
Linea 113: Linea 130:
   }   }
  
-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() inizializza m_context e chiama il metodo initialize() che si occupa di impostare l'ambiente opengl.
  
   void GLWindow::initialize() {   void GLWindow::initialize() {
Linea 125: Linea 142:
       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. Più in particolare, nel metodo initShaders()
 +  * 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 178: Linea 192:
  
  
-Ed infine i comandi per disegnare il nostro triangolo+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.
  
   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;
Linea 191: Linea 205:
       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, +
-          0.0f, 1.0f, 0.0f, +
-          0.0f, 0.0f, 1.0f+
       };       };
      
-      glVertexAttribPointer(m_posAttr, 2, GL_FLOAT, GL_FALSE, 0, vertices); +      m_program->enableAttributeArray( m_posAttr ); 
-      glVertexAttribPointer(m_colAttr3, GL_FLOAT, GL_FALSE, 0, colors);+      m_program->setAttributeArraym_posAttrvertices );
      
-      glEnableVertexAttribArray(0); +      QVector3D colors[] = { 
-      glEnableVertexAttribArray(1);+          QVector3D(1.0f, 0.0f, 0.0f)
 +          QVector3D(0.0f, 1.0f, 0.0f), 
 +          QVector3D(0.0f, 0.0f, 1.0f) 
 +      }; 
 +   
 +      m_program->enableAttributeArraym_colAttr ); 
 +      m_program->setAttributeArray( m_colAttr, colors );
      
       glDrawArrays(GL_TRIANGLES, 0, 3);       glDrawArrays(GL_TRIANGLES, 0, 3);
-   
-      glDisableVertexAttribArray(1); 
-      glDisableVertexAttribArray(0); 
      
       m_program->release();       m_program->release();
 +  }
 +
 +Per visualizzare quello che abbiamo creato ci serve un file mail.cpp
 +
 +  #include <QtGui/QGuiApplication>
 +  
 +  #include "glwindow.h"
 +  
 +  int main(int argc, char **argv) {
 +      QGuiApplication app(argc, argv);
 +  
 +      GLWindow window;
 +      window.resize(640, 480);
 +      window.show();
 +  
 +      return app.exec();
   }   }
  
Linea 222: Linea 250:
 {{ :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 =====+ 
 +===== e poi... ===== 
 + 
 +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. 
 + 
 +===== 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]]
 + 
  

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

Facebook Twitter Google+ Digg Reddit LinkedIn StumbleUpon Email