Articoli

Papervision3D - La telecamera a molla

logoPV3D

Il tipo di telecamera spring è una telecamera che segue un oggetto 3D. Pensate ad auto o astronavi che sono seguite da una terza persona o da una telecamera come si è visto in molti giochi 3D.
È anche possibile usarla come una telecamera in prima persona. La fotocamera non si limita a seguire l'oggetto, aggiunge un piacevole effetto molla quando l'oggetto accelera o cambia direzione.
La telecamera si avvale della fisica, creando di una molla immaginaria tra essastessa e l'oggetto. Quando l'oggetto si muove la molla immaginaria con la fotocamera collegata ad esso verrà estesa e sarà poi tirata indietro, con un conseguente movimento naturale.

Costruiamo un esempio che si basa su quello precedente. Si aggiungerà un oggetto volante alla scena e diremo alla telecamera a molla di dargli la caccia. C'è una cosa che faremo prima di poter utilizzare la telecamera. Anche se essa si prende cura di seguire il nostro oggetto  abbiamo prima bisogno di far muovere l'oggetto. Abbiamo visto che la telecamera di debug ha qualche funzione di spostamento incorporata usabili utilizzando i tasti della tastiera e il mouse. Abbiamo bisogno di costruire alcune funzioni di spostamento così dar far volare oggetto. Tecniche di navigazione più avanzate verranno discusse successivamente, ma per ora, diamo l'opportunità di acquisire familiarità con la navigazione di base.
Chiameremo questo progetto SpringCameraExample. Poiché questo esempio si basa sull'esempio della fotocamera di debug, è possibile copiare e incollare il codice completo di DebugCameraExample nella classe di documento del nuovo progetto. Basta non dimenticare di cambiare la definizione della classe e il nome del costruttore in SpringCameraExample.
Inoltre, copiamo la cartella risorse dal progetto precedente e incolliamolo nella cartella bin di quello attuale in quanto contiene la bitmap per la sfera terrestre.
Prima di creare la fotocamera, per prima cosa creiamo un oggetto semplice che aggiungerà la navigazione in modo da poter volare in giro seguendolo con òa telecamera. Useremo l' aeroplano di carta come nostro oggetto volante.
Importare la classe paperplane e aggiungere la seguente riga per assegnare l'oggetto a una variabile di istanza:

private var paperPlane:PaperPlane;

Per applicare una composizione di due materiali al piano di carta, abbiamo bisogno di importare sia WireframeMaterial e CompositeMaterial:

import org.papervision3d.materials.WireframeMaterial;
import org.papervision3d.materials.special.CompositeMaterial;

Nel metodo init (), subito dopo il codice che crea i piani della galassia, ma prima delle impostazioni della telecamera, aggiungere il seguente:

var planeMaterial:CompositeMaterial = new CompositeMaterial ();
planeMaterial.addMaterial (nuovo ColorMaterial (0xFFFFFF));
planeMaterial.addMaterial (nuovo WireframeMaterial (0x484848));
planeMaterial.doubleSided = true;

Il materiale composito è costituito da un colore e un materiale wireframe e sarà applicata all'aereoplano di carta che noi istanzieremo e posizioneremo.

paperPlane = new PaperPlane (planeMaterial);
scene.addChild (paperPlane);
paperPlane.y = 250;
paperPlane.z = -1000;

Abbiamo finito di creare l'aereo di carta, diamo un'occhiata a come possiamo costruire i fondamentali di navigazione tramite tastiera.

La navigazione di base con la camera 3D

Il tipo di navigazione che stiamo per crere è molto comune in Flash 2D, cosicchè il codice sembrerà famigliare ai programmatori.
Poichè useremo i tasti della tastiera per far navigare l'aereo di carta  (una primitiva che abbiamo già incotrato e incorporato), ci servono le seguenti importazioni:

import flash.events.KeyboardEvent;
import flash.ui.Keyboard;

Per tenere traccia di quali tasti vengono premuti, creiamo alcune proprietà nella classe principale.

private var keyRight:Boolean;
private var keyLeft:Boolean;
private var keyForward:Boolean;
private var keyBackward:Boolean;

All'inizio del metodo init(), aggiungiamo due event listeners in ascolto sullo stage:

stage.addEventListener(KeyboardEvent.KEY_DOWN,keyDownHandler);
stage.addEventListener(KeyboardEvent.KEY_UP,keyUpHandler);

Come si può verdere, gli event listeners aspettano due methods: keyUpHandler() e KeyDownHandler(). 
Il metodo keyDownHandler() appare come segue a:

private function keyDownHandler(e:KeyboardEvent):void

  switch( e.keyCode )
  {
    case "W".charCodeAt():
    case Keyboard.UP:
    keyForward = true;
      break;
    case "S".charCodeAt():
    case Keyboard.DOWN:
       keyBackward = true;
       break;
     case "A".charCodeAt():
     case Keyboard.LEFT:
        keyLeft = true;
        break;
     case "D".charCodeAt():
     case Keyboard.RIGHT:
       keyRight = true; 
       break;
  }
}

Il metodo controlla quale tasto è stato premuto e imposta la relativa proprietà boleana a true. Il metodo keyUpHandler() appare molto simile al precedente, e imposta le proprietà boleane di nuovo a false.

private function keyUpHandler(e:KeyboardEvent):void
{
  switch(e.keyCode)
  {
    case "W".charCodeAt():
    case Keyboard.UP:
      keyForward = false;
      break;
    case "S".charCodeAt():
    case Keyboard.DOWN:
      keyBackward = false;
      break;
    case "A".charCodeAt():
    case Keyboard.LEFT:
      keyLeft = false;
      break;
    case "D".charCodeAt():
    case Keyboard.RIGHT:
      keyRight = false;
      break;
  }
}

Questo codice non fa nulla, ma aspetta che i listners segnalino la pressione dei tasti. Ma comunque abbiamo bisogno di controllare continuamente se un tasto è premuto e quindi dire all'aereoplano di carta di rispondere adeguatamente, per fare ciò abbiamo bisogno di un altro metodo e richiamarlo all'interno del metodo onRenderTick().
Il metodo per controllare lo stato delle proprietà boleane in ogni frame del filmato è il seguente:

private function moveObject():void
  {
     if(keyForward)
  {
    paperPlane.moveForward(30);
  }
  else if(keyBackward)
  {
    paperPlane.moveBackward(30);
  }
  if(keyRight)
  {
    paperPlane.localRotationY -=2;
  }
  else if(keyLeft)
  {
    paperPlane.localRotationY +=2;
  }
}

Essa contiene 2 dichiarazioni if-else. Il primo si cura che l'aereo di carta si muova avanti e indierto, mentre il secondo gestisce la sterzata. Si noti che abbiamo usato 2 nuovi metodi.

Questi sono parte della classe DisplayObject3D e sono piuttosto autoesplicativi:
• moveForward(): muove l'oggetto in avanti lungo il proprio asse z
• moveBackward(): muove l'ogetto indietro lungo il proprio asse z

DisplayObject3D include 4 metodi simili che non abbiamo usato in questo esempio, ma è giusto menzionarli:
• moveLeft(): muove l'oggetto a sinistra lungo il proprio asse x
• moveRight(): muove l'oggetto a destra lungo il proprio asse x
• moveUp(): muove l'oggetto in alto lungo il proprio asse y
• moveDown(): muove l'oggetto in basso lungo il proprio asse y 

Ognuno dei sei metodi richiede un argomento numerico, il quale definisce di quante  unità l'oggetto dovrebbe muoversi per ogni frame.
Una volta che abbiamo aggiunto il metodo moveObject()  giusto dopo la gestione della tastiera, abbbiamo bisogno di richiamarlo ogni frame per ottenere il movimento dell'aereoplano di carta.

Aggiungiamo la seguente linea all'interno del metodo di rendering, assolutamente prima della chiamata a super.onRenderTick() altrimenti vedremo costantementela posizione dell'aereo di carta in ritardo di un frame:

moveObject();

Se ora pubblichiamo il file, dovremmo vedere un aereo di carta appena aggiunto.
Comunque il nostro sistema di navigazione non funziona per nulla perchè la telecamera è settata sul tipo di debug.
La telecamera di debug è in ascolto sugli stessi tasti e sovrascrive i nosti listners.

Non imposteremo il tipo di telecamera su spring perchè prima vogliamo ottenere la navigazione dell'aereoplano senza che la telecamera lo segui. Quindi, lasciamo il tipo su CameraType.TARGET 
per incominciare, per permetterci di testare il codiceche abbiamo scritto.
Cambiamo la chaiamate super() nella seguente:

super(stage.stageWidth,stage.stageHeight,true,false,CameraType.TARGET);

Ora pubblichiamo nuovamente il file e usiamo la tastiera per muovere l'aereoplano.
l'esempio mostra come si muove e ruota l'oggetto 3D, ma invece possiamo anche applicare il codice alla telecamera, con conseguente comportamento simile a quello vistoquando abbiamo usato la telecamera di debug.
E'sufficiente sostituire paperPlane con la camera nel metodo moveObject(). 
Si noti che per vedere la camera ruotare è necessario impostare il suo target su null.

Mettere al lavoro la telecamera a molla

Adesso che abbiamo costruito un semplice sistema di navigazione per far volare un'aereo di carta inseriamo la spring camera per vedere cosa fa.
L'instanziamento della telecamera spring richiede un approccio leggermente differente
rispetto agli alti tipi.
La telecamere che normalmente abbiamo usato nei nostri esempi viene istanziata in
BasicView come un oggetto CameraObject3D.
La classe SpringCamera3D alcune proprietà uniche che non sono instanziate da CameraObject3D.

Siccome la nostra telecamera abituale è un oggetto CameraObject3D, non avremmo accesso alle proprietà della classe SpringCamera3D.
Una strada per maneggiarla è eseguire un typecast  alla telecamera per farla diventare SpringCamera3D.
Per farlo, necessitiamo di importare la classe SpringCamera3D.
Importando la classe Number3D ci viene permesso di lavorare con alcune proprietà di SpringCamera.

import org.papervision3d.cameras.SpringCamera3D;
import org.papervision3d.core.math.Number3D;

La classe Number3D si distingue per un valore tridimensionale. 
Diamo un'occhiata alla linea seguente dove number3D
rappresenta un valore 3D con coordinate x,y e z

var number3D:Number3D = new Number3D(0,50,20);

Adesso impostiamo il tipo a spring attraverso una nuova chiamata a super():

super(stage.stageWidth,stage.stageHeight,true,false,CameraType.SPRING);

Nel metodo init(),assegnamo l'oggetto SpringCamera3D
a una variabile locale e typecast la camera come SpringCamera3D.

var camera:SpringCamera3D = SpringCamera3D(camera);

Dopo questa linea aggiungiamo quanto segue:

camera.mass = 20;
camera.damping = 4;
camera.stiffness = 1;
camera.positionOffset = new Number3D(0,150,-500);
camera.lookOffset = new Number3D(0,0,100);

Qui abbiamo impostato le proprietà che volevamo cambiare, a cui avevamo accesso,
poichè abbiamo typecasted la fotocamera come SpringCamera3D. 
Abbiamo già descritto prima cosa fanno,ora settiamo il bersaglio della telecamera spring.
Alla fine del metodo init(),
appena dopo il settaggio della telecamera aggiungiamo le righe seguenti:

camera.target = paperPlane;

Ripubblichiamo il file. Questa volta la telecamera è subito nella posizione giusta, pronta per seguire l'aereo di carta.
Se muoviamo l'aereo in giro, la telecamera lo seguirà se la molla collega l'aereo alla telecamera risultando un movimento e una rotazione più dolce.

Abbiamo impostato un gruppo di proprietà della telecamera, adesso guardiamo in dettaglio cosa fanno:

Propietà  Tipo di dato
Valore di default  Descrizione 
1 mass Numero 40 La massa o peso della telecameraEsso definisce quanto sia duro tirarla.Un'alta massa rende la telecamera difficile da muovere
2 damping Numero 4  Controlla la frizione interna o quanto la molla resiste all'effetto elastico.Incrementando il valore decrementa l'effetto elastico rendendo il movimento più liscio.E' preferibile mantenere il valore tra 1 e 20.
3 stiffness Numero 1 La stiffness della molla o quantodura deve essere la molla da estendere.Un valore alto fa sembrare la telecamera fissaad una distanza dall'oggettoE' preferibile mantenere il valore tra 1 e 20.
4 positionOffset Number3D Number3D(0,5,-50) Laposizione della telecamera in relazione dello spazio locale del targhet.lookOffset Number3D Number3D(0,2,10) Imposta il punto dove deve guardare la telecamera,sempre definito nello spazio ocale del targetUno spostamento di Number3D(0,100,0)causa il puntamento della telecamera 100 unità più in alto della posizione del target.

Le ultime 2 proprietà contibuiscono alla prospettiva di visione della telecamera e quindi all'esperienza 3D dell'utente. 
Diamo un'occhiata alla posizione ravvicinata, che dovrebbe essere considerata come la posizione in cui si vuole che la telecamera ritorni sempre, siccome cambia tutte le volte causando l'effetto molla desiderato.
Un offset di Number3D(0,50,200) imposta la tlecamera 50 unità più in alto del target e 200 unità dietro a esso. Se volessimo impostare questa proprietà nel nostro esempio  a un valore Number3D(0,0,-300), la telecamera sarebbe giusto dietro l'aereo.
Siccome non sarebbe una visione interessante alziamo la telecamera di 150 unità.
In alcuni giochi 3D, l'utente può scambiare  la visuale tra quella in terza persona,
dove la telecamera è dietro alla testa dell'avatar; e quella in prima persona, dove la telecamera è posizionata in modo da rimpiazzare gli occhi dell'avatar.
Ciò è possibile effettuarlo semplicemente cambiando l'offset della camera a molla.

Filippo Porcari
Author: Filippo PorcariWebsite: http://filippo.porcari.oranjuice.org/Email: Questo indirizzo email è protetto dagli spambots. E' necessario abilitare JavaScript per vederlo.
designer freelance
Sono un graphic designer e mi occupo di pubblicità. Da più di 10 anni dedico le mie energie alla realizzazioni d'immagine aziendale e comunicazione visiva con un'attenzione alle nuove tecnologie del web. Da qualche anno ho scoperto il software open source e mi sono dedicato alla sua introduzione nel mio workflow produttivo ottenendo ottimi risultati.

© copyright 2011

Porcari Filippo studio grafico - p.iva 01985590023

Tutti i diritti riservati.