Come abbiamo visto DirectX usa degli array di vertici per rappresentare gli oggetti tridimensionali. Si suppone quindi che all'interno delle mesh ci siano array di vertici che vengano passati in qualche modo al device. Questo è corretto ma abbastanza approssimativo. La mesh tra i tanti campi che contiene (a noi nascosti) comprende 2 parti in cui sono contenuti i vertici e gli indici. I vertici sapete già cosa sono mentre forse non sapete cosa sono gli indici.
Una figura tridimensionale deve essere divisa in triangoli e come abbiamo visto dobbiamo riempire l'array di vertici in modo consecutivo per formare tutti i triangoli. Può capitare quindi che alcuni vertici debbano essere ripetuti. Ad esempio un cubo che ha solo otto vertici deve essere rappresentato con 12 triangoli ossia 36 vertici. Dato che i vertici occupano molta memoria (se contengono anche normali, coordinate texture e così via) si è preferito inserire un array di vertici senza ripetizioni (quindi solo gli 8 ipotetici) ed un array di short che determinano l'ordine con cui prenderli. Questi sono gli indici.
Gli indici sono in numero uguali al numero di triangoli moltiplicati per 3 (che vanno da 0 a n-1).
Inserendo i valori nell'array di vertici sarà quindi possibile ricostruire i triangoli e quindi l'intera figura. In realtà non si usano quasi mai gli array degli indici se non in qualche raro caso in cui occorra ricostruire la figura. Inoltre i vertici del nostro cubo potrebbero essere un pò più di 8 dato che esistono anche le normali e le coordinate texture ed è quindi necessario ripetere vertici uguali ma con altri componenti diversi. Rimane comunque il principio che non esistono 2 vertici identici nell'array dei vertici.
I vertici e gli indici sono memorizzati all'interno di due zone di memoria chiamate vertexbuffer e indexbuffer gestiti dagli oggetti omonimi che possono venir creati dalla mesh.
Tramite opportuni metodi potete accedere e modificare i valori in essi contenuti. Questo si rivela importante per milioni di cose come modificare la posizione o le coordinate texture o modificare la struttura dei vertici.
Ad esempio potete caricare un oggetto da file, modificare il tipo di vertice e dare un colore ad ognuno in base alle proprie esigenze (è quasi impossibile trovare un editor che invece dei materiali salvi i colori). Altri utilizzi possono anche essere l'estrazione del modello per ricevere informazione da utilizzare ad esempio per calcoli di collisione o per calcoli più elaborati. Negli effetti avanzati si usano spesso vertici molto particolari da gestire con l'accesso alla memoria.
Codice
Estrarre i dati non è particolarmente difficile ma è necessario che il formato della mesh e quello dell'array in cui andrete a caricare i valori corrispondano
Dim vertices() As Vertex = Nothing 'è un array dinamico
Dove il tipo vertex era un tipo che avevo definito così
Public Structure Vertex
Public p As Vector3
Public n As Vector3
Public tu, tv As Single
Public Const Format As VertexFormats = VertexFormats.Position Or VertexFormats.Normal Or_
VertexFormats.Texture1
End Structure
Ora con una funzione così estraete i vertici
Function getVertexArray(ByVal m As Mesh) As System.Array
Dim vertexBuffer As VertexBuffer = m.VertexBuffer
getVertexArray = vertexBuffer.Lock(0, GetType(Vertex), 0, m.NumberVertices)
vertexBuffer.Unlock()
End Function
Per usarlo basta porre l'array dinamico
vertices=getVertexArray(mesh)
Dichiarate un oggetto VertexBuffer e ponetelo uguale al VertexBuffer della mesh. Dopo di che blocchi la mesh in memoria con la funzione Lock della mesh. Questo significa fermare momentaneamente i vertici contenuti nella memoria della scheda video in modo da accellerare al massimo l'acceso.
La funzione richiede tra le opzioni il punto di partenza (vi consiglio uno 0 che indica l'inizio, è preferibile non fare errori qui), il tipo di vertice tramite un getType, un opzione (lasciate 0) ed il numero di vertici che andiamo a prendere (massimo il numero specificato dalla mesh). Il risultato sarà un array generico. Ponete l'array di vertici uguale al risultato e sbloccate la memoria con UnLock.
RICORDATEVI SEMPRE DI SBLOCCARE IL VERTEX BUFFER O VERRA' GENERATO UN ERRORE!!! SUI WINDOWS PIU' VECCHI (tipo il 98 o il me) POSSONO BLOCCARE IL PC COSTRINGENDOVI A RESETTARE!!!!!!!!!!!!!!!!!!
Quindi massima attenzione. La funzione in questo caso restituisce un array di vertici. Specificando il tipo verranno generati array differenti sempre a patto che il formato concordi con quello della mesh.
Per modificare il vertex buffer viene usata una funzione tipo questa
Sub setVertexArray(ByVal m As Mesh, ByVal v As Vertex())
Dim vertici As Vertex()
Dim vertexBuffer As VertexBuffer = m.VertexBuffer
vertici = vertexBuffer.Lock(0, GetType(Vertex), 0, m.NumberVertices)
Dim i As Integer
For i = 0 To vertici.Length - 1
vertici(i) = v(i)
Next
vertexBuffer.Unlock()
End Sub
Per usarlo basta passare alla funzione la mesh e l'array.
Come notate viene usata sempre la stessa istruzione e non faccio altro che modificare i valori dell'array restituito dal vertexbuffer. Questo perchè l'array che mi restituisce ha un puntatore (praticamente è legato all'array contenuto nella mesh) facendo in modo che ogni modifica influenzi il valore originario. Quindi mentre il vertexbuffer è bloccato potete manipolare l'array. Potete farlo anche direttamente, questa è solo una funzione che copia i valori 1 per 1 nell'array. Non funziona se ponete l'array uguale all'altro.
Queste funzioni sono state realizzate per il tipo scelto da me ma potete usare i tipi che volete e anzi: siate sicuri che i tipi concordino. Potete chiedere alla mesh il formato
mesh1.VertexFormat
O modificarlo con una clonazione di mesh
mesh1=mesh1.Clone(MeshFlags.Managed, formato, device)
Questa istruzione crea una nuova mesh modificando il tipo di vertice di quella vecchia e può assegnarsi a se stessa.
Per gli indici è più tranquillo
Function getIndexArray(ByVal m As Mesh) As System.Array
Dim indexBuffer As IndexBuffer = m.IndexBuffer
getIndexArray = indexBuffer.Lock(0, GetType(Short), 0, m.NumberFaces * 3)
indexBuffer.Unlock()
End Function
Come per i vertici ma con array di interi
Dim indici() As Short
indici = getIndexArray(mesh)
Non vi scrivo la funzione per modificare gli indici (mai l'adopererete) ma comunque è sufficiente modificare i valori dell'array quando è lockato.
Animazioni in tweening
Una delle possibilità che subito si presenta è la possibilità di effettuare il cosiddetto tweening. Il tweening è una tecnica per animare gli oggetto effettuando un processo di morfing ossia un mutazione tra un oggetto ad un altro. Tutti i vertici dell'oggetto vengono letteralmente spostati tra una posizione iniziale ed una finale in linea retta. In questo modo avendo un certo numero di posizioni medie potete far variare la posizione dell'oggetto tra i vari intermedi. Per questo si utilizza la formula di interpolazione lineare che genera un vertice compreso fra 2 vertici rappresentanti le due posizioni iniziali e finali. La funzione riceve un valore chiamato coefficiente di interpolazione compreso tra 0 e 1. Per il valore uguale a 0 il vertici corrisponde con quello iniziale mentre aumentando questo si avvicina via via a quello finale (coincide per valore uguale ad 1). Effettuando le interpolazioni fra i vari frame l'oggetto verrà deformato per assumere le varie posizioni.
La formula è
punto=(puntoFinale * coefficiente) + puntoIniziale * (1# - coefficiente)
Occorre effettuarla per ogni componente del vertice.
DirectX permette di effettuare un interpolazione direttamente con i vettori
Vector3.Lerp(v1(i).p, v2(i).p, interpolazione)
Utile per il formato usato da me.
Il tweening forse non è adattissimo per animazioni di modelli molto complessi (per il quale è più adatta l'animazione con animationSet o lo skinning mesh). Tuttavia rimane un sistema molto comodo per alcune mutazioni che non si possono effettuare con i primi 2 metodi (ad esempio mutazione di volto).
Vi propongo un esempio che effettua tramite tweening una animazione
Esempio VB.Net
Esempio C#