Quarto giorno
Per ritrovare abbastanza morale da tornare all'attacco mi è occorsa circa una settimana. Soprattutto mi aveva abbattuto il fatto di averci capito poco negli esempi di OpenGL veri e propri: sono abituato ad avere problemi con le difficoltà “tecniche” (quelle che odio) ma non mi aspettavo di non capire completamente ciò che realmente mi interessava...
Così ieri ho seguito il consiglio del mio amico ingegnere e ho provato a guardarmi un altro minicorso: non mi sono pigramente accontentato del primo collegamento sputato da Google ma ho scelto il secondo, cioè Open Gl Introduction!
Forse, si potrebbe obiettare, avrei dovuto cercare un corso con maggiore attenzione: il problema è che, per capire se sia fatto bene, bisogna o conoscere già la materia (non è il mio caso) o è comunque necessaria un'analisi approfondita e, allora, tanto vale provarlo direttamente...
Questo nuovo minicorso dà però (forse giustamente) per scontato che lo studente sappia crearsi l'ambiente di sviluppo e in particolare istruire l'IDE affinché usi specifiche librerie.
E io, per queste problematiche tecniche (che odio), sono vergognosamente scarso: fortunatamente ho scoperto che delle librerie base richieste una era la GLEW che già mi funzionava nell'ambiente di sviluppo del precedente minicorso; la seconda (usata solo per creare la finestra e inizializzare la OpenGL) poteva essere scelta fra tre opzioni suggerite fra cui la GLFW e anche questa già mi funzionava...
Gli esempi del codice del nuovo minicorso usano però un'altra libreria (SFML) per gestire le finestre ma ho pensato che avrei potuto sostituirne le chiamate: così, invece di crearmi un nuovo ambiente di lavoro ho deciso di riutilizzare quello già funzionante del vecchio minicorso.
Come detto ho dovuto sostituire le chiamate alla SFML con quelle alla GLFW ma per il resto, in teoria, non avrei dovuto avere problemi e, infatti:
Segmentation Fault
È quello che mi piace del C: mi dà la sensazione che la macchina si fidi ciecamente di me ed esegua, anche a suo danno, tutto ciò che le ordino...
Dopo un po' di spidocchiamento (*1), sostanzialmente commentando il codice che avevo aggiunto alla base di un vecchio esempio del minicorso precedente, ho scoperto il problema. Nel mio pasticciare fra i due codici sorgenti, un copia e incolla di pezzettini vari fra un archivio e l'altro, mi ero dimenticato una linea che non mi pareva importante:
glewExperimental = GL_TRUE;
Che, più che abilitare funzioni “sperimentali” (come superficialmente avevo pensato), permette di usare quelle oggi ormai comuni e impedisce di usare quelle obsolete...
Comunque, sistemato questo dettaglio, sono riuscito a compilare il primo esempio!
Col secondo esempio ho però immediatamente incontrato un nuovo problema: aggiungendo la banale linea...
#include <chrono>
...ricevevo uno strano messaggio di errore che, in pratica, mi obiettava che le funzioni per il “c++11” non erano abilitate. Dopo la solita ricerca su Google ho così imparato che nel 2011 il C++ ha subito un nuovo aggiornamento del linguaggio mentre il mio compilatore si aspettava codice scritto seguendo le specifiche del 1998...
In teoria il problema era banale: sarebbe bastato “dire” al compilatore di aspettarsi (e quindi compilare) il C++ del 2011 e non quello del 1998... Peccato che non sapessi come fare!
Il problema è che nel mio ambiente di sviluppo non uso direttamente il compilatore ma premo semplicemente il tasto Build della IDE!
La IDE a sua volta utilizza un programmino di 775 linee, scritto in un linguaggio che non conosco (CMAKE), per effettuare tutte le operazioni necessarie.
La soluzione mi è stata, come al solito, fornita da Google con una ricerca del tipo “CMAKE enable c++11”:
add_definitions(-std=c++11)
E con questa modifica, incollata nello script di (ora) 776 linee, sono riuscito anche a compilare il secondo esempio!
Non solo: al termine della prima lezione c'erano ben tre esercizi non banali né troppo difficili ma comunque piuttosto significativi che mi sono riusciti senza problemi!
Quinto giorno
Per il giorno dopo (*2) mi ero lasciato il tipico compito tecnico che odio (perché non mi riesce). La seconda lezione del minicorso richiedeva infatti di usare la libreria SOIL per caricare archivi di immagini in svariati formati.
Come detto questo minicorso dà per scontato che lo studente sappia compilare e istruire la propria IDE per risolvere queste semplici problematiche e, quindi, si limitava a dire di inserire nei giusti percorsi gli header e la libreria SOIL vera e propria.
In realtà si tratta di compiti veramente semplici che FORSE, dopo tutti questi giorni di smanettamento, saprei fare anch'io...
Così non mi sono preoccupato troppo, sono andato sul sito di SOIL, e mi sono scaricato il sorgente: mi immaginavo di trovare le istruzioni per la compilazione ma, forse è colpa mia, non ne ho visto traccia. In pratica si trattava di soli tre o quattro archivi da compilare insieme e così mi son detto: “Vabbè, ci penso io...”
Non entro nei dettagli delle mie prove ma non mi è riuscito venirne a capo: ho già scritto che odio questo tipo di problemi? E che non mi riescono, l'ho scritto?
Alla fine, dopo la solita ricerca su Google, ho installato la versione “dev” di tale libreria con Synaptic (era cioè già disponibile nell'archivio di Ubuntu).
L'unico problemino che mi è rimasto è stato cambiare la linea
#include <SOIL.h>
in
#include <SOIL/SOIL.h>
In questa maniera ho potuto iniziare a giocare con le texture (in pratica le immagini) del minicorso.
I tre esercizi finali questa volta erano più impegnativi. Il primo in realtà era facile ma a causa di una mia stupida distrazione mi ha richiesto più tempo del previsto.
L'esercizio richiedeva di alternare due immagini sovrapposte (canino e gattino) sfumandole l'una sull'altra in base al tempo: compito molto più facile di quanto si potrebbe pensare perché si riduceva a variare nel tempo un unico parametro di una funzione fra 0 e 1.
Devo aggiungere una precisazione tecnica che per lavorare con la OpenGL è necessario anche scrivere degli speciali programmini, chiamati shader, che girano sulla GPU della scheda grafica. La funzione in questione viene eseguita proprio in uno shader ma il parametro le deve essere passato dall'esterno. Per passare una variabile dal programma principale a uno shader c'è da seguire un semplice protocollo che consiste nel chiamare un paio di funzioni della OpenGL...
Io scrivo immediatamente le modifiche necessarie e... non mi funziona.
Ricontrollo quanto scritto ma mi pare tutto a posto: avevo modificato lo shader per ricevere il nuovo parametro e nel codice principale avevo chiamato le giuste funzioni della OpenGL...
Ci perdo qualche altro minuto e poi vado a controllare la soluzione: è “uguale” alla mia!
L'unica differenza è che io eseguo dei calcoli matematici prima di passare il parametro mentre nel codice della soluzione, gli stessi calcoli, vengono fatti eseguire allo shader. Non riesco a capire e provo a fare vari esperimenti senza capirci niente. Ah, devo aggiungere che gli shader non danno messaggi di errore (da qualche parte avevo letto che è disponibile un archivio di log ma non ricordavo come fare per accedervi...) e quindi quando hanno qualche problema...
Alla fine però l'occhio mi è caduto sul nome che avevo scelto per il parametro (“mix”) e il nome della funzione (“mix”)... Ovviamente mi è bastato cambiare nome al mio parametro per risolvere il problema!
Il secondo esercizio chiedeva «Draw a reflection of the kitten in the lower half of the rectangle.»
Ho usato una diversa tecnica da quella proposta nella soluzione ottenendo un risultato diverso ma, secondo me, migliore.
Ai lettori il giudizio:
Versione ufficiale
Versione mia
Il terzo esercizio è stato l'unico che mi ha dato da pensare: il problema non era tanto di programmazione quanto matematico. Si doveva ottenere nel riflesso del gattino un effetto di onde animato...
Comunque dopo diverse prove (ed errori) facendo un passo alla volta (*3) sono riuscito a ottenere una soluzione sostanzialmente identica a quella ufficiale.
Ho così chiuso la giornata con un successo informatico che mi ha dato molta soddisfazione ed entusiasmo.
Nota (*1): “spidocchiamento” è la mia traduzione del più noto debugging. Avevo pensato anche a “sbacamento”, visto che è già piuttosto comune usare “baco” per “bug”, ma non mi piaceva come suonava...
Nota (*2): ieri rispetto a oggi mentre scrivo, ma qualche giorno fa rispetto alla pubblicazione di questo pezzo!
Nota (*3): prima ho realizzato l'ondulazione fissa, cioè immobile, in base alla coordinata Y dell'immagine e, solo successivamente, a essa ho aggiunto il movimento in funzione del tempo...
alla prima stazione
1 ora fa
Nessun commento:
Posta un commento