Papervision 3D rappresenta un motore 3D open-source per Flash scritto in AS3.
Hon ha quindi una interfaccia grafica, ma possono essere importati elementi tridimensionali costruiti con “3D studio max”, “Maya” o “Cinema 4D 11″.
La nostra analisi si concentrerà invece sulla programmazione 3D direttamente in ActionScript.
Esistono altri linguaggi concorrenti al PV3D, quali Sandy 3D e Away 3D in primis, ma considerato il grande successo del primo ho pensato sia giusto concentrarmi su questo.
Gli esempi, i tutorials e le notizie riguardanti PV3D non mancano di certo sulla rete, forse l’unico vero difetto è che manca una guida definitiva (manco per sogno in italiano).
Anche questa e le altre future, sono solo degli interventi (trascrizione di appunti e conoscenze personali) e non hanno l’obiettivo di diventare una vera e propria guida, ma proprio per questo mi piacerebbe collaborare con voi, magari mandandomi le vostre indicazioni preziose
Le basi del sistema: gli oggetti primitivi.
Voglio iniziare a trattare di papervision 3D 2.0 analizzando le fondamenta della programmazione 3D per Flash, in modo da fare un discorso ordinato e completo (eheheh metodo universitario), dopo passeremo a un tutorial pratico (CLICCA QUI per vedere il risultato) con maggiore sicurezza e competenza.
Ovviamente per cominciare bisogna possedere qualche competenza di AS3. Inoltre bisogna scaricare i sorgenti di papervision da questo sito, inserire poi la cartella “org” dei sorgenti all’interno di quella contenente i nostri file di lavoro .fla e .as. Tali sorgenti sono fondamentali per la realizzazione di progetti tridimensionali, poiché a questi bisogna collegare il nostro file actionscript con tutto la programmazione.
Qualsiasi cosa programmiamo in PV3D bisogna inserire 2 classi fondamentali: Scene3D e Camera3D.
È possibile utilizzare anche le classi Viewport3D e BasicRenderEngine, ma personalmente preferisco limitarmi alle precedenti 2.
Scene3D
Rappresenta il mondo virtuale 3D che vediamo dalla “viewport” dove sono presenti tutti gli elementi che inseriremo nel lavoro. Inizialmente esso sarà uno spazio tridimensionale vuota.
//Creazione della Scena 3D
private var scene:Scene3D = new Scene3D();
Camera3D
La “camera3D” serve per visualizzare all’utente tutto ciò che si trova o succede all’interno della scena tridimensionale. Per chi ha qualche familiarità con qualsiasi programma di grafica 3D, conosce benissimo come funziona la camera: un occhio, una telecamera che registra e permette la visualizzazione su uno schermo della realtà (virtuale in questo caso) di fronte.
Papervision3D, essendo basato un linguaggio interattivo in Flash, permette inoltre all’utente la manipolazione semplice e veloce della camera: cioè rende l’effetto di movimento sulla scena.
Esistono infatti 2 metodi per realizzare un’impressione di movimento dentro una realtà tridimensionale: spostare gli oggetti o spostare il punto di visualizzazione (la camera3D), un po’ come nei giochi sparatutto in prima persona.
In questo modo l’utente muove la “camera3D” e l’intera “scene3D” si aggiusta alla nuova posizione.
In papervision3D esistono tre differenti tipologie di camera:
- Camera3D: che richiede la definizione delle coordinate di una posizione target, a cui punterà la visuale qualsiasi sia la sua posizione nello spazio 3D.
- FreeCamera3D: permette un movimento libero nello spazio in ogni direzione o angolo.
- FrustumCamera3D: permette gli stessi movimenti della “FreeCamera3D” ma visualizza soltanto gli oggetti inseriti all’interno di un campo definito dal programmatore.
In ogni caso la principale tipologia di camera è la prima, che consiglio di usare.
Finora però di ciò che si è realizzato non viene visualizzato niente, proprio perché bisogna necessariamente prima renderizzare il tutto, ossia renderlo visibile.
Si può renderizzare direttamente col comando:
//scene rappresenta la variabile associata a Scene3D,
//mentre camera è la variabile associata a Camera3D.
scene.renderCamera(camera);
È possibile utilizzare il comando “BasicRenderEngine” per renderizzare la scena 3D partendo dal posizionamento della “Camera3D” attraverso le caratteristiche del “Viewport3D” definite dal programmatore. Ma preferisco il primo metodo.
Vediamo ora un esempio di codice completo per la creazione dei vari elementi finora esposti, definito in un file .as esterno al quale il filmato .fla deve collegarsi:
package inizio{
import flash.display.Sprite;
import org.papervision3d.scenes.*;
import org.papervision3d.objects.*;
import org.papervision3d.cameras.*;
import org.papervision3d.materials.*;
//estendiamo la classe “inizio” come elemento “Sprite”
//per acquisirne le caratteristiche.
public class cubo extends Sprite
{
//realizzo un elemento contenitore che ospiti la
//scena 3D e la centri poi nello stage.
var contenitore:Sprite = new Sprite();
var mioCubo:Cube = new Cube();
public function cubo():void {
container.x = stage.stageWidth * 0.5;
container.y = stage.stageHeight * 0.5;
addChild(container);
var scene:Scene3D = new Scene3D(container);
var camera:Camera3D = new Camera3D();
}
scene.renderCamera(camera);
}
}
Le coordinate 3D in PV3D
In papervision le coordinate centrali di un oggetto 3D rispetto al suo centro (e non rispetto all’angolo superiore-sinistro come di default in Flash) è X= 0, Y= 0 e Z= 0 della scena 3D.
Di default le coordinate della Camera3D sono X= 0, Y= 0 e Z= -1000 dall’origine degli assi.
Le unità di misura per le coordinate in PV3D non sono precisamente i pixel di una tradizionale realizzazione in Flash in 2 dimensioni, quindi per definire gli intervalli di movimento bisogna basarsi sulle distanze che si vengono a creare fra la Camera3D e i vari oggetti inseriti nella Scene3D.
È conveniente quindi, per definire le coordinate e le distanze, basarsi sul risultato di visualizzazione effettuando più prove, impostando valori differenti.
L’oggetto base, in PV3D, per la creazione di elementi tridimensionali avanzati è il triangolo, essendo la figura piana con minor vertici. PV3D sfrutta poi gli algoritmi di disegno di Flash, per realizzare la figura del triangolo, che avviene in maniera rapida.
Esso però comporta problemi nella visualizzazione, rara per fortuna, di sovrapposizioni dei triangoli (visibili a volte in molti esempi di grafica 3D in Flash). Per risolvere questo problema bisogna creare molti più segmenti per ogni oggetto 3D, diminuendo ancora le basse possibilità di sovrapposizione, ma di contro di aumenta il tempo e la memoria del PC necessaria per la creazione di tali elementi 3D più abbondanti d’informazioni.
Il piano
Il piano rappresenta una delle figure più usate nei progetti tridimensionali per il web. Tecnicamente il piano non è un oggetto 3D, perché non ha profondità, ma è formato da 2 triangoli uniti per formare un rettangolo. Realizzare un piano è semplicissimo (la definizione delle caratteristiche di base sono già implementate nei codici sorgenti di PV3D che abbiamo scaricato all’inizio), ma bisogna poi aggiungerlo alla scena seguendo il procedimento standard di AS3:
var plane:Plane = new Plane();
scene.addChild(plane);
Il piano così creato avrà di default una larghezza ed una altezza di 500, centrato all’origine degli assi. Ovviamente, riguardo il piano, possono essere indicate dei parametri ulteriori, quali il materiale di cui è composto, la larghezza, l’altezza, i segmenti orizzontali e verticali, ecc:
Plane( material:MaterialObject3D=null, width:Number=0, height:Number=0, segmentsW:Number=0, segmentsH:Number=0)
Il numero di segmenti orizzontali e verticale è utile per aumentare i dettagli del piano e soprattutto aiuta ad evitare la distorsione dell’immagine in caso di rotazione. Ovviamente più si aumentano questi valori, più triangoli si vengono a creare e di conseguenza più pesante diventa il filmato flash (pesante soprattutto nel senso di capacità della CPU richiesta per l’elaborazione del mondo tridimensionale), conviene quindi non esagerare mai coi valori e mantenersi, nel totale delle figure create in 3D, sotto i 2000 triangoli.
Vediamo un esempio di piano con 4 segmentsW e 3 segmentsH.
Per definire le coordinate X,Y, Z iniziali, le rotazioni X, Y, Z, le scale X, Y, Z, ed extra parametri è consigliabile applicarli poi direttamente al piano che creiamo.
Un importante extra parametro da definire al materiale è l’attivazione doppio lato (”doubleSided”), altrimenti, in caso di rotazione del piano, questo sparisce appena si visualizza l’altro lato, poiché non è colmato da una texture.
Ad esempio:
//crea una maglia, ossia si visualizzano solo i contorni
var materiale:WireframeMaterial = new WireframeMaterial(); //definiamo la larghezza e l'altezza var w:Number = 800; var h:Number = 800; //il numero di segmenti var sW:Number = 1; var sH:Number = 1; var plane:Plane = new Plane(materiale, w, h, sW, sH);
//inseriamo quindi alcuni valori a piacere plane.x = 100; plane.rotationY = 30; plane.scaleZ = 20;
//attiviamo la doppia faccia, in modo da colmare
//anche la seconda faccia del piano con una texture
materiale.doubleSided = true;
//ricordiamo sempre di aggiungerlo alla scena scene.addChild(plane);
La Sfera, il Cono e il Cilindro.
La sfera in PV3D non è altro che un poligono con moltissime facce composte da triangoli, ovviamente appare spigolosa e non rotonda perfettamente, ma aumentando il grado di dettaglio si possono raggiungere risultati accettabili.
Realizzare la sfera è semplicissimo, a differenza del piano bisogna indicare il raggio:
var sphere:Sphere = new Sphere();
shere( material:MaterialObject3D=null, radius:Number=100, segmentsW:int=8, segmentsH:int=6);
scene.addChild(sphere);
Anche il cono si realizza allo stesso modo (rispetto alla sfera si indica in più una altezza):
var cone:Cone = new Cone();
cone( material:MaterialObject3D=null, radius:Number=100, height:Number=100, segmentsW:int=8, segmentsH:int=6);
scene.addChild(cone);
Così per il Cilindro (viene specificato se la faccia superiore deve essere disegnata):
var Cylinder: Cylinder = new Cylinder ();
Cylinder( material:MaterialObject3D=null, radius:Number=100, height:Number=100, segmentsW:int=8, segmentsH:int=6, topRadius:Number=-1)
scene.addChild(Cylinder);
Il Cubo
Il cubo rappresenta una importante figura geometrica, realizzarla è molto semplice:
mioCubo = new Cube(materiale:MaterialsList, width:Number=500, depth:Number=500, height:Number=500, segmentsS:int=1, segmentsT:int=1, segmentsH:int=1, insideFaces:int=0, excludeFaces:int=0);
scene.addChild(mioCubo);
Vediamo meglio di capire i vari parametri che possono ora essere inseriti:
- materiale rappresenta il riferimento ad un oggetto MaterialObject3D per quanto riguarda il materiale da applicare all’esterno della faccia (poi vedremo degli esempi pratici),
- width, depth e height rappresentano la larghezza, la profondità e l’altezza del cubo,
- segmentS, T e H rappresentano le suddivisioni interne delle facce,
- insideFaces definisce se e quali facce interne devono essere realizzate (di default in PV3D 1.5 esse sono visibili pure dall’interno),
- excludeFaces (presente solo in PV3D versione 2 beta) definisce invece se e quali facce devo diventare invisibili.
Nel caso in cui stessimo lavorando con PV3D versione 2 beta (la più aggiornata) vi sono anche dei parametri che servono per indicare con precisione a quali facce applicare l’invisibilità o la visibilità interna:
Cube.NONE, FRONT, BACK, LEFT, RIGHT, TOP, BOTTOM, ALL.
Vediamo degli esempi (da realizzarsi sempre con la versione 2) fra di loro alternativi:
var insideFaces:int = Cube.TOP; //rende visibile, fra quelle interne, soltanto la faccia superiore
var cube:Material = new Cube(m, w, d, h, sS, sT, sH, insideFaces);
----------------------------------------------------------
var insideFaces:int = Cube.LEFT + Cube.RIGHT + Cube.BOTTOM; //rende visibile solo quella sin, dest e inferiore.
var cube:Material = new Cube(m, w, d, h, sS, sT, sH, insideFaces);
--------------------------------------------
var insideFaces:int = Cube.ALL - Cube.FRONT; //tutte le facce interne saranno visibili tranne quella frontale
var cube:Material = new Cube(m, w, d, h, sS, sT, sH, insideFaces);
Allo stesso modo lavora il parametro “ecludeFaces” (sempre solo nella vers 2).
Collada
È fondamentale un accenno al metodo d’importazione in PV3D dei file collada (.DAE) di grafica 3D, questi riproducono un progetto 3D in formato XML, in pratica rappresentano una delle tante tipologie di file con cui salvare un progetto tridimensionale realizzato con un software di grafica 3D (i principali che permettono tale esportazione sono “3D studio max”, “Maya”, “Blender”, “Cinema 4d v.11″ e “Swift 3D”). Così, realizzando un modello 3D (si consiglia più semplice possibile perché funzioni bene in Flash) lo si può importare in PV3D per aggiungerci una certa animazione o interattività.
Personalmente però preferisco, il più delle volte, realizzarmi la grafica 3D, soprattutto se deve essere semplice, direttamente con le primitive che abbiamo analizzato.
Realizziamo un primitiva 3D in PV3D
Vediamo ora di lavorare con un esempio completo, il nostro obiettivo è realizzare il cubo (o qualsiasi altra primitiva), renderizzarlo e farlo girare su stesso per gustarci la tridimensionalità.
Ovviamente si tratta di un progetto di base, che poi, in altri tutorial, vedremo d’implementare un pochino.
Apriamo un nuovo file di actionscript (vi consiglio di usare il programma gratuito “FlashDevelop”) e nominate il file “cubo” (ricordate che il nome del file deve essere uguale a quello inserito per la “public class” principale e per la “public function” principale), solo dopo creeremo il file .fla ; ricordate però di salvare la cartella “org” di PV3D (scaricabili da qui vers. 1.5) accanto a dove salvate i file di questo progetto.
//importiamo ciò che ci serve, anche dal codice PV3D
package {
import flash.events.Event;
import flash.display.Sprite;
import org.papervision3d.scenes.*;
import org.papervision3d.objects.*;
import org.papervision3d.cameras.*;
import org.papervision3d.materials.*;
public class cubo extends Sprite
{
var contenitore:Sprite = new Sprite();
var mioCubo:Cube = new Cube();
public function cubo():void {
//creiamo un contenitore (una specie di clip) che conterrà
//tutta la scena3D e centriamola. Esistono anche altri
//metodi per inserire la Scena3D nello stage
contenitore.x = stage.stageWidth * 0.5;
contenitore.y = stage.stageHeight * 0.5;
//aggiungiamo il contenitore allo stage
addChild(contenitore);
//inseriamo la scena3D nel contenitore
var scene:Scene3D = new Scene3D(contenitore);
var camera:Camera3D = new Camera3D();
camera.zoom = 2;
//se togliamo il commento seguente spostiamo la camera in
//avanti sin dentro il cubo e ne visualizziamo l'interno
//camera.z = -200;
//creiamo un materiale per le facce del cubo partendo da una
//immagine che dobbiamo inserire nella libreria nel file .fla
var bam:BitmapAssetMaterial = new BitmapAssetMaterial("flash");
bam.oneSide = false;
bam.smooth = true;
//oppure creiamo una maglia che visualizza solo i contorni
var allM:WireframeMaterial = new WireframeMaterial();
//avviamo la funzione per creare il cubo
creaCubo();
function creaCubo():void {
//definiamo i parametri del cubo.
var w:Number = 500;
var d:Number = 500;
var h:Number = 500;
var sS:int = 2;
var sT:int = 3;
var sH:int = 4;
//creiamo il cubo
mioCubo = new Cube(bam, w, d, h, sS, sT, sH);
//definiamo altri parametri iniziali del cubo
mioCubo.x = 0;
mioCubo.y = 0;
mioCubo.z = 0;
mioCubo.rotationY = 20;
mioCubo.rotationX = 35;
//aggiungiamo il tutto nella scena
scene.addChild(mioCubo);
}
//aggiungiamo un listener per l'ascolto continuo
this.addEventListener(Event.ENTER_FRAME, render);
function render(e:Event):void {
//impostiamo che la rotazione X e Y del Cubo si modifichi
//ogni istante a seconda della posizione del mouse
//sullo stage (quando il mouse è al centro tutto si ferma)
mioCubo.rotationY += (stage.mouseX - (stage.stageWidth/2)) / 30;
mioCubo.rotationX += (stage.mouseY - (stage.stageHeight/2)) / 30;
//ovviamente ogni istante dobbiamo renderizzare la scena
scene.renderCamera(camera);
}
}
}
}
Infine creiamo un file .fla (AS3) nuovo, inseriamo nella libreria il logo di Flash (presente nei file di progetto inclusi), premiamo tasto destro su di esso, clicciamo “proprietà” e in basso clicchiamo su “esporta per Actionscript”, dopo modifichiamo il nome nella casella “classe” appena sopra ed inseriamo “flash” (lo stesso nome inserito quando abbiamo creato la “BitmapAssetMaterial”).
E voilà… ecco a voi il vostro cubo ruotante!
In conclusione ringrazio John Lindquist autore dell’articolo in inglese a cui mi sono ispirato.








Dicembre 17th, 2008 at 17:46
Ciao, complimenti e grazie per aver creato questo blog, chiaro, utilissimo ed adatto anche a chi, come me non si è mai cimentato con il 3d ma possiede qualche conoscenza di base di action script. Papervision è davvero spettacolare per i risultati che consente di ottenere e per la fluidità e leggerezza degli swf prodotti. Seguirò costantemente il tuo blog e non mancherò di pubblicizzarlo a tutti quelli che come me muovono i primi passi verso papervision3D.
Ciao
Luglio 18th, 2009 at 11:44
ciao, ho trovato per caso la tua guida su papervision, direi molto utile…ho scaricato papervision 2 e ho settato il percorso della libreria…ho testato il funzionamento con questo semplice codice e funziona!
package{
import flash.display.Sprite;
import flash.events.Event;
import org.papervision3d.view.Viewport3D;
import org.papervision3d.scenes.Scene3D;
import org.papervision3d.cameras.Camera3D;
import org.papervision3d.materials.ColorMaterial;
import org.papervision3d.objects.primitives.Plane;
import org.papervision3d.render.BasicRenderEngine;
public class PV3D extends Sprite
{
private var viewport: Viewport3D;
private var scene: Scene3D;
private var camera: Camera3D;
private var material: ColorMaterial;
private var primitive: Plane;
private var renderer: BasicRenderEngine;
public function PV3D():void
{
//viewport = new BasicRenderEngine(width, height, scaleToStage, interactive);
viewport = new Viewport3D(550, 400, false, true);
addChild(viewport);
//instantiates a Scene3D instance
scene = new Scene3D();
//instantiates a Camera3D instance
camera = new Camera3D();
//renderer draws the scene to the stage
renderer = new BasicRenderEngine();
//ColorMaterial, doubleSided draws the color on both sides of the geometry normals
material = new ColorMaterial(0×333333);
material.doubleSided = true;
//primitive = new Plane(material applied to object, width, height, wSegments, hSegments);
primitive = new Plane(material, 200, 200, 3, 3);
scene.addChild(primitive);
//set up enterFrame event
addEventListener(Event.ENTER_FRAME, onEnterFrame);
//define enterFrame Method, render the PV3D Scene and animate the primitive
function onEnterFrame(e:Event):void
{
primitive.rotationY += 2;
renderer.renderScene(scene, camera, viewport);
}
}
}
}
———————
Il problema che quando cerco di utilizzare il tuo codice, mi da 4 errori…:
1046: Type was not found or was not a compile-time constant: XrayLog.