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 [2015/02/10 07:21]
mickele
tutorial_qt:opengl_01 [2015/05/05 14:43] (versione attuale)
mickele
Linea 1: Linea 1:
-====== Qt e OpenGLl: Introduzione ======+====== Qt e 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 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 13: Linea 13:
 ~~READMORE~~ ~~READMORE~~
  
-===== 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 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... ===== ===== 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 quest'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.
Linea 60: Linea 56:
 Abbiamo introdotto alcuni attributi 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 70: 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 79: 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 93: Linea 87:
 ===== Gli shader ===== ===== Gli shader =====
  
-Alla base della programmazione opengl moderna ci sono gli [[http://it.wikipedia.org/wiki/Shader|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.+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]].  Nella versione 5 delle Qt creiamo gli shader usando la classe [[http://qt-project.org/doc/qt-5/qopenglshaderprogram.html|QOpenGLShaderProgram]]. 
Linea 101: Linea 95:
 ===== Opengl secondo la Qt-way ===== ===== 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!+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 108: 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 118: 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 148: 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 155: 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 192: 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 212: 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 221: 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 238: 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 252: Linea 246:
 Tutti i file necessari sono contenuti 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]].
  
 +===== Articoli correlati =====
  
-===== e poi... ===== +<blog related> 
- +  blog   default 
-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.+  tag    'tutorial qt opengl
 +</blog>
  
 ===== Per approfondire ===== ===== Per approfondire =====
Linea 270: Linea 266:
   * [[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]]   * [[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.1423549290.txt.gz · Ultima modifica: 2015/02/10 07:21 da mickele

Facebook Twitter Google+ Digg Reddit LinkedIn StumbleUpon Email