Come anticipato nel precedente articolo sul FLAR Toolkit, realizziamo un piccolo esempio pratico di Augmented Reality in Flash. I requisiti per poter ricreare l'esempio sono i seguenti:
- Il FLAR Toolkit, scaricabile con SVN, nel nostro caso però ci serviremo solo del file SWC, scaricabile direttamente da qui
- Un software per la generazione del marker, possibile usare un tool online come ARToolKit Marker Generator o l'applicazione AIR creata da Saqoosha, nell'esempio verrà utilizzata quest'ultima
- Una stampante per poter stampare il nostro marker
- Papervision3D, che verrà utilizzato per creare gli elementi aggiuntivi (nel nostro esempio saranno 3 semplici cubi)
- Un editor per creare ed esportare il file MXML, va quindi benissimo il Flash Builder (nuovo nome del Flex Builder, disponibile in beta)
- Una webcam per creare il marker e poi per testare il risultato finale
Nonostante il numero di requisiti, il codice che regolerà il nostro esempio non sarà moltissimo, anche perchè la maggior parte delle operazioni saranno svolte dal FLAR Toolkit, che si occuperà rilevare la presenza del marker e e calcolarne la posizione nello spazio 3D, questo per fare in modo che l'animazione possa aggiornarsi in tempo reale qualora andassimo a spostare od inclinare il foglio o comunque la superficie su cui si troverà il marker.
Una volta reperiti i componenti necessari, passiamo finalmente a creare il nostro primo esempio pratico di realtà aumentata. Iniziando dalla generazione del pattern.
Creazione del marker
Per creare il marker abbiamo due possibilità: possiamo sfruttare uno dei marker presenti nei vari esempi (ne abbiamo visti alcuni nell'articolo precedente), oppure crearne uno. In entrambi i casi possiamo avvalerci della nostra webcam e di uno dei programmi segnalati tra i requisiti, ovviamente partire da un marker pre-esistente ha il vantaggio di essere sicuri della sua correttezza, d'altro canto però avere un marker personalizzato da sicuramente una miglior impressione anche verso l'utente.
Se pensiamo di creare un marker personalizzato, creiamo in un qualsiasi programma di grafica un quadrato di 8 cm
, con il bordo (nero) spesso 4 cm
e di conseguenza l'interno (bianco) a sua volta di 4 cm. All'interno dello spazio bianco possiamo inserire una forma di nostro gradimento, ecco un esempio:
A questo punto possiamo stampare il nostro marker (o stampare uno dei marker degli esempi disponibili online) e aprire l'ARToolKit Marker Generator. Il software è molto semplice, individua i possibili marker nell'immagine catturata dalla webcam, e li evidenzia con un bordo rosso.
Quando la webcam evidenzia il nostro marker, possiamo cliccare sul pulsante Save pattern
e salviamo l'immagine nella cartella dove abbiamo precedentemente copiato il file .dat. Ricordiamoci di inserire nella maschera di salvataggio anche l'estensione del file, che può essere ad esempio .pat (nell'esempio abbiamo salvato il marker come patternHTML.pat).
Nelle parti successive, vedremo come effettuare la calibrazione della camera e scriveremo il codice vero e proprio.
Calibrazione della camera
Una volta ottenuto il pattern dobbiamo impostare alcuni parametri per la gestione dei dati della webcam. Questi dati si trovano in un file chiamato camera_para.dat: possiamo generare questo file utilizzando il software ARToolKit, ma se non abbiamo esigenze particolari, possiamo copiare il file presente nella cartella src/Data
dell'esempio in allegato.
Questo file può essere tranquillamente riutilizzato e funziona senza problemi, tanto che la maggior parte degli esempi visibili online utilizza questo stesso file .dat
.
Preparare il progetto
Finalmente lanciamo l'ambiente di sviluppo, nel nostro caso caso il Flash Builder, dove creiamo un nuovo Actionscript Project (File > New > ActionScript Project
).
Qui scriviamo il nome del progetto e indichiamo la cartella in cui salvare i file (possiamo anche lasciare il percorso di default). Poi clicchiamo su Next
.
Nella seconda schermata abbiamo la possibilità di impostare le directory relative alle librerie Actionscript che vogliamo utilizzare nel progetto, nel nostro caso quindi Papervision3D e FlarToolkit. Per maggior comodità aggiungiamo le librerie precompilate (swc
), quello di Papervision3D lo troviamo sul sito ufficiale , mentre quello del FLARToolkit è nella cartella bin
del repository SVN.
Una volta ottenuti i file li importiamo spostandoci sulla tab Library path
e cliccando su Add SWC
.
Cliccando su Finish
, il sistema crea tutti i file del progetto compreso il file ActionScript della classe principale (nel nostro caso Esempio_Flar.as
).
Il codice
È il momento di iniziare a scrivere qualche riga di codice, non molto in realtà: il grosso del lavoro sarà svolto dalle librerie.
Aprendo il file Esempio_Flar.as
, vediamo che è stata già dichiarata la classe.
package { import flash.display.Sprite; public class esempio_flar extends Sprite { public function esempio_flar() { } } }
Per iniziare scriviamo gli import
delle classi di FLAR e Papervision. Inoltre avremo bisogno anche delle classi di Flash per gestire la webcam e per analizzare il marker.
// Importa le classi native // BitmapData, ByteArray - analisi del pattern // Camera, Video - visualizzazione della webcam // Event - gestione degli eventi inviatida FLAR import flash.display.BitmapData; import flash.utils.ByteArray; import flash.media.Camera; import flash.media.Video; import flash.events.Event; // Importa le classi del FLARToolkit import org.libspark.flartoolkit.core.FLARCode; import org.libspark.flartoolkit.core.param.FLARParam; import org.libspark.flartoolkit.core.raster.rgb.FLARRgbRaster_BitmapData; import org.libspark.flartoolkit.core.transmat.FLARTransMatResult; import org.libspark.flartoolkit.detector.FLARSingleMarkerDetector; import org.libspark.flartoolkit.pv3d.FLARBaseNode; import org.libspark.flartoolkit.pv3d.FLARCamera3D; // Importa le classi di Papervision3D import org.papervision3d.lights.PointLight3D; import org.papervision3d.materials.shadematerials.FlatShadeMaterial; import org.papervision3d.materials.utils.MaterialsList; import org.papervision3d.objects.primitives.Cube; import org.papervision3d.render.BasicRenderEngine; import org.papervision3d.scenes.Scene3D; import org.papervision3d.view.Viewport3D;
All'interno della classe creiamo le proprietà necessarie ad incorporare, nel nostro SWF
, i file necessari alla calibrazione della webcam (camera_para.dat
) e alla definizione del pattern (patternHTML.pat
). Per farlo creiamo una variabile di riferimento relativa al marker (pattern
) e una relativa ai parametri della webcam (params
) e decoriamo le dichiarazioni con il comando Embed. In questo modo inietteremo il codice dei due file direttamente negli oggetti.
Dichiariamo anche gli oggetti che utilizzeremo per generare l'ambiente 3D, individuare il marker e realizzare l'interazione con la webcam.
public class esempio_flar extends Sprite { // Importa il pattern [Embed(source="patternHTML.pat", mimeType="application/octet-stream")] private var pattern:Class; // Importa i parametri [Embed(source="camera_para.dat", mimeType="application/octet-stream")] private var params:Class; // Variabili per la creazione della visualizzazione della webcam private var vid:Video; private var cam:Camera; private var bmd:BitmapData; // Variabili relative a papervision e FLAR private var fparams:FLARParam; private var mpattern:FLARCode; private var raster:FLARRgbRaster_BitmapData; private var detector:FLARSingleMarkerDetector; private var scene:Scene3D; private var camera:FLARCamera3D; private var container:FLARBaseNode; private var vp:Viewport3D; private var bre:BasicRenderEngine; private var trans:FLARTransMatResult; public function esempio_flar() { } }
A questo punto utilizziamo il costruttore della nostra classe per inizializzare i diversi componenti dell'ambiente, per farlo utilizziamo le seguenti funzioni che dichiareremo più avanti.
Metodo | Descrizione |
---|---|
setupWebcam |
Imposta la visualizzazione del flusso video dalla Webcam |
setupFLARToolkit |
Inizializza i parametri della Webcam e stabilisce le dimensioni del Marker |
setupPattern |
Stabilisce la posizione del marker all'interno del flusso video |
setupPapervision |
Inizializza la scena tridimensionale, gli oggetti e l'illuminazione |
Oltre all'inizializzazione degli oggetti, assegnamo alla funzione renderizza
la gestione dell'evento ENTER_FRAME
. In questo modo possiamo ricalcolare in ogni istante la posizione degli oggetti in base alla camera e al marker.
public function Esempio_Flar() { setupFLARToolkit(); setupWebcam(); setupPattern(); setupPapervision(); addEventListener(Event.ENTER_FRAME, renderizza); }
Implementiamo ora le varie funzioni. La prima da realizzare è setupWebcam, che ci permetterà di visualizzare nel nostro SWF l'immagine catturata dalla camera. Il codice è molto semplice ed è riportato di seguito coi relativi commenti.
private function setupWebcam() : void { // Crea un nuovo oggetto Video vid = new Video(640, 480); // Ricava l'oggetto Camera cam = Camera.getCamera(); // Imposta risoluzione (640x480) e frame rate (30) della webcam cam.setMode(640, 480, 30); // Aggancia il flusso video catturato dalla webcam // all'oggetto video creato in precedenza vid.attachCamera(cam); // Inserisce l'oggetto video sullo stage addChild(vid); }
Se effettuiamo un test adesso, il Flash Player ci richiede l'accesso alla webcam, per mostrare le immagini della nostra telecamerina.
Fatto questo creiamo le funzioni per l'avvio di FLAR e l'impostazione del pattern: setupFLARToolkit e setupPattern.
private function setupFLARToolkit():void { // Crea un nuovo oggetto FLARParam fparams = new FLARParam(); // Carica i parametri della Webcam come ByteArray fparams.loadARParam(new params() as ByteArray); // Crea un nuovo oggetto FLARCode mpattern = new FLARCode(16, 16); // Carica il pattern mpattern.loadARPatt(new pattern()); } private function setupPattern():void { // Crea un oggetto BitmapData con le stesse // dimensioni del flusso della webcam (640x480) bmd = new BitmapData(640, 480); // Disegna nell'oggetto bmd l'attuale frame del flusso video bmd.draw(vid); // Crea un oggetto FLARRgbRaster_BitmapData passandogli // il fotogramma catturato raster = new FLARRgbRaster_BitmapData(bmd); // Crea un nuovo detector passandogli i parametri // della webcam, il pattern da rilevare e la larghezza // del marker (80 mm) detector = new FLARSingleMarkerDetector(fparams, mpattern, 80); }
Queste funzioni potranno essere utilizzate in generale ogni volta che utilizziamo il FLARToolkit: l'unica cosa che potrebbe cambiare è il pattern (e per questo basta modificare il relativo Embed
) o le azioni conseguenti al detect del marker (e in questo caso cambieranno le funzioni relative a Papervision3D), ma i comandi relativi alla creazione del flusso della webcam e al setup di FLAR e del marker possono essere mantenute così come le abbiamo create in questo esempio.
Creiamo ora la funzione relativa al setup di Papervision: in questa funzione impostiamo gli elementi tridimensionali che verranno aggiunti al detect del pattern, avremo quindi un'interazione tra alcuni elementi di Papervision e alcuni di FLAR, infatti per esempio il tipo di camera usato nella scena sarà una FLARCamera3D.
private function setupPapervision():void { // Crea una nuova scena di Papervision scene = new Scene3D(); // Crea una nuova camera basata su FLAR // e sui parametri caricati dal file .dat camera = new FLARCamera3D(fparams); // Crea un nuovo FLARBaseNode container = new FLARBaseNode(); // Aggiunge l'oggetto FLARBaseNode alla scena di Papervision scene.addChild(container); // Crea una luce da usare in Papervision var pl:PointLight3D = new PointLight3D(); // Posiziona la luce pl.x = 1000; pl.y = 1000; pl.z = -1000; // Crea un nuovo materiale per i cubi var ml:MaterialsList = new MaterialsList({all: new FlatShadeMaterial(pl)}); // Crea i 3 cubi e li posiziona a diverse profondità var cube1:Cube = new Cube(ml, 30, 30, 30); var cube2:Cube = new Cube(ml, 30, 30, 30); var cube3:Cube = new Cube(ml, 30, 30, 30); cube2.z = 50; cube3.z = 100; // Aggiunge i cubi alla scena container.addChild(cube1); container.addChild(cube2); container.addChild(cube3); // Impostia il rendering della scena bre = new BasicRenderEngine(); trans = new FLARTransMatResult(); // Crea la visuale vp = new Viewport3D(); // Aggiunge la scena completa allo stage addChild(vp); }
È importante notare che questa funzione crea gli elementi della scena e li imposta, ma non renderizza la scena, questo perchè il rendering della scena deve avvenire solo quando il marker viene rilevato, operazione che eseguiamo nella funzione renderizza
.
private function renderizza(evt:Event):void { // Disegna il frame nell'oggetto bmd bmd.draw(vid); // Se il marker viene rilevato if(detector.detectMarkerLite(raster, 80) && detector.getConfidence() > 0.5) { // Ricava la transformMatrix dal detector detector.getTransformMatrix(trans); // Imposta la transformMatrix sulla scena container.setTransformMatrix(trans); // Renderizza la scena di Papervision bre.renderScene(scene, camera, vp); } }
Notiamo il controllo all'interno dell'oggetto detector: se il marker (memorizzato nell'oggetto raster) viene rilevato nella scena, ricaviamo la transformMatrix
(utile per conoscere la posizione e l'eventuale inclinazione e rotazione del marker) e la applichiamo all'oggetto container
(che contiene la scena 3D), quindi la renderizziamo. Aver associato l'azione di rendering al detect del marker comporta che, non inquadrando il foglio o la superficie con il nostro marker stampato e rilevabile dalla webcam, non vedremo la scena di Papervision.