Grafica 3D per il Web con Away3D

21 dicembre 2013

WebGL, acronimo di Web-based Graphics Library, è una tecnologia che ci permette di manipolare grafica 3D (ma anche 2D) sui nostri browser in modo decisamente performante, sfruttando l’accelerazione hardware del dispositivo, senza l’intermediazione di plugin o estensioni specifiche.

Anche se la specifica WebGL fornisce una API molto ricca, per semplificarne l’uso sono nati diversi framework, tra cui Away3D.

Away3D

Away3D è un motore grafico open source scritto in linguaggio ActionScript3 e progettato per la piattaforma Flash. Supporta le versioni più recenti del plugin Adobe Flash e sfrutta l’accelerazione grafica della GPU per il rendering 3D fornendo una API che consente di disegnare oggetti tridimensionali ed eseguire trasformazioni sulla posizione, la scala, la rotazione degli stessi, oltreché applicare texture, luci e altro ancora.

Possiamo scaricare Away3D gratuitamente dal sito ufficiale.

La cosa interessante è che esistono diversi porting di Away3D in altri linguaggi, tra cui TypeScript, che ci consente di usare la libreria all’interno di una pagina Web sfruttando WebGL.

TypeScript

TypeScript è un linguaggio sviluppato da Microsoft che estende la sintassi JavaScript aggiungendo il supporto ai tipi e altre caratteristiche tipiche della programmazione object oriented e presenti nei linguaggi adatti allo sviluppo di applicazioni su larga scala; la compilazione di un programma TypeScript genera codice JavaScript.

>> Leggi “Introduzione al linguaggio TypeScript”.

Possiamo scaricare il compilatore di TypeScript dal sito ufficiale dove troviamo anche il plugin per Visual Studio o per il proprio editor o ambiente di sviluppo (come Sublime Text, FlashDevelop, Eclipse e altri ancora). Il plugin funziona anche con Visual Studio Express 2013 for Web, scaricabile gratuitamente dal Download Center di Microsoft.

Primi passi con Away3D

Per utilizzare Away3D, è possibile scaricare i sorgenti (oppure clonare il repository) della versione TypeScript della libreria dal portale GitHub che li ospita. In questo articolo analizzeremo uno degli esempi scaricabili come demo, che si possono vedere anche online sul sito ufficiale, per saggiare le capacità di WebGL e Away3D.

In particolare vedremo alcuni dettagli implementativi dell’esempio “Basic Skybox”, che mostra una forma geometrica toroidale immersa in uno sfondo con nuvole e montagne, che rotea e riflette l’ambiente circostante, spostando la camera in base alla posizione del mouse nella pagina:

Creazione di una scena 3D

Per esaminare in dettaglio le parti salienti dell’esempio “Basic Skybox”, vediamo quali sono le classi e i metodi utilizzati per ottenere il disegno.

Importazione della libreria

Prima di poter utilizzare le classi che fanno parte dell’API di Away3D, occorre aggiungere una riga che esplicita il riferimento al file JavaScript che contiene il codice compilato della libreria e che referenzia a sua volta tutti gli altri script che ne fanno parte:

///<reference path="../libs/Away3D.next.d.ts" />

Creazione del modulo e della classe

Per convenzione, tutta la logica che implementa l’ambientazione tridimensionale e ne gestisce gli eventi, va racchiusa all’interno di una classe TypeScript, che memorizza in campi appositi tutti i riferimenti agli oggetti della libreria A3D che rappresentano forme, luci e altri elementi che compongono la scena.

Qui di seguito è riportata la definizione del modulo TypeScript (module) e della classe (class) che verrà “farcita” con la logica dell’esempio.

module examples
{
	export class Basic_SkyBox
	{
		// TODO: Inserire qui la logica di implementazione
	}
}

Creazione dei campi della classe

I riferimenti agli oggetti della libreria che vengono utilizzati nella scena sono memorizzati in campi privati dichiarati all’interno della classe:

//engine variables
private _view:away.containers.View3D;

//material objects
private _cubeTexture:away.textures.HTMLImageElementCubeTexture;
private _torusMaterial:away.materials.ColorMaterial;

//scene objects
private _skyBox:away.entities.SkyBox;
private _torus:away.entities.Mesh;

//navigation variables
private _timer:away.utils.RequestAnimationFrame;
private _time:number = 0;
private _mouseX:number;
private _mouseY:number;

Vediamo brevemente le finalità di alcune delle classi utilizzate per i campi.

ClasseDescrizione
away.containers.View3Drappresenta il “palco” sul quale prenderanno posto tutti gli elementi della scena, per i quali funge da contenitore, oltre a gestire gli eventi del mouse generati dall’interazione dell’utente.
away.textures.HTMLImageElementCubeTextureconsente di utilizzare una immagine HTML come texture da spalmare sulla superficie dell’oggetto da animare nella scena.
away.materials.ColorMaterialdefinisce il modo in cui l’oggetto “protagonista” appare definendo un colore scelto che viene “diffuso” dalla superficie.
away.entities.SkyBoxrappresenta una entità già definita nella libreria che contiene tutti gli elementi necessari a riprodurre l’aspetto e il comportamento di un cielo che avvolge la scena tridimensionale.
away.entities.Meshpermette di raggruppare in un unico oggetto tutti gli elementi che definiscono le caratteristiche di un singolo oggetto (materiali, colori, texture, animazioni, ecc.) da collocare nella scena: in questo caso, si tratterà della figura di un “toro geometrico”.

Questi campi conterranno i riferimenti agli oggetti che creeremo in fase di inizializzazione.

Inizializzazione del motore e della scena principale

Per creare l’ambiente 3D, dobbiamo istanziare una delle classi menzionate e salvarne i riferimenti all’interno dei campi privati. Vediamo il codice del metodo che consente di configurare la vista principale, commentato opportunamente per spiegare cosa avviene in ciascuna riga:

/**
 * Inizializza il motore
 */
private initEngine():void
{
	// Crea un'istanza della vista
	this._view = new away.containers.View3D();
	
	// Imposta posizione punto di osservazione della camera
	this._view.camera.z = -600;
	this._view.camera.y = 0;
	this._view.camera.lookAt(new away.geom.Vector3D());
	
	// Applica una matrice di trasformazione prospettica
	this._view.camera.lens = new away.cameras.PerspectiveLens(90);

	// Inizializza la posizione orizzontale del mouse
	// al centro della finestra del browser
	this._mouseX = window.innerWidth/2;
}

Nel metodo viene inizializzata la vista che conterrà tutti gli elementi della scena, tra cui la camera che definisce il “punto di osservazione” e le sue proprietà. Si inizializza inoltre la posizione del mouse al centro della finestra: quando il mouse si sposterà successivamente verso sinistra o verso destra, la camera verrà ruotata di conseguenza.

Creazione della forma e del materiale

Il materiale definisce in buona sostanza le caratteristiche visive della superficie dell’oggetto; qui di seguito è riportato il codice che crea e inizializza il materiale che verrà applicato alla forma geometrica inserita nella scena.

/**
 * Inizializza i materiali
 */
private initMaterials():void
{
	// Crea il materiale impostando il colore da diffondere
	this._torusMaterial = new away.materials.ColorMaterial(0xFFFFFF, 1); 

	// Definisce le proprietà del riflesso dell'ambiente sulla superficie
	this._torusMaterial.specular = 0.5;
	this._torusMaterial.ambientColor = 0x111199;
	this._torusMaterial.ambient = 1;
}

La creazione della forma “a ciambella” è forse la parte più semplice:

/**
 * Inizializza gli oggetti della scena
 */
private initObjects():void
{
	// Crea l'oggetto che rappresenta la forma toroidale
	this._torus = new away.entities.Mesh(new away.primitives.TorusGeometry(150, 60, 40, 20), this._torusMaterial); 

	// Inserisce l'oggetto nella scena precedentemente inizializzata
	this._view.scene.addChild(this._torus);
}

La gestione degli eventi è importante poiché consente di modificare dinamicamente i parametri della scena e degli oggetti che la compongono in base alle azioni dell’utente, trasformando in un ambiente interattivo quella che sarebbe stata altrimenti una semplice fotografia.

Rendering della scena

Di importanza fondamentale è l’uso dell’oggetto away.utils.RequestAnimationFrame, che consente di ricevere una notifica nel momento in cui il browser richiede il frame successivo della nostra animazione, sincronizzandoci così perfettamente con la pipeline della scheda grafica preposta al rendering ed evitando effetti di sfarfallio ma ottimizzando le performance e il consumo di batteria (qualora l’animazione venga eseguita su un dispositivo portatile).

La funzione responsabile del disegno, come predetto, si limita ad apportare le variazioni ai valori che determinano la posizione, la rotazione e gli altri parametri di assetto degli elementi della scena:

/**
 * Loop di rendering e navigazione della scena
 */

private onEnterFrame(dt:number):void
{
	// Modifica la rotazione della figura toroidale
	this._torus.rotationX += 2;
	this._torus.rotationY += 1;

	// Applica una rotazione alla camera basata sulla posizione orizzontale del mouse
	this._view.camera.position = new away.geom.Vector3D();
	this._view.camera.rotationY += 0.5*(this._mouseX - window.innerWidth/2)/800;
	this._view.camera.moveBackward(600); 

	// Forza il rendering della vista
	this._view.render();
}

In breve, per ciascun frame dell’animazione, la figura della ciambella viene continuamente ruotata; lo stesso avviene per la camera, che ruota tanto quanto la posizione orizzontale del mouse si sposta dal centro della finestra del browser, verso sinistra oppure verso destra.

Le coordinate del mouse vengono aggiornate nella funzione di callback associata al relativo evento:

/**
 * Gestione movimento del mouse per aggiornamento delle coordinate
 */
private onMouseMove(event)
{
	// Memorizza nei campi dell'oggetto le coordinate del mouse
	this._mouseX = event.clientX;
	this._mouseY = event.clientY;
}

I “limiti” delle dimensioni della vista, invece, sono regolati nell’evento che risponde al ridimensionamento della pagina:

/**
 * window listener for resize events
 */
private onResize(event = null):void
{
	// Imposta le dimensioni dell'area rettangolare della scena
	this._view.y = 0;
	this._view.x = 0;
	this._view.width = window.innerWidth;
	this._view.height = window.innerHeight;
}

Fuoco alle polveri!

Il codice che abbiamo visto sino a ora è parte integrante della classe TypeScript che contiene tutta la logica della nostra scena e che ne definisce sia gli attributi sia il comportamento.

Per “dare vita” alla creazione, è sufficiente creare un’istanza della classe al momento del caricamento della pagina Web:

window.onload = function ()
{
	new examples.Basic_SkyBox();
}

Conclusioni

In questo articolo abbiamo visto come è possibile creare con poche righe di codice una semplice classe che definisca un’ambientazione 3D da mostrare all’interno di una pagina Web, utilizzando gli oggetti della libreria Away3D e sfruttando la comodità di un linguaggio più rigido e tipizzato quale è TypeScript per la programmazione; grazie al supporto WebGL integrato nei browser moderni, possiamo aggiungere superfici, sfondi, effetti di riflesso, texture, luci, ombre e animazioni che vengono riprodotte sfruttando la potenza offerta dalla GPU della scheda grafica, sollevando la CPU dall’onere di gestire queste funzioni multimediali e mantenendo quindi performance ottimali e consentendo di risparmiare energia laddove questo fattore costituisce un requisito fondamentale.

Nell’analisi dell’esempio abbiamo visto il significato di una minima parte degli oggetti e dei metodi forniti della libreria; per una trattazione esaustiva è possibile fare riferimento alla documentazione ufficiale riferita alla versione ActionScript: laddove possibile, i nomi dei tipi di dati della versione TypeScript rimangono identici così come le loro funzionalità.

Se vuoi aggiornamenti su Grafica 3D per il Web con Away3D inserisci la tua e-mail nel box qui sotto:
 
X
Se vuoi aggiornamenti su Grafica 3D per il Web con Away3D

inserisci la tua e-mail nel box qui sotto:

Ho letto e acconsento l'informativa sulla privacy

Acconsento al trattamento dei dati per attività di marketing