notJustCode.it
 
\\ Home : Articoli
Vertici e Movimenti
Di RobyDx (del 15/01/2007 @ 21:34:13, in DirectX9, linkato 4282 volte)

Finalmente cominciamo ad adoperare DirectX. Ovviamente questo tutorial non basterà a fare tutto quello che volete ma rappresenta la base su cui iniziare. Spero che abbiate bene a mente il processo di inizializzazione del device. Come banalmente dice il nome, la grafica 3D rappresenta un sistema di visualizzazione tridimensionale di oggetti che vengono posizionati sullo schermo seguendo un piano cartesiano con tre assi X,Y,Z.

assi cartesiani coordinate 3d

Di questo piano cartesiano possiamo settare ogni cosa, dall’orientamento degli assi alla posizione da cui guardarlo. L’unità di misura non ha nulla a che vedere con lo schermo e si chiama semplicemente unità. Questo fa in modo che in ogni risoluzione ciò che vedrete sarà sempre della giusta dimensione (ovviamente a parità di settaggi). Gli oggetti posizionati nel mondo 3D formeranno la scena del gioco. In grafica 3D un oggetto, come ad esempio un personaggio tridimensionale, è una figura geometrica interamente composta da triangoli chiamati “poligoni”. Non importa quanto un personaggio sia complesso o abbia curve morbide: se osservato attentamente e da vicino è composto da triangoli tridimensionali posizionati nello schermo. A loro volta i triangoli sono composti da vertici, ossia 3 punti posizionati nello spazio che formano la figura e portano con sé tutta una serie di informazioni per ogni cosa che possa servire in un ambiente 3D come ad esempio Texture (immagini che ricoprono i poligoni per formare ad esempio il viso del personaggio) e sul modo in cui questi riflettono la luce.
L’oggetto composto dai poligoni viene mosso tutto insieme ma DirectX non chiede certo la posizione che esso occupa tramite una banale serie di numeri (ad esempio la posizione X,Y,Z). Il sistema di controllo usato in DirectX e valido nella geometria tridimensionale è la matrice. Una matrice è una griglia di numeri (nel caso di DirectX di 4x4) che consente di impostare la posizione esatta di un oggetto, comprese rotazioni e ridimensionamenti.
Anche la telecamera e l’impostazione del piano cartesiano è dettato da matrici. Ma come impostare tali matrici? DirectX comprende una serie lunghissima di istruzioni utili per la gestione di matrici, a partire da una variabile che rappresenta una matrice, l’oggetto Matrix.
Cominciamo a settare il nostro mondo. Creerò una routine con un settaggio base.

Telecamera

La telecamera viene impostata tramite una matrice chiamata View Matrix. Questa viene passata al device tramite

device.Transform.View = ViewMatrix

Per settare una telecamera esiste una comoda istruzione che ha bisogno di un’altra variabile la Vector3. Ecco un esempio

device.Transform.View = Matrix.LookAtLH(New Vector3(0, 0, -30), New Vector3(0, 0, 0), New Vector3(0, 1, 0))

Il primo vettore rappresenta il punto di vista, ossia la posizione da cui guardiamo, nel nostro caso da 0,0,-30. Il secondo vettore è il punto dove guardiamo mentre l’ultimo indica la direzione dell’alto. Significa settare ad 1 per avere quel punto come alto, nel nostro caso la Y sarà l’asse verticale e il verso positivo sarà alto. Questa è una visione semplicistica perché settando in modo più raffinato potremo girare l’asse come vogliamo. Per gli occhi questo sembrerà come se la telecamera stesse storta, utile per alcuni effetti. La telecamera può essere cambiata in ogni momento per aggiornare la visuale.
La telecamera non basta a settare la visuale di base. Una seconda matrice è la projection matrix che imposta la zona visiva.

device.Transform.Projection = Matrix.PerspectiveFovLH(CSng(Math.PI / 3), 4 / 3, 1, 2000)

Il primo valore è l’angolo della visuale espresso in radianti. Nella misura in radianti il Pi greco (di cui abbiamo una costante nella classe Math di VB.Net) equivale a 180° e di conseguenza dividendolo per 3 ne avremo 60°. Le migliori visuali sono tra i 90° e i 45° ma come al solito dipende da voi. Il secondo valore è la proporzione. Impostandola ad uno avremo che gli assi saranno uguali sullo schermo ma essendo lo schermo in genere in proporzione 4:3 un cubo non sarà tale. Dovrete quindi specificare un valore. Ad esempio se avete un monitor in 16:9 la migliore visualizzazione sarà 16/9. I due ultimi numeri sono il piano frontale e finale. Gli oggetti che saranno più vicini della distanza frontale o più lontani di quella finale non saranno visibile. Questo serve per il clipping, quel processo che fa sparire gli oggetti lontani per alleggerire il carico del PC. Se c’è un muro a distanza 30 allora impostando a 30 il piano finale tutto ciò che è dietro non si vedrà e il gioco andrà più veloce. La posizione di un oggetto si imposta tramite la MatWorld. A differenza delle matrici view e proj, la matWorld viene cambiata continuamente. Ad esempio possiamo avere un cubo in memoria (non sullo schermo). Questo cubo si trova nella sua posizione base al centro dello schermo e ha lati tutti di uno. Al device noi passeremo una prima matrice che sposta sulla X di 3 unità. Disegnamo il cubo e questo sarà spostato come specificato. Sempre con lo stesso cubo in memoria passiamo un’altra matrice con una rotazione e ridisegniamolo. Quando effettueremo il present vedremo due cubi, ognuno nella giusta posizione. Molti nel precedente DirectX non capivano come spostare più oggetti. DirectX non fa altro che tenere in memoria gli oggetti in una posizione base ed effettua una serie di copia tra gli oggetti in memoria e lo schermo. Basta cambiare la matrice prima di ogni copia e l’oggetto sarà copiato lì. La posizione sarà quella con cui è stato generato (quando caricheremo da file sarà quella con cui un editor 3D ha salvato).
Le matrici sono impostate moltiplicando tra loro più matrici contenenti dei movimenti. Ad esempio DirectX può creare una matrice spostamento in alto di 3 unità e una rotazione di 90°. Se moltiplichiamo le matrici l’oggetto compierà istantaneamente i due movimenti in seguenza. Di conseguenza l’ordine è fondamentale perché è diverso ruotare e poi traslare e viceversa.
Ad esempio

Dim m As Matrix
Dim m1 As Matrix
Dim m2 As Matrix
m1 = Matrix.Scaling(1, 1, 1)
m2 = Matrix.RotationZ(angoloX )
m = Matrix.Multiply(m1, m2)
device.Transform.World = m

Viene creata una matrice scale (che ridimensiona l’oggetto sui tre assi) e una rotazione. La matrice m viene creata moltiplicando le due matrice tramite l’istruzione Matrix.Multiply. Infine viene passata al device.
Le 5 trasformazioni base da usare sono:

Matrix.Translation(x, y, z)
Matrix.RotationX(angoloX)
Matrix.RotationY(angoloY)
Matrix.RotationZ(angoloZ)
Matrix.Scaling(x, y, z)

Gli angoli sono in radianti (moltiplicarli per 3.14/180)
La prima è per traslare, la 2,3,4 per le rotazioni sugli assi, la 5 per il ridimensionamento.
Matematicamente le cinque operazioni creano matrici come queste in foto

matrice traslazione

matrice rotazione 

matrice rotazione

matrice rotazione

matrice per scalare proporzioni

Per velocizzare il calcolo ho creato dopo 30 minuti di calcolo matriciale (faccio ingegneria e riesco a fare queste cose) una ruotine che prende direttamente tutti i valori (gli angoli stavolta in gradi) e che effettua le 5 trasformazioni in serie. Questo per risparmiare anche in velocità essendo la mia routine 2.5 volte più veloce del processo normale.

Public Sub muoviObj(ByVal scalaX As Single, ByVal scalaY As Single, ByVal scalaZ As Single, ByVal angleX As Long, ByVal angleY As Long, ByVal angleZ As Long, ByVal posX As Single, ByVal posY As Single, ByVal posZ As Single)
'creazione rapida matworld
Dim CosRx As Single, CosRy As Single, CosRz As Single
Dim SinRx As Single, SinRy As Single, SinRz As Single
Dim mat1 As Matrix
'
CosRx = Math.Cos(angleX * rad) 'Used 6x
CosRy = Math.Cos(angleY * rad) 'Used 4x
CosRz = Math.Cos(angleZ * rad) 'Used 4x
SinRx = Math.Sin(angleX * rad) 'Used 5x
SinRy = Math.Sin(angleY * rad) 'Used 5x
SinRz = Math.Sin(angleZ * rad) 'Used 5x
With mat1
    .M11 = (scalaX * CosRy * CosRz)
    .M12 = (scalaX * CosRy * SinRz)
    .M13 = -(scalaX * SinRy)
'
    .M21 = -(scalaY * CosRx * SinRz) + (scalaY * SinRx * SinRy * CosRz)
    .M22 = (scalaY * CosRx * CosRz) + (scalaY * SinRx * SinRy * SinRz)
    .M23 = (scalaY * SinRx * CosRy)
'
    .M31 = (scalaZ * SinRx * SinRz) + (scalaZ * CosRx * SinRy * CosRz)
    .M32 = -(scalaZ * SinRx * CosRz) + (scalaZ * CosRx * SinRy * SinRz)
    .M33 = (scalaZ * CosRx * CosRy)
'
    .M41 = posX
    .M42 = posY
    .M43 = posZ
    .M44 = 1.0#
End With
device.SetTransform(TransformType.World, mat1)
End Sub

Dategli i 9 valori e fa tutto lei.
Ora passiamo agli oggetti 3D.

Poligoni

Un oggetto 3D è composto come abbiamo detto da triangoli composti a loro volta da 3 vertici. Un quadrato può essere realizzato con 2 triangoli e quindi 6 vertici. Un cubo ha 6 faccie per un totale di 36 vertici. Per disegnare occorre quindi impostare un array di vertici, settarli e passarli al device. Come faccio allora a disegnarmi un personaggio di 1000 poligoni? No panic esiste un modo per caricare modelli 3D già pronti(userete al 99,9% sempre quelli) ma è meglio spiegare e vedere cosa c’è sotto per capire bene. I vertici possiedono determinate caratteristiche che possono essere settate a piacimento. Di solito vengono usate le coordinate del punto, le normali e la posizione delle texture. Le normali servono a proiettare nel giusto verso le luci (ora non ci servono e neanche le texture). Si possono creare però anche vertici con più coordinate texture o con colori incorporati o addirittura con posizione dei punti espressi in pixel anziché in unità (utili solo in qualche caso perché non li si può spostare con la matrice).
Nel mio caso disegnerò un solo triangolo e quindi basta un array di soli 3 vertici. Userò un formato normale (in genere si usa questo vertice).

Dim poligoni(2) As CustomVertex.PositionNormalTextured

I formati sono tutti accessibili tramite CustomVertex
Ora li setto a formare un triangolo

poligoni(0).X = 0
poligoni(0).Y = 0
poligoni(1).X = 5
poligoni(1).Y = 5
poligoni(2).X = 5
poligoni(2).Y = 0

Attenzione cosa importante!!!! I triangoli sono visibili solo se sono disposti in senso orario rispetto a dove si guarda. Per disegnare un cubo dovrete quindi mettervi con un po’ di pazienza per disporli a dovere in senso orario secondo la faccia che vi serve (o se li mettete al contrario vedrete l’interno ma non l’esterno). Ora settate la matrice MatWorld e dite al device che vertice state usando.

device.VertexFormat = CustomVertex.PositionNormalTextured.Format

Notate che è lo stesso usato nella dischiarazione ma si usa la proprietà format.
Ora disegnate. Notate, è un triangolo quindi è un solo poligono o in DirectX primitiva

device.DrawUserPrimitives(PrimitiveType.TriangleList, 1, poligoni)

Triangle list è il tipo che stiamo usando. Ma ci torniamo dopo.
Tutto, dalla matrice alla istruzione deve essere tra BeginScene e EndScene.
Se fossero stati 2 triangoli dovevate settare 6 vertici e specificare 2 primitive anziche 1.
Le primitive possono essere anche solo delle linee o dei punti. Se ad esempio usavate PointList invece di triangleList sarebbe stato disegnato solo un punto. I poligoni infatti sono primitive solo se è impostato il device a triangleList. Se impostate a pointList allora i punti sono primitive e tre vertici sono appunto 3 primitive. Nel caso delle lineList sarebbero state le linee le primitive. Esistono 6 tipi di settaggi per primitive. Ecco delle immagini chiarificatrici.
POINTLIST 6 vertici, 6 primitive

POINTLIST 6 vertici, 6 primitive


LINELIST 6 vertici, 3 primitive

LINELIST 6 vertici 3 primitive


LINESTRIP 6 vertici, 5 primitive (linee collegate in serie)

LINESTRIP 6 vertici 5 primitive


TRIANGLELIST 6 vertici, 2 primitive

TRIANGLELIST 6 vertici 2 primitive


TRIANGLESTRIP 6 vertici, 4 primitive (triangoli collegati in serie)

TRIANGLESTRIP 6 vertici 4 primitive


TRIANGLEFAN 6 vertici, 4 primitive ma tutti i punti collegati al primo vertice.

TRIANGLEFAN 6 vertici 4 primitive ma tutti i punti collegati al primo vertice


Nei tipi strip i triangoli o le linee continuano dall’ultimo punto. Per un quadrato bastano ad esempio 4 vertici anziché 6.
Per i formati dei vertici è abbastanza intuibile cosa possiedono dato che i nomi comprendono tutte le caratteristiche. Ad esempio TransformedColored è in pixel e ha il colore. Ricordate di settare ad 1 il valore RHW quando compare. Al momento fregatevene di normali e di coordinate texture. Nei prossimi tutorial verranno spiegate queste cose.
Passiamo ora agli ultimi dettagli.
Settiamo le ultime cose per la nostra prima visualizzazione

device.RenderState.ZBufferEnable = True 'Z buffer on
device.RenderState.Lighting = False 'luci spente
device.RenderState.ShadeMode = ShadeMode.Gouraud 'gouraud mode

Con la prima istruzione ho attivato lo Zbuffer. Lo Zbuffer è responsabile del posizionamento in profondità degli oggetti. Se io ad esempio disegno un cubo e poi un altro dietro ma parzialmente visibile lo Z buffer interviene per disporre tutto nel migliore dei modi. Se lo disattiviamo i poligoni dietro si troverenno davanti se disegnati dopo e la cosa non và (anche se a volte può essere utile).
Con la seconda ho Disattivato le luci. Per le luci aspettate i prossimi tutorial.
Infine con la terza ho impostato il tipo di ombra. Per ombra si intende il modo con cui le luci vengono sfumate. Ci sono 2 tipo (il tipo Phong non è supportato): il flat mode in cui ogni triangolo ha un suo colore e il Gouraud in cui il colore viene sfumato tra tutti. Questo è significativo per i colori, soprattutto in presenza di luci, dato che con il flat si vedrebbero tutti i triangoli (potete provare già con il mio esempio a cambiare).
Importante un aggiunta da fare al clear

device.Clear(ClearFlags.Target Or ClearFlags.ZBuffer, Color.Blue, 1, 0)

Notate I due ClearFlags. In DirectX si possono passare più argomenti collegati con degli or e in questo caso ho specificato di pulire il target e lo Z buffer. Anche lo Z buffer va pulito altrimenti si otterranno degli effetti indesiderati (se ad esempio disegno un cubo e cancello solo il target tutto ciò che verrà disegnato dietro quella zona non si vedrà come se il cubo fosse ancora lì. Utile per effetti speciali ma non ora).
Credo di aver terminato con questo tutorial. Ricordate comunque che se il tipo è trasformed questo se ne fregherà di matrici, luci e Z buffer. Vi lascio all’esempio. Fate prove su prove, è l’unico modo per imparare.

Esempio VB.Net

Esempio C#

Articolo Articolo  Storico Storico Stampa Stampa
I commenti sono disabilitati.
"È più facile spezzare un atomo che un pregiudizio."

Albert Einstein


Cerca per parola chiave
 

Titolo
Articoli (4)
C++ (4)
Direct3D10 (30)
Direct3D11 (20)
DirectX9 (82)
DotNet (10)
English (9)
FanGames (22)
ManagedDX11 (2)
Materiale Utile (4)
News (39)
Shader Library (12)
SharpDX (1)
Software (25)
Tecnologia (19)
Varie (9)

Gli interventi più cliccati

Ultimi commenti:
If you wish to retai...
23/05/2013 @ 13:07:45
Di chanel outlet
You deficit of self-...
23/05/2013 @ 13:07:13
Di cartier watches uk
Reinforce your own l...
23/05/2013 @ 13:06:37
Di replica watches
Whenever you"re shiv...
23/05/2013 @ 13:06:11
Di swiss replica watches
It's likely you have...
23/05/2013 @ 13:05:02
Di chanel handbags
Cheap automobile ins...
23/05/2013 @ 13:04:28
Di replica watches

Titolo
Con quale tecnologia state realizzando o avete intenzione di realizzare i vostri progetti?

 DirectX11
 DirectX10
 DirectX9
 XNA
 DirectX8 o Precedenti
 OpenGL
 Motori grafici già pronti
 Altro

Titolo
Umorismo (17)

Le fotografie più cliccate



Ci sono 11 persone collegate
Sono state visualizzate  pagine

18/08/2019 @ 19:52:30
script eseguito in 48 ms