Nel nostro progetto abbiamo realizzato un'isola con il tema dei pirati. L'isola, costruita a partire da una heightmap realizzata appositamente, è stata quindi decorata con vari oggetti che seguissero il tema. Molti di questi oggetti sono stati inoltre animati.
Il file principale è Progetto-Cubes-2019-Rossetto-Travasci.html
. Vengono utilizzate le librerie three.min.js
, stats.min.js
e OrbitControls.js
, tutte contenute nella cartella lib
. Il file principale ha accesso anche alla libreria Coordinates.js
(sempre collocata nella stessa cartella), che però al momento non è usata.
La cartella scripts
contiene vari file .js
che vengono utilizzati dal file principale per vari scopi. In particolare, in ordine alfabetico: animations.js
contiene tutto il codice che implementa le animazioni; builders.js
contiene le funzioni necessarie a creare gli oggetti presenti nella scena; lights.js
si occupa di creare le luci e di gestirle nel ciclo giorno/notte e nella attivazione e disattivazione dello stesso; terrainBuilder.js
, infine, crea il terreno a partire dalla heightmap, aggiunge il mare e si occupa della creazione ed animazione delle nuvole.
La cartella audioFiles
contiene i file audio usati nel progetto.
La cartella textures
contiene tutte le textures e la heightmap.
Lo spostamento all'interno della scena è gestito dai controlli definiti in OrbitControls.js
.
Il terreno viene costruito dalla funzione buildTerrain()
all'interno di terrainBuilder.js
. Questa funzione utilizza l'immagine heightmapIsland.png
, che non è altro che una heightmap, per posizionare i blocchi del terreno alla giusta altezza. Ogni pixel della heightmap rappresenta un blocco di lato 0.5, ovvero mezzo metro nella nostra convenzione.
Solo i blocchi visibili del terreno vengono creati, ovvero i blocchi che si trovano in superficie e quelli che fanno parte di pareti verticali esposte. Ai confini del terreno, inoltre, un muro verticale di blocchi arriva fino all'altezza del punto più basso del terreno, in modo da far sembrare compatto il terreno quando visto dai lati.
Le texture dei blocchi che compongono il terreno variano a seconda della loro altezza e del fatto che si trovino o meno in superficie. Ad esempio, i blocchi di erba vengono posizionati solo al di sopra di una certa altezza e solo se non ci sono altri blocchi direttamente al di sopra di loro.
Inoltre, i blocchi d'erba possiedono diverse varianti, in modo che le loro facce laterali siano completamente composte da erba se subito al di sotto di tale faccia si trova un altro cubo di erba. In caso contrario, la faccia laterale in questione presenterà una parte superiore di erba e una inferiore di terra.
Per diminuire l'impatto nelle prestazioni del terreno, i blocchi di superficie che si trovano ad una altezza inferiore o uguale a quella di tutti i blocchi di superficie ad essi adiacenti non generano ombre. Inoltre, invece di creare una nuova mesh per ogni blocco posizionato nel terreno, vengono clonate delle mesh create in precedenza.
Il mare, parte integrante del terreno, è un parallelepipedo con base di dimensioni quasi uguali a quelle del terreno che utilizza un materiale trasparente.
Il costruttore buildFish(color)
ritorna un Object3D di un pesce del colore fornito in input.
A seconda del tipo di animazione scelta, il pesce si muoverà su un tracciato a forma di cerchio oppure di "8". Il pesce inoltre muoverà la coda a destra e a sinistra per dare l'impressione che stia nuotando.
Il costruttore buildBridge(height)
ritorna un Object3D di una sezione di ponte di altezza height
.
Un albero, creato utilizzando il costruttore buildTree(color)
. Al momento della sua creazione è possibile sceglierne il colore.
Nel terreno sono stati aggiunti diversi alberi. Gli alberi uguali sono stati ottenuti clonando una stessa mesh, invece di crearne di separate. Quindi, per averli di dimensioni diverse, sono state applicate diverse scalature.
Una farfalla, creata utilizzando il costruttore buildButterfly(color)
. Nel momento della sua creazione è possibile scegliere il colore dele sue ali.
Quando animate, si muoveranno su un tracciato ellittico, sbattendo le ali e ondeggiando in alto ed in basso durante lo spostamento.
Una bandiera dei pirati, creata utilizzando il costruttore buildPirateFlag()
.
Per rendere creare una animazione della bandiera che sventola, il tessuto è stato scomposto in diversi parallelepipedi (ognuno animato).
Un forziere, creato utilizzando il costruttore buildCoffer()
.
Alla pressione del tasto O
il forziere si aprirà e si chiuderà dopo un tempo prefissato, emettendo suoni all'apertura e alla chiusura.
Un cannone, creato utilizzando il costruttore buildCannon()
.
Alla pressione del tasto F
la miccia si "accenderà", ovvero emetterà un suono e genererà fumo e scintille. Dopo qualche secondo il cannone "sparerà" una palla di cannone. Dopo lo sparo, una piccola colonna di fumo si alzerà dalla bocca del cannone.
Una statua magica, creata utilizzando il costruttore buildStatue()
.
Attraverso l'alternanza di molteplici texture, è stata creata una animazione grazie alla quali gli occhi della statua sembrano lampeggiare.
Delle nuvole animate che si muovono in continuazione nel cielo. Per nascondere il confine del piano su cui appaiono le nuvole è stata aggiunta una nebbia alla scena.
Il codice deputato alla creazione ed animazione delle nuvole si trova all'interno di terrainBuilder.js
. L'animazione, in particolare, funziona incrementando continuamente l'offset della texture delle nuvole.
Tramite la pressione del tasto N
è possibile simulare un ciclo giorno/notte attivando un'animazione che sposta la DirectionalLight e ne cambia l'intensità. Anche l'intensità della HemisphereLight viene modificata durante il corso della giornata simulata. Lo sfondo reagisce anch'esso al cambiamento cambiando colore gradualmente in base alla percentuale di animazione a cui si è arrivati. Alla successiva pressione del tasto la luce torna nella sua posizione di default.
Tramite la pressione del tasto P
è possibile attivare dei suoni ambientali di sottofondo.
Un overlay che mostra i tasti della tastiera da premere per effettuare certe azioni. Nascondibile premendo il tasto Esc
.
Le feature da sviluppare individuate all'inizio dei lavori sono state divise in tre gruppi con crescenti priorità, in modo da distinguere le feature che rappresentavano le basi fondanti del progetto, quelle che pur essendo meno importanti dovevano essere comunque obbligatoriamente completate e quelle di minore importanza che non erano strettamente necessarie. In corso d'opera ci sono stati vari ridimensionamenti e aggiunte, come ad esempio il cannone e il forziere, in modo da rispecchiare la nostra volontà sull'obiettivo finale del progetto.
La modellazione degli oggetti è stata fatta usando solo i metodi fornitoci dalla libreria di three.js, senza l'uso di strumenti esterni. Le texture sono state realizzate tutte personalmente da noi utilizzando un raster graphic editor (Paint per Windows e Pinta per Ubuntu).
Nel progetto sono stati utilizzati i seguenti suoni, tutti provvisti di una licenza Creative Commons 0.
fuse2.wav by j1987 on freesound.org
Cannon1.wav by Isaac200000 on freesound.org
Chest Opening.wav by spookymodem on freesound.org
Chest Slam by TNTdude7 on freesound.org
Tropical Island by richwise on freesound.org