in

DotNetSide

Dot Net South Italy Developers User Group

Articoli

Articoli pubblicati dagli iscritti a .netSide

Introduzione alla grafica 3D con WPF

Autore: Bruno (DaViL) Fortunato

INTRODUZIONE

Windows Presentation Foundation (da ora WPF) è il nuovo framework per lo sviluppo di interfacce grafiche che sarà introdotto con l'avvento di Windows Vista. Con questa nuova tecnologia le interfacce saranno interamente gestibili tramite un comodo linguaggio dichiarativo (in stile HTML per intenderci) chiamato XAML.

Se fino ad oggi, utilizzando le GDI gli oggetti grafici sono stati renderizzati secondo il metodo raster, con WPF tutti i controlli saranno creati in grafica vettoriale il che non è banale se condideriamo l'utilità di non dover riscrivere un'interfaccia grafica per ogni risoluzione.

Con la grafica di tipo vettoriale, infatti, gli oggetti vengono renderizzati di volta in volta secondo specifici algoritmi e questo porta ad avere un'immagine sempre nitida ad ogni risoluzione.

Un'altra interessante innovazione sta nell'introduzione della grafica tridimensionale. Grazie all'integrazione con Direct3d infatti è possibile, con poche righe di codice, creare scene 3D di sicuro effetto.

In questo articolo ci concentreremo proprio su questo interessante aspetto, e proveremo a creare una semplice scena tridimensionale utilizzando la sintassi XAML .

REQUISITI

Per implementare l'esempio nell'articolo non abbiamo bisogno di altro che dell'SDK di WinFX. Per scrivere il codice possiamo utilizzare la comoda utility presente nell'SDK, l'XAMLPad.

Il tutto è scaricabile da qui

ALCUNE NOZIONI BASE SULLE SCENE 3D

Prima di accedere alla pratica è necessario ripassare alcuni semplici concetti riguardo lo spazio tridimensionale inteso nella computer-grafica.

Credo che tutti conoscano il piano cartesiano e le rispettive variabili x e y, che indicano a loro volta la larghezza e l'altezza. Come sembra ovvio, in uno spazio 3D è necessaria un'altra variabile, z, che denota la profondità.
Lo spazio 3D, in WPF, è associato all'oggetto Viewport3D.

L'oggetto fondamentale di una scena 3D è il Punto. Tramite il punto è possibile definire praticamente ogni oggetto in una scena 3D. L'unione di piu punti infatti permette di creare oggetti primitivi, ad esempio il Triangolo, che, uniti, permettono di creare modelli molto complessi.

In WPF il punto è associato all'oggetto Point3D e, come ovvio, richiede la definizione di tre valori di tipo double: x, y e z. L'intersezione delle 3 assi sul piano cartesiano rappresentano il punto 0 ( Point3D(0, 0, 0) ).

La rappresentazione delle direzioni, invece, avviente tramite un altro oggetto: il vettore ( Vector3D in WPF ) anch'esso identificato con le solite x, y e z. Diversamente da quanto accade nei piani 2D, nei piani 3D la posizione di un vettore è ininfluente in quanto essi indicano semplicemente la direzione.

Nella figura i 2 vettori v1 e v2 sono identici in quanto entrambi si dirigono verso l'alto. Volendoli definire in WPF dovremmo scrivere:

Vector3D v1 = new Vector3D(0, 1, 0);
Vector3D v2 = new Vector3D(0, 1, 0); 

Nel piano, l'asse x corrisponde a Vector3D(1, 0, 0), l'asse y a Vector3D(0, 1, 0) e l'asse z a Vector3D(0, 0, 1).

IMPOSTAZIONE DI UNA SCENA 3D

Come abbiamo gia accennato, per la definizione di uno spazio 3D in WPF si utilizza il Viewport3D. In XAML, come possiamo vedere di sotto, è semplicissimo implementarlo.

<Viewport3D Width="320" Height="200">
...
</Viewport3D>

Dove siamo e dove guardiamo?

A questa domanda WPF risponde con la ProjectionCamera. Grazie a questo oggetto possiamo informare il nostro Viewport3D del luogo in cui ci troviamo e della direzione in cui stiamo guardando.

Dalla ProjectionCamera derivano 2 oggetti. La PerspectiveCamera e la OrthographicCamera. Come gli stessi nomi suggeriscono, questi 2 oggetti sono molto simili ma si differenziano nel modo di visualizzare gli oggetti. Nell'esempio utilizzeremo la PerspectiveCamera in quanto la visualizzazione in prospettiva rappresenta quella più vicina alla realtà rispetto a quella ortografica, che viene utilizzata principalmente per la creazione di grafici tridimensionali.

Ecco come configurare la camera del nostro Viewport3D

<Viewport3D.Camera> 
<PerspectiveCamera Position="-0.7,1.8,5" LookDirection=".2,-.3,-1" />
</Viewport3D.Camera>

Le proprietà Position e LookDirection sono già state illustrate e mostrano appunto la posizione in cui si trova l'osservatore e la direzione verso cui sta guardando.

A dir il vero ci sono numerose altre impostazioni per la PerspectiveCamera, ma per il momento verranno tralasciate.

CREAZIONE DI UNA PIRAMIDE

Una volta decisa la posizione in cui l'osservatore si trova, dobbiamo avere qualcosa da osservare. La primitiva piu semplice di una scena 3D è il triangolo. Il triangolo è formato da 3 punti. Una volta definita quindi la posizione di questi 3 punti, WPF si preoccuperà di unirli e di renderizzare quindi il nostro triangolo! L'unione di 4 triangoli ci permettera' di creare la nostra piramide.

Per poter definire i punti di un oggetto 3D, WPF ci mette a disposizione una classe: GeometryModel3D. L'oggetto in questione ha una proprieta, Geometry, nella quale dobbiamo definire i vari punti che formeranno i triangoli che compongono la piramide.

<GeometryModel3D.Geometry>
<MeshGeometry3D>
<MeshGeometry3D.Positions>
<!-- Faccia anteriore -->
<Point3D X="0" Y="1" Z="0"></Point3D>
<Point3D X="-1" Y="-1" Z="1"></Point3D>
<Point3D X="1" Y="-1" Z="1"></Point3D>

<!-- Faccia sinistra -->
<Point3D X="0" Y="1" Z="0"></Point3D>
<Point3D X="-1" Y="-1" Z="-1"></Point3D>
<Point3D X="-1" Y="-1" Z="1"></Point3D>

<!-- Faccia destra -->
<Point3D X="0" Y="1" Z="0"></Point3D>
<Point3D X="1" Y="-1" Z="1"></Point3D>
<Point3D X="1" Y="-1" Z="-1"></Point3D>

<!-- Faccia posteriore -->
<Point3D X="0" Y="1" Z="0"></Point3D>
<Point3D X="1" Y="-1" Z="-1"></Point3D>
<Point3D X="-1" Y="-1" Z="-1"></Point3D>

</MeshGeometry3D.Positions>
</MeshGeometry3D>
</GeometryModel3D.Geometry>

Ma di cosa è fatta questa piramide? Di acciaio, di plastica, di vetro? Di che colore è? Bhe, per rispondere a queste domande, il GeometryModel3D ci mette a disposizione la proprietà Material, nel quale settiamo appunto il tipo di materiale di cui l'oggetto è composto.

Nel nostro esempio utilizzeremo un materiale semplicissimo ( DiffuseMaterial ) che colorera' la nostra piramide di giallo

<GeometryModel3D.Material>
<DiffuseMaterial Brush="Yellow" />
</GeometryModel3D.Material>

 

AGGIUNTA DI LUCI ALLA SCENA

Se noi provassimo ora a compilare l'esempio vedremmo una piramide nera. Come mai? Eppure abbiamo impostato un materiale giallo. Bhe... la risposta è semplice. Vediamo nero semplicemente perchè è tutto buio!

E' necessario quindi accendere una luce.

In WPF esistono 4 tipi di luce

  • Ambient: questa luce è paragonabile al sole. E' onnipresente su tutti gli oggetti della scena e tutti i lati in maniera uguale ed uniforme. Classe: AmbientLight
  • Directional: un'altra luce onnipresente. La differenza con AmbientLight è che possiede una direzione e che quindi agisce solo sui lati basati sulla direzione definita. Classe: DirectionalLight
  • Point: questo oggetto emette da un punto definito luce in ogni direzione. Classe: PointLight
  • Spot: una luce che richiede un punto ed una direzione ed è quindi utile per illuminare un obbiettivo definito. Classe: SpotLight

Per illuminare la nostra piramide utilizzeremo una luce ambientale e due luci direzionali. La prima luce direzionale sarà di colore rosso e illuminerà di fronte la piramide, la seconda sara' bianca e la illuminerà da destra verso sinistra.

<AmbientLight Color="DarkGray"></AmbientLight>
<DirectionalLight Direction="0, 0, -1" Color="Red"></DirectionalLight>
<DirectionalLight Direction="-1, 0, 0" Color="White"></DirectionalLight>

ROTAZIONE DELLA PIRAMIDE

In WPF è possibile applicare diversi tipi di trasformazioni ad un oggetto 3D. E' possibile, scalarlo, translarlo, ... e, come a noi interessa, ruotarlo. Per ruotare la piramide utilizzeremo una AxisAngleRotation3D. Con questo oggetto possiamo decidere l'asse è l'angolo di rotazione. Noi vogliamo far ruotare la piramide sull'asse Y di n gradi e come già detto l'asse Y corrisponde al Vector3D(0, 1, 0).

Non specifico i gradi della rotazione perchè essi andranno da 0 a 360 ed il valore verrà modificato utilizzando il sistema di animazioni integrato in WPF. Nella fattispecie utilizzeremo una DoubleAnimation.
Aggiungiamo quindi la trasformazione al GeometryModel3D

<GeometryModel3D.Transform>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D x:Name="Rotazione" Axis="0, 1, 0" Angle="0"></AxisAngleRotation3D>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</GeometryModel3D.Transform>

Come è possibile notare, l'oggetto AxisAngleRotation3D possiede un attributo, x:Name. In questo modo abbiamo instanziato l'oggetto e possiamo utilizzarlo quindi nella DoubleAnimation per modificare dinamicamente il valore della proprietà Angle.

Intercettiamo quindi l'evento Loaded del Viewport3D e implementiamo l'animazione che farà ruotare la nostra piramide

<Viewport3D.Triggers>
<EventTrigger RoutedEvent="Viewport3D.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetName="Rotazione"
Storyboard.TargetProperty="Angle"
From="0"
To="360"
Duration="0:0:10"
AutoReverse="False"
RepeatBehavior="Forever"
/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Viewport3D.Triggers>

CONCLUSIONI

Windows Presentation Foundation sembra avere le carte in regola per regalarci applicazioni di notevole impatto grafico.
Se fin'ora èra necessario utilizzare delle api esterne per creare scene 3D (Direct3d, OpenGL, ...) ora il tutto è perfettamente integrato ed ottenibile con poche righe di codice.
Speriamo solo che tutta questa semplicità e potenza non porti alla creazione di applicazioni esageratamente decorate che tralascino la sostanza è l'usabilità della stessa.
In allegato il sorgente XAML dell'esempio
Per ulteriori informazioni su Windows Presentation Foundation scaricare gli Hands-On-Labs da questo indirizzo
NB: L'articolo si basa sulla RC di WinFX di Febbraio 2006

 

 
 
Only published comments... Jun 11 2006, 07:27 AM by DotNetSide Staff
Filed under:
Attachment: WPF_3D_1.xaml

Comments

 

Blog di Bruno Fortunato said:

Sono sempre stato appassionato di grafica 3D ed onestamente quando ho visto le potenzialit&#224; di Windows...
June 11, 2006 9:07 AM
Powered by Community Server (Commercial Edition), by Telligent Systems