Flight Around!

Antonio Conteduca - A.A. 2017-2018
Relazione progetto del corso di "Grafica" del prof. Casciola

L'obiettivo del progetto è la realizzazione di un semplice videogioco del tipo "automotive 3d game" che racchiuda le principali argomentazioni affrontate nel corso. Il software è pensato per ambiente UNIX e sviluppato con il linguaggio C++, utilizzandolo col paradigma ad oggetti. La gestione della grafica è resa possibile dalle librerie SDL e OpenGL. In particolare la prima ha il compito di gestire finestre e ricevere segnali esterni, mentre la seconda si preoccupa principalmente di amministrare oggetti grafici 3D. L'interattività con l'utente è affidata ad un ciclo degli eventi, che tramite polling(chiamata SDL_PollEvent(e) della libreria OpenGL) rileva gli input esterni(SDL_Event) e reagisce in base a questi. Il progetto si basa e prende spunto dal codice usato per il "progettoCar" mostrato a lezione.


GAMEPLAY

Il gioco consiste nel pilotare un aereo con l'obiettivo di accumulare più punti possibile. Esistono due modalita' di gioco: Time Version, accumula più punti entro i due minuti, e Fuel Version, accumula punti prima della fine del carburante. I punti vengono accumulati mediante le monete poste all'interno del gioco. E' prevista una terza modalita' di gioco (work in progress) che prevede la possibilita' di fare rifornimento (sez. Conclusioni e sviluppi futuri). Sono presenti premi speciali nel caso in cui vengano presi i cubi: incremento velocita', magnete e bonus di 30 punti.

Menù iniziale del gioco

Come si gioca?

W: Sali
S: Scendi
A: Sinistra
D: Destra
SPACE: Accellera
P: Pausa (solo fuel version)
R: Cambia Camera
MOUSE: Gestione Camera
ESC: Torna Indietro
F1: On/Off Wireframe
F2: On/Off Pencil
F3: Flat/Gouraud Shading
F4:Luce Direzionale/Puntiforme
F11: Debug Info

NB. La pausa funziona per la versione "fuel" del gioco in quanto la modalità a tempo non prevede le pause. Tale funzione verrà estesa nei lavori futuri.


Camera Iniziale (dietro)

Camera Interna

Camera dall'alto

Camera frontale

Camera gestita dal Mouse

Geometria 3D e vista

Le trasformazioni Window-Viewport sono gestite automaticamente dalla libreria. Nel progetto è stato necessario settare la Viewport tramite la chiamata glViewPort, la quale setta il numero corretto di pixel nel Frame Buffer.

Le coordinate dell'occhio sono moltiplicate con la matrice GL_PROJECTION che definisce il volume di vista (frustum) e come i dati dei vertici sono proiettati. Gli oggetti vengono visualizzati in proiezione prospettica, settando i prametri con la funzione gluPerspective. In tal modo viene effettuato il Clipping 3D rispetto al Volume di Vista.

Le trasformazioni di modellazione hanno l'obiettivo di ricavare le coordinate mondo di un particolare oggetto/vertice ed agiscono sulla matrice GL_MODELVIEW. Solitamente sono composta dalle chiamate glScale, glRotate e glTranslate, nell'ordine specificato, e comprese tra un glPushMatrix e glPopMatrix (per non intaccare lo stato dello stack dopo la trasformazione) per circoscrivere la trasformazione di modellazione all'oggetto desiderato.

Le coordinate dopo il clipping vengono normalizzate e infine passate al processo di rasterizzazione della pipeline di OpenGL. Viene usata la funzione glViewport() per definire il rettangolo dell'area di rendering dell'immagine finale.
Per muovere la telecamera la matrice GL_MODELVIEW viene moltiplicata con una o più matrici di trasformazione. Nel progetto sono stati usati glTranslate e glRotate.
          
              glViewport(0, 0, scrW, scrH); 
              glMatrixMode(GL_PROJECTION); 
              glLoadIdentity(); 
              gluPerspective(70, ((float) scrW) / scrH, 0.01, 10000); 
              glMatrixMode(GL_MODELVIEW);
              glLoadIdentity();
              setCamera(); // cambia parametri a seconda del tipo di camera selezionata 
          
        

Illuminazione

E' presente una luce direzionale in modo da rappresentare la luce del sole. Tale luce è stata settata usando la funzione glLightfv. A seconda del tipo di mesh la luce si comporta in modo diverso; ciò è dovuto all'abilitazione del ColorMaterial che permette il settaggio dei parametri del materiale di ogni singola mesh. Il modello di illuminazione usato è quello di Phong composto da tre componenti: ambiente, riflessione diffusa e speculare. Tali componenti sono i parametri che si settano per definire un materiale.


Illuminazione sulla mesh Aereo


Di seguito è mostrato il codice utilizzato nel modulo Ship.cpp per settare i valori delle tre componenti dette in precedenza:

                  
                      float mat_ambient[3] ={ 1.0f, 1.0f, 0.06625f };
                      float mat_diffuse[3] ={ 0.18275f, 1.0f, 0.22525f};
                      float mat_specular[3] ={1.0f, 1.0f, 0.346435f };
                      glMaterialfv(GL_FRONT, GL_AMBIENT, mat_ambient);
                      glMaterialfv(GL_FRONT, GL_DIFFUSE, mat_diffuse);
                      glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
                      float shine = 0.21794872;
                      glMaterialf(GL_FRONT, GL_SHININESS, 128 * shine );
                      glEnable(GL_COLOR_MATERIAL); //Abilita colore sulla mesh               
                    
                      // [.... RENDER DELLA MESH] 

                      glDisable(GL_COLOR_MATERIAL); 

                    
                

Mesh poligonali e Texture Mapping

I modelli 3D nel gioco sono:
  • Ship, sul quale è stata fatta una pre-elaborazione attraverso Blender per separare i componenti del modello iniziale e applicare trasformazioni e texture sui singoli componenti ottenuti (ad esempio l'elica)
  • Moneta
  • Deserto
  • Cubo

Wireframe: ON della Ship

Oggetto Moneta

Deserto

Cubo bonus

La classe Mesh.cpp si preoccupa del reperimento dei dati da file .obj esterni tramite la funzione LoadFromObj e della renderizzazione tramite le differenti tecniche NxF(Flat Shading) NxV (Gouraud Shading) attivabili mediante F3.


Flat Shading ( obj.RenderNxF() )


Gouraud Shading ( obj.RenderNxV() )

Ambiente

Il cielo è stato realizzato con una tecnica chiamata cubemapping, ovvero un metodo di mappatura dell'ambiente che utilizza le sei facce di un cubo come forma della mappa. Per ognuna delle 6 facce viene utilizza una diversa texture. Il test di profondità viene disabilitato quando si renderizza lo skybox per far sì che esso venga disegnato sempre dietro qualsiasi mesh presente sulla scena.

Flowers in Chania Cubemapping

Testo e grafica 2d

In basso a destra è presente la minimappa al fine di aiutare il giocatore a capire dove si trova all'interno dello spazio di gioco. Questa minimappa è formata da un insieme di geometrie 2D. L'area in cui ci si può muovere è formata da un quadrato rosso, mentra la ship è indicata da un'immagine 2D della navicella, i cubi e le monete sono rispettivamente di colore verde e giallo. A seconda dell'altezza dalle monete o dai cubi la dimensione dei cerchi nella mappa varia in modo da capire a quale altezza di trova l'oggetto rispetto all'altezza della ship.

Minimap

Le posizioni di tutti gli elementi nella minimappa sono proporziali alle loro posizioni effettive nello spazio di gioco. In particolare, le posizioni (x,y) della minimappa rispecchiano le posizioni (x,z) del mondo di gioco. In altre parole, è come se ci fosse una telecamera che guarda costantemente la scena dall'alto ed ecco perchè si è deciso di implementare il meccanismo descritto prima relativa alla distanza ship/moneta oppure ship/cubo. Per quanto il testo, viene creata una texture attraverso la funzione TTF_RenderText specificando gli opportuni paramentri come il testo, il colore e il font (che viene caricato attraverso la funzione TTF_OpenFont). Tale texture viene poi applicata a un quadrato 2D.
                
                    void RenderTextCoord(string message, SDL_Color color, int x, int y, TTF_Font *font);
                
              
Premendo F11 viene i mostrato il pannello per il debug. Attraverso tale pannello è possibile vedere le configurazioni attive.


Minimap

Riflessione

E' stata anche testa la riflessione del drone su una superficie, sfruttando l'Alpha Blending e lo Stencil Buffer di OpenGL. La ship viene ridisegnata nuovamente ma capovolta su una superficie che raffigura il mare.


Stencil Attivato

Stencil Disattivato

Conclusioni e sviluppi futuri

Nonostante il lavoro svolto fosse incentrato sulla grafica, è stato necessario implementare anche un minimo di logica per rendere il tutto più interessante e coinvolgente. Una delle difficoltà maggiori è stata nel capire come ragionasse OpenGL nelle trasformazioni, il loro ordine e la loro esecuzione. Un esempio di sviluppo futuro è stato abbozzato attraverso la beta version che dovrà tenere conto dei conflitti con gli altri oggetti presenti nella scena.