«[Figlio dell'uomo] Porgi l'orecchio e ascolta le parole di KGB
e applica la tua mente alla SUA istruzione
» Pv. 22,17

Qui si straparla di vari argomenti:
1. Il genere dei pezzi è segnalato da varie immagini, vedi Legenda
2. Istruzioni per i nuovi lettori (occasionali e non) qui
3. L'ultimo corto è questo

venerdì 11 settembre 2015

KGB vs la OpenGL (5/??)

Ottavo giorno
Ieri avevo un po' le pile scariche ma ho voluto comunque iniziare a leggere la lezione sui cosiddetti frame buffer. Alla prima lettura ho capito solo il principio generale: usando specifiche istruzioni si può istruire la scheda video in maniera che crei le proprie immagini non sul “video” ma in apposite aree di memoria, i frame buffer appunto, che poi possono essere successivamente rielaborate o usate come se fossero immagini (texture). Per capirci posso usare questa tecnica per, ad esempio, riempire il contenuto di uno specchio, oppure potrei far apparire in un riquadro le immagini riprese da una telecamera...
In pratica la pletora di nuove chiamate alla OpenGL mi ha però confuso. L'autore del minicorso deve poi stare iniziando a stufarsi e tralascia qua e là qualche dettaglio che evidentemente ritiene banale.
Comunque non mi sono preoccupato troppo: con gli stencil avevo capito ancora meno ma poi, giocando con l'esempio pratico, mi si era chiarito tutto.
Così ho copiato e incollato il codice per creare un frame buffer, senza comunque utilizzarlo, e ho provato a vedere cosa succedeva. Risultato: finestra vuota.
Finestra vuota significa in genere che gli sheader hanno avuto un problema nel compilare il proprio codice ma, in questo caso, era il risultato voluto: il mio cubo rotante non veniva più “disegnato” sullo schermo ma sul frame buffer e per questo non vedevo niente...

Ma era veramente questo il caso? Nel dubbio ho provato a riattivare la modalità “normale”. Secondo il minicorso sarebbe in teoria bastato aggiungere la linea... glBindFramebuffer(GL_FRAMEBUFFER, 0);
...dopo aver creato (e non usato) il frame buffer.
Risultato ancora finestra vuota ma adesso significava che qualcosa non andava! Come detto ero però piuttosto stanco e così ho lasciato perdere...

Nono giorno
Per prima cosa ho cercato di scoprire dov'era il problema nel nuovo codice: l'ho tutto commentato, ho ricompilato e lanciato. La finestra mostrava di nuovo il cubo ruotante col gattino: ottimo.
Poi ho iniziato a scommentare un paio di linee del frame buffer e subito la finestra è tornata vuota. Così ho osservato bene le linee scommentate e i miei sospetti si sono concentrati su:
glBindTexture(GL_TEXTURE_2D, texColorBuffer);

Devo fare qui un piccolo inciso sulle funzioni “glBindXXX” della OpenGL. Quando si chiama una funzione della libreria OpenGL che agisce su, ad esempio, una texture per me sarebbe naturale specificare la texture da elaborare fra i parametri. Invece no, nella OpenGL la texture da usare è implicitamente quella attiva: e per rendere attiva una texture si usa appunto la funzione glBindTexture (che secondo me si sarebbe dovuta chiamare glEnableTexture!).
Suppongo che il motivo di questa scelta sia massimizzare l'efficienza, evitando di passare più volte un parametro sempre uguale (nel mio esempio la texture), anche a scapito della chiarezza...

Così ho immaginato che non bastasse chiamare glBindFrameBuffer ma che servisse anche aggiornare la texture attiva: e infatti, aggiungendo una chiamata alla glBindTexture con la texture con l'immagine del gattino, il problema si è risolto.
Ora posso creare il mio frame buffer, non utilizzarlo (!), e ripristinare la situazione originale.

Le istruzioni del minicorso si sono fatte un po' vaghe: se ho ben capito dovrei adesso far apparire un rettangolo 2D davanti al mio cubo roteante. In teoria non dovrebbe essere difficile: si tratta di replicare tutto il codice mischiando in pratica il sorgente del cubo con quello del rettangolo. L'autore è sarcastico: già notato in precedenza nei commenti, ignora al 100% le domande più stupide ed elogia quelle intelligenti, ma adesso è evidente.
Alla fine il mio codice scritto da zero funziona e il mio rettangolo appare correttamente: il problema è che non si vede il cubo rotante. Chiaramente è colpa delle istruzioni fornite dal minicorso su come alternare i due disegni. Sicuramente l'errore sarà mio ma come ho già detto l'autore adesso tende a tralasciare molti dettagli...
Non ho voglia di spidocchiare il mio codice confrontandolo con quello fornito di esempio e, anzi, mi limito a riadattare quest'ultimo (solito problema della libreria per la gestione delle finestre).
Sorpresa: in questo caso c'è il cubo rotante ma il rettangolo non si vede!
Un po' annoiato decido di lasciar perdere per il resto della serata...

Decimo giorno
Mi sono limitato a cercare di capire cosa facesse e come funzionasse il codice dell'esempio.
Alla fine sono arrivato alla conclusione che il rettangolo non si vede perché viene direttamente usato come destinazione dell'immagine del cubo rotante: per rendersene conto basta deformare il rettangolo cambiando le coordinate di uno solo dei suoi vertici. Il risultato è che anche il cubo viene a sua volta deformato seguendo la prospettiva della “tela” (texture) su cui è disegnato.

Successivamente mi sono limitato a compilare delle modifiche del codice dell'esempio per ottenere degli effetti di post processing: lo sfocamento, il bianco e nero e l'algoritmo di Sobel per l'evidenziamento dei bordi.
Di seguito un'immagine di questo terzo effetto:
È buffo: dal vivo il cubo ruota con l'usuale fluidità ma, per qualche motivo, la schermata lo ha ripreso in diversi momenti della rotazione chiaramente individuabili nelle successive strisce parallele....

Comunque, come giustamente evidenzia l'autore, è impressionante la potenza di queste nuove schede grafiche. Ad esempio, per l'effetto di sfocatura, per ogni singolo fotogramma del cubo rotante, si analizza per ciascun pixel dell'immagine risultante, gli 80 pixel che lo circondano e se ne calcola la media delle componenti del colore. Tutto questo è possibile grazie al parallelismo massiccio delle GPU.

Nessun commento:

Posta un commento