====== Qt e OpenGL - Index Buffer Object con la classe QOpenGLBuffer ====== In questo articolo parleremo degli Index Buffer Object. Come già accaduto nel [[tutorial_qt:opengl_02_vbo_qopenglbuffer|precedente articolo]], prima vedremo come usare questo caratteristica utilizzando direttamente le API OpenGL, e, a seguire, con gli strumenti presenti nelle librerie Qt. ===== A cosa servono gli Index Buffer Object ===== Per capire a cosa servano gli index Buffer Object (d'ora in poi IBO) riferiamoci al caso concreto del disegno di un cubo. Utilizzando gli strumenti visti nel [[tutorial_qt:opengl_02_vbo_qopenglbuffer|precedente articolo]], per disegnare le facce che delimitano un cubo con triangoli, dovremmo creare un VBO contenente le coordinate di 36 punti (6 facce * 2 triangoli * 3 punti), ripetendo più volte le coordinate degli otto vertici che geometricamente definiscono il cubo. L'idea dietro gli IBO è molto semplice: * carico un VBO contenente, nel nostro caso, i soli 8 vertici effettivamente necessari * disegno le facce del cubo comunicando volta per volta alla GPU i soli indici dei vertici che intendo disegnare. L'IBO è il buffer nel quale individuo gli indici dei vertici. Trattandosi di indici, tipicamente l'IBO conterrà interi senza segno (GLushort piuttosto che GLuint). ===== Gli IBO in generale ===== Vediamo ora all'opera gli IBO utilizzando direttamente le API OpenGL. Prenderò come base i sorgenti di uno dei [[tutorial_qt:opengl_01bis|precedenti articoli]]. ~~READMORE~~ Prima di tutto creiamo i VBO per le coordinate dei vertici e per i colori // vettore contenete le coordinate dei vertici double l = 1.5/2.0; GLfloat vertexData[] = { GLfloat(-l), GLfloat(-l), GLfloat(-l), GLfloat(1.0), GLfloat(l), GLfloat(-l), GLfloat(-l), GLfloat(1.0), GLfloat(l), GLfloat(l), GLfloat(-l), GLfloat(1.0), GLfloat(-l), GLfloat(l), GLfloat(-l), GLfloat(1.0), GLfloat(-l), GLfloat(-l), GLfloat(l), GLfloat(1.0), GLfloat(l), GLfloat(-l), GLfloat(l), GLfloat(1.0), GLfloat(l), GLfloat(l), GLfloat(l), GLfloat(1.0), GLfloat(-l), GLfloat(l), GLfloat(l), GLfloat(1.0) }; // genera il VBO glGenBuffers(1, &m_vertexVBO); // attiva il VBO glBindBuffer(GL_ARRAY_BUFFER, m_vertexVBO); // carica nella memoria della GPU i valori contenuti in vertexData glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW); // disattiva il VBO glBindBuffer(GL_ARRAY_BUFFER, 0); // vettore contenete i colori dei vertici GLfloat colorData[] = { GLfloat(1.0), GLfloat(0.0), GLfloat(0.0), GLfloat(1.0), GLfloat(0.0), GLfloat(1.0), GLfloat(0.0), GLfloat(1.0), GLfloat(0.0), GLfloat(0.0), GLfloat(1.0), GLfloat(1.0), GLfloat(1.0), GLfloat(1.0), GLfloat(0.0), GLfloat(1.0), GLfloat(1.0), GLfloat(0.0), GLfloat(1.0), GLfloat(1.0), GLfloat(0.0), GLfloat(1.0), GLfloat(1.0), GLfloat(1.0), GLfloat(1.0), GLfloat(1.0), GLfloat(1.0), GLfloat(1.0), GLfloat(0.1), GLfloat(0.1), GLfloat(0.1), GLfloat(1.0) }; // genera il VBO glGenBuffers(1, &m_colorVBO); // attiva il VBO glBindBuffer(GL_ARRAY_BUFFER, m_colorVBO); // carica nella memoria della GPU i valori contenuti in vertexData glBufferData(GL_ARRAY_BUFFER, sizeof(colorData), colorData, GL_STATIC_DRAW); // disattiva il VBO glBindBuffer(GL_ARRAY_BUFFER, 0); Passiamo ora all'IBO. Come già per il VBO, individuiamo il buffer con un'attributo intero senza segno dichiarato privato nell'header della classe class GLWidget: ... { ... private: ... GLuint m_IBO ... Nel metodo intializeGL() creiamo l'IBO GLushort indices[] = { 0, 1, 2, 0, 2, 3, 0, 1, 4, 1, 5, 4, 1, 2, 6, 1, 6, 5, 2, 6, 3, 3, 6, 7, 0, 3, 4, 3, 7, 4, 4, 5, 7, 5, 6, 7 }; glGenBuffers(1, &m_IBO); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), &indices[0], GL_STATIC_DRAW); Per i VBO il primo argomento dei comandi glBindBuffer e glBufferData era pari al parametro ARRAY_BUFFER; per creare un IBO sostituiamo ARRAY_BUFFER con GL_ELEMENT_ARRAY_BUFFER. L'altra differenza sostanziale è presente nella fase di disegno. Infatti nel metodo paintGL(), dopo aver attivato i VBO e l'IBO, disegneremo i triangoli con glDrawElements invece che con glDrawArray // Attiviamo il VBO dei vertici glBindBuffer(GL_ARRAY_BUFFER, m_vertexVBO); // attiva il VBO glEnableVertexAttribArray( m_posAttr ); glVertexAttribPointer( m_posAttr, 4, GL_FLOAT, GL_FALSE, 0, 0 ); // Attiviamo il VBO dei colori glBindBuffer(GL_ARRAY_BUFFER, m_colorVBO); // attiva il VBO glEnableVertexAttribArray( m_colAttr ); glVertexAttribPointer( m_colAttr, 4, GL_FLOAT, GL_FALSE, 0, 0 ); // attiviamo l'IBO glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO); // Disegna i triangoli glDrawElements( GL_TRIANGLES, // modalita' disegno 36, // numero indici GL_UNSIGNED_SHORT, // tipologia degli indici 0 // offset tra gli indici ); Al link [[http://ingegnerialibera.altervista.org/blog-file/opengltut03-01.zip|ingegnerialibera.altervista.org/blog-file/opengltut03-01.zip]] trovate il codice sorgente riepilogativo di quanto visto, di modo da permettervi di studiarlo con calma. Compilando tale codice vedrete un cubo multicolore che ruota {{ :tutorial_qt:opengltut03-01.png |Un cubo multicolore realizzato con gli IBO}} ===== Gli IBO con la classe QOpenGLBuffer ===== Vediamo ora come implementare l'IBO con la classe QOpenGLBuffer. Nella classe GLWidget dichiareremo l'attributo privato m_IBO, puntatore alla classe QOpenGLBuffer class GLWidget: ... { ... private: ... QOpenGLBuffer * m_IBO; ... Per la creazione del VBO abbiamo invocato il costruttore della classe QOpenGLBuffer con il parametro QOpenGLBuffer::VertexBuffer, per creare un IBO usiamo invece il parametro QOpenGLBuffer::IndexBuffer. Nel metodo initializeGL() aggiungiamo pertanto GLushort indices[] = { 0, 1, 2, 0, 2, 3, 0, 1, 4, 1, 5, 4, 1, 2, 6, 1, 6, 5, 2, 6, 3, 3, 6, 7, 0, 3, 4, 3, 7, 4, 4, 5, 7, 5, 6, 7 }; m_IBO = new QOpenGLBuffer( QOpenGLBuffer::IndexBuffer ); m_IBO->create(); m_IBO->setUsagePattern( QOpenGLBuffer::StaticDraw ); m_IBO->bind(); m_IBO->allocate( indices, sizeof(indices)); m_IBO->release(); Il vettore indices contiene l'elenco degli indici dei triangoli che delimitano il cubo che stiamo disegnando. In paintGL(), per il disegno del cubo, dopo avere attivato i VBO delle coordinate e dei colori, attiviamo l'IBO con il metodo bind() // Attiviamo il VBO dei vertici m_vertexVBO->bind(); m_program->enableAttributeArray( m_posAttr ); m_program->setAttributeBuffer( m_posAttr, GL_FLOAT, 0, 4); m_vertexVBO->release(); // Attiviamo il VBO dei colori m_colorVBO->bind(); m_program->enableAttributeArray( m_colAttr ); m_program->setAttributeBuffer( m_colAttr, GL_FLOAT, 0, 4); m_colorVBO->release(); // Attiviamo l'IBO m_IBO->bind(); // Disegniamo i triangoli glDrawElements( GL_TRIANGLES, // modalita' 36, // numero indici GL_UNSIGNED_SHORT, // tipologia degli indici 0 // offset tra gli indici ); Il codice finale è disponibile al link [[http://ingegnerialibera.altervista.org/blog-file/opengltut03-02.zip|ingegnerialibera.altervista.org/blog-file/opengltut03-02.zip]]. Il risultato è lo stesso ottenuto al paragrafo precedente usando direttamente le API OpenGL. {{ :tutorial_qt:opengltut03-02.png |Otteniamo lo stesso risultato del paragrafo precedente con la classe QOpenGLBuffer}} ===== Potrebbero interessarti anche... ===== Un elenco degli altri articoli disponibili sull'argomento: