OpenGL: Gioco 3D

Il Cubo di Rubik


[top]

Obiettivi

Si progetti ed implementi un videogioco 3D interattivo composto da oggetti definiti mediante mesh poligonali e/o superfici quadriche. Si definisca una opportuna scenografia colorando e/o texturando gli oggetti della scena.


[top]

Descrizione del gioco

Il gioco da me implementato è il famoso rompicapo "Cubo di Rubik" (cubo magico). Il Cubo di Rubik ha 9 quadrati su ogni faccia per un totale di 54 quadrati. I quadrati vengono identificati tra di loro per il colore, con un totale di 6 colori differenti. Quando il cubo è risolto, ogni faccia ha i quadrati dello stesso colore. Il giocatore per interagire con il cubo ha a sua dispozione i tasti numerici (da 1 a 9) della tastiera. Ogni numero corrisponde ad una rotazione specifica di 9 cubi. In realtà la versione da me implementata presenta, per ogni rotazione che avviene, una sorta di effetto di scomposizione dell'intera struttura del cubo, questo mentre avviene la rotazione e successivamente la sua ricomposizione.


[top]

Scelte implementative

Il linguaggio da me scelto per la costruzione di questo progetto è stato il C, utilizzando il supporto delle librerie OpenGL e Glut come da specifiche. La finestra di gioco è stata impostata con una risoluzione di 800x600. I cubi più piccoli che costituiscono il cubo più grande sono stati realizzati tramite delle GL_POLYGON definendo 4 vertici per ogni faccia che compone il cubetto (per un totale 6 quadrati per cubetto). Ogni cubetto possiede una struttura associata (cube_t), nella quale vengono salvati i dati realtivi alla loro posizione all'interno del cubo più grande e ai gradi di rotazione per ogni asse effettuati dal cubetto nella rotazione. In questo modo è possibile stabilire quali cubi dovranno essere ruotati nel momento in cui si effettua una determinata rotazione. In realtà ho scelto di adottare un tipo di tecnica per quanto riguarda la rotazione del cubo. Infatti ogni qualvolta che si esegue una rotazione i relativi cubetti ruotano di 90 gradi la loro posizione rispetto al cubetto centrale (sostituito con una sfera realizzata con la primitiva glutSolidSphere), e una volta che hanno terminato la loro rotazione i colori delle faccette vengono cambiate di posto rispetto alla loro posizione originale, settandosi secondo i colori determinati dalla rotazione avvenuta. In fine una volta salvati i dati legati ai colori delle faccette i cubi appena ruotati tornano alla loro posizione di partenza. In questo modo ogni volta che eseguo questo tipo di movimento, otterò l'effetto ottico di aver spostato realmente i cubetti senza aver causato uno stravolgimento nella struttura del cubo stesso. Questo approccio secondo il mio parere facilità in generale la gestione delle rotazioni.

Il piano su cui galleggia il cubo è stato realizzato attraverso la primitiva gluDisk e le texture variano a seconda dell'impostazione impostata tramite menù interattivo o da tastiera. Il gioco è stato inserito all'interno di una sfera (primitiva gluSphere) molto più grande impostanto la texture all'interno dell'oggetto, dando l'effetto di spazio aperto. Per quanto riguarda l'illuminazione della scena di gioco ho scelto una sola luce(GL_POSITION) posizionata all'incirca dietro il punto di vista dell'osservatore. La telecamera (primitiva utilizzata gluLookAt)è stata posizionata in modo da inquadrare sia il cubo che il piano di gioco mentre per quanto riguarda il suo movimento ho scelto di utilizzare le coordinate sferiche; in questo modo si ha una visuale di 360° nel movimento orizzontale, mentre ho scelto di limitare quello verticale che è solo di 90°.


[top]

Comandi del gioco

Per interagire con il gioco vengono utilizzati sia il mouse che la tastiera:

TASTI DESCRIZIONE
T Render di tipo Wire o Fill
R Aggiungi o rimuovi il riflesso
W Aggiungi o rimuovi le ombre
F Aggiungi o rimuovi la nebbia
L Attiva o disattiva la luce
1 a 9 Rotazione delle faccie del cubo.

Opzioni camera

TASTI DESCRIZIONE
Z Incrementa lo zoom
z Decrementa lo zoom
FRECCIA SINISTRA Ruota la telecamera a sinistra.
FRECCIA DESTRA Ruota la telecamera a destra.
FRECCIA SU' Ruota la telecamera in alto.
FRECCIA GIU' Ruota la telecamera in basso.

Opzioni di gioco

TASTI DESCRIZIONE
C Cambia la texture del piano sul quale galleggia il cubo.
P Imposta come texture del piano la foto del programmatore.
SPAZIO Mette il gioco in pausa.
S Varia la velocità di rotazione del cubo.
q Esce dal gioco.


[top]

Tipo di Resa

[top]

Ombre

Per realizzare la proiezione d'ombra del cubo (essendo l'unico oggetto della scena) è stata utilizzata la tecnica dello STENCIL_BUFFER. La tecnica di renderizzazione delle ombre, consiste nel fare il prodotto vettoriale tra la posizione del punto luce e l'equazione del piano su cui l'ombra deve essere proiettata (ovvero sul piano) trovando cosi quella che viene chiamata ShadowMatrix (matrice di proiezione delle ombre). Questa viene poi moltiplicata alla matrice GL_MODELVIEW. Vengono successivamente disattivate tutte le ombre, impostato il colore dell'ombra ed attivato il BLENDER per dare quella trasparenza all'ombra. Usando lo STENCIL BUFFER vengono disegnati gli oggetti che proiettano l'ombra che, grazie allo stencil buffer ed alla moltiplicazione precedente della ShadowMatrix, vengono disegnati "piatti" e posizionati sul terreno.


[top]

Riflesso

Inizialmente ho scelto di creare il riflesso attraverso l'utilizzo di un secondo cubo posto sotto la superficie piana e rendendo il piano trasparente (dando un effetto ottico di riflessione). Successivamente ho capito che utilizzando questo tipo di approccio il codice stava diventando sempre più complesso e di mole elevata siccome i movimenti del cubo dovevano essere speculari. Una soluzione che ho adottato in seguito è stata quella di utilizzare lo STENCIL BUFFER ancora una volta. Infatti attraverso alcuni passi descritti nel documento fornito da Nvidia Corporation (citato nella bibliografia a fonda pagina),con lo Stencil è possibile avere esattamente il riflesso dell'oggetto in questione su una determinata superfice.

La parte riflettente:
La finestra dovrebbe essere allocata con lo stencil buffer. Successivamente quando cancelliamo il frame buffer all'inizio della scena, bisogna cancellare anche lo stencil buffer a zero. Una volta eseguiti questi due passi disabilitiamo il GL_DEPTH_TEST e impostiamo con glColorMask tutti i colori a false, in questo modo non avremo aggiornameti ne per il depth buffer ne per i colori. Abilitiamo successivmente lo GL_STANCIL_TEST impostando la scrittura sullo stancil_buffer a 1, in questo modo tutto quello che disegneremo successivamente sarà utilizzato per la riflessione.
Una volta eseguiti questi passaggi ,quindi ,bisogna determinare la parte della scena che ha il compito di riflettere gli oggetti, che di solito possono essere: quattro vertici di un rettangolo, oppure i vertici di un poligono, oppure "l'equazione del piano" derivata dalla superficie sulla quale si vuole riflettere il tutto.
In fine riabilitiamo sia il GL_DEPTH_TEST che la glColorMask.
Una volta implementata la parte che si occupa della riflessione degli oggetti, dobbiamo impostare quali oggetti varranno riflessi a loro volta.
In questo caso basterà moltiplicare la matrice di vista per la matrice di riflessione che riflette la scena attraverso la superfice determinata prima.
Consideriamo quindi in questo caso che la parte che riflette stia sull'asse Y=0. Questa matrice speciale di riflessione in pratica è una semplice matrice di scala glScale(), nella quale sono stati negati i valori dell'asse Y.
In fine disegniamo gli oggetti che verranno riflessi, stando attenti nel cambiare l'ordine delle facce dei poligoni da renderizzare, in quanto l'orientamento dei poligono riflessi viene invertito, quindi bisognerà impostare glCullFace(GL_FRONT) (se prima era impostato a GL_BACK) disegnare l'oggetto e ripristinare l'orientamento alla fine.


[top]

Nebbia

Per creare l'effetto di nebbia utilizzato funzioni già presenti nelle librerie standard di OpenGL ovvero la glFogi().


[top]

Menu

Il menu è stato creato usando la funzione glutCreateMenu() a cui è stata passata come gestore lo stesso della tastiera in modo da avere gli stessi effetti sia interagendo con la tastiera sia utilizzando il mouse.


[top]

Immagini di resa del gioco




















[top]

Materiale utilizzato

Materiale utilizzato:


[top]

Problemi riscontrati e Bug

Fondamentalmente l'obiettivo del progetto era quello di realizzare un video gioco mediante OpenGL. Come da specifiche bisogna tener presente che il progetto è sulle OpenGL non sui videogiochi, quindi ho implemetnato in modo essenziale il video gioco senza tener conto: