Strumenti Utente



tutorial_qt:opengl_03_ibo_qopenglbuffer

Qt e OpenGL - Index Buffer Object con la classe QOpenGLBuffer

In questo articolo parleremo degli Index Buffer Object. Come già accaduto nel 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 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 precedenti articoli.

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 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

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 ingegnerialibera.altervista.org/blog-file/opengltut03-02.zip. Il risultato è lo stesso ottenuto al paragrafo precedente usando direttamente le API OpenGL.

Otteniamo lo stesso risultato del paragrafo precedente con la classe QOpenGLBuffer

Potrebbero interessarti anche...

Comments


tutorial_qt/opengl_03_ibo_qopenglbuffer.txt · Ultima modifica: 2015/05/05 14:42 da mickele

Facebook Twitter Google+ Digg Reddit LinkedIn StumbleUpon Email