notJustCode.it
 
\\ Home : Articoli
Skin Animation
Di RobyDx (del 25/07/2007 @ 11:02:15, in DirectX9, linkato 3111 volte)

Lo skinning mesh è attualmente il migliore sistema di animazione esistente. Lo skinning unisce la possibilità di deformare gli oggetti come il tweening ma migliorando la qualità tramite curve più morbide e soprattutto lasciando il lavoro alla velocissima GPU della scheda video. DirectX offre pieno supporto allo skinning anche nel formato X in cui è possibile creare delle mesh in modo che siano animate tramite questo sistema e diversi software offrono la possibilità di creare modelli animati in skinning (esempio il 3D Studio Max). Utilizzare lo skinning non è semplicissimo per due motivi:
1. Non esistono classi che fanno interamente il lavoro di caricamento e gestione;
2. I modi con cui vengono salvati le animazioni in skinning sono spesso diversi a secondo del programma e del file;
Entrambi devono venire risolti da noi. Il sistema di caricamento di file x avviene quasi come se stessimo caricando un file binario in visual basic e dovremo quindi cercare di rendere il nostro algoritmo il più flessibile possibile adattandolo a tutti i problemi e le imprecisioni dei fileX con cui potremo venire a trovarci (oppure affezionarci ad un programma o ad un plugins ed imparare il suo sistema di salvataggio). Passiamo alla teoria, molto importante in questo tutorial. Un modello per lo skinning è un modello 3D in cui vengono posizionate delle bones (ossa) che come suggerisce il nome altro non sono che lo scheletro del modello. Ogni bone influenza i vertici che si trovano nelle sue vicinanze (parametri regolati dai programmi grafici) e permettono di deformare il modello semplicemente muovendole. Si capisce che con la giusta abilità si può ricostruire uno scheletro per il modello che gestisca ogni movimento (esempio tutte le principali articolazioni del corpo umano). Guardate l’immagine qui sotto:

 

image

 

Nel cilindro si vede l’ossatura (poligoni rossi). Curvare l’ossatura significa curvare il modello. In DirectX lo skinning mesh significa creare una geometry blending mesh in cui sono già settati i pesi (weight). Le matrici utilizzate dal geometry blending saranno appunto le matrici delle ossa che saranno caricate nell’animazione. Le ossa infatti saranno animate in modo del tutto simile alle mesh nelle animazioni con animation set. Le fasi di caricamento saranno queste nell’ordine:
1. Apertura del modello
2. Trasformazione del modello in una mesh con vertici in blending
3. Caricare l’animazione

Il processo di caricamento richiede molto intervento da parte del programmatore. Alla base di tutto c’è la funzione LoadHierarchyFromFile che si occupa di avviare il processo di caricamento. La funzione LoadHierarchyFromFile usa come parametro una classe allocate hierarchy di tipo astratto. Il programmatore deve sovrascrivere le funzioni definite all’interno per gestire il caricamento di oggetti Frame ed oggetti MeshContainer. Un frame è una struttura che contiene tutti i dati di una mesh (non le animazioni). Può contenere anche altri frame che ne contengono a loro volta altri. I frame figli avranno come matrice di trasformazione la concatenazione delle matrici genitori più l'eventuale matrice animazione. Utilizzeremo come classe frame una classe derivata da Frame con una matrice che conterrà la concatenazione fra le matrici della animazione. I frame contengono dati chiamati meshContainer che noi useremo derivati per avere dati extra per l'animazione in skinning mesh.

Breve descrizione della classe:

la classe contiene all'interno 3 classi:

Ah che deriva da allocatedHierarchy. In pratica l'istruzione

Dim animazione As AnimationRootFrame 'contenitore della animazione
Dim alloc As New AH 'classe per l'allocazione
'caricamento animazione
animazione = Mesh.LoadHierarchyFromFile(filesrc, MeshFlags.Managed, device, alloc, Nothing)

la classe passata all'istruzione LoadHierarchy sovrascrive i metodi. DirectX chiama i metodi come se fossere eventi e mentre carica la mesh passa i dati alle 2 funzioni. Le funzioni richiedono la restituizione di un frame ma noi restituiremo una classe derivata al frame, idem per le meshContainer.

'classe derivata da frame che contiene la matrice combinata
'ossia la generazione della matrice in animazione
Public Class frameD
    Inherits Frame
    Public matrixC As Matrix 'matrice combinata
End Class

La classe frame aggiunge la matrice che sarà la matrice del frame di destinazione.

Public Class MeshContainerDerived
    Inherits MeshContainer
    Public meshTextures() As Texture 'texture
    Public numAttr As Integer = 0 'numero attributi
    Public numInfl As Integer = 0 'numero influenze delle bones
    Public bones() As BoneCombination 'bones
    Public frameMatrices() As frameD 'frame figli
    Public offsetMatrices() As Matrix 'matrici delle bones
End Class

le funzioni di allocateHierarchy restituiranno i frame con matrice ad identità e la mesh container con tutti i dati inseriti. Tutti restituiranno classi derivate. Stavolta per avanzare i frame non bisogna fare altro che usare

animazione.AnimationController.AdvanceTime(t, Nothing)

t non indica il tempo nella animazione, ma la quantità di tempo da mandare avanti. Inserire 1 significa che ad ogni utilizzo l'animazione va avanti di 1. Per avere il tempo di durata di una animazione usate

Return animazione.AnimationController.GetTrackAnimationSet(0).Period

per settare la velocità usate invece

animazione.AnimationController.SetTrackSpeed(0, t)

Questo setta la velocità. In base alla velocità e allo scorrere del tempo le matrici degli oggetti animati si aggiorneranno.

Altre utili informazioni sono:

per avere l'istante del tempo

animazione.AnimationController.Time

per resettare il tempo.

animazione.AnimationController.ResetTime()

Dato che il tempo prosegue sempre aumentando potete azzerare il contatore quando volete. Il tempo può solo avanzare, attenzione. Per usare animazioni in senso inverso dovete regolare la velocità con un numero negativo.

La classe è abbastanza lunga ma ben commentata. La trovate all'interno dell'esempio: ricordate, serve directX9.0b e .Net 2003 per girare dato che .Net 2002 non può usare DirectX9.0b. Ecco qui l'API della Classe

Costruttori

Dim a as animationClass
a = new animationClass(filesrc,texP)

Crea una nuova classe da file. Occorre passargli il path del file e della directory contenente le texture

Metodi Publici

setSpeed(velo)
imposta la velocità. Inserendo velocità negative l'animazione procederà al contrario
a.getTime()
restituisce il tempo trascorso
a.getAnimationLenght()
restituisce la lunghezza dell'animazione
a.ProcessNextFrame(t, matrice)
avanza l'animazione impostando il tempo  e la matrice di trasformazione (world matrix)
a.resetTime()
azzera il contatore del tempo: questo non influenza l'animazione ma solo il contatore
a.drawMesh()
disegna la mesh

Proprietà publiche e condivise

a.animazione()
è l'animationRootFrame della mesh animata. Contiene tutte le informazioni sulla mesh
a.texPath()
proprietà condivisa da tutte le classi. contiene il path della texture dell'ultima animazione caricata

Potete derivare la classe sovrascrivendo il metodo drawMeshContainer (ad esempio per i vertex shader).

La classe permette di caricare sia le animazioni in skinning che quelle in animation set. Non funziona per le mesh immobili. Il modo migliore di vedere il funzionamento dell’intero processo è quello di studiare il codice ed in particolare le classi di gestione ed animazione.

Esempio VB.Net

Esempio C#

Animazioni multiple scritto da _Fa

Questo aggiornamento scritto da _Fa mostra come modificare la mia classe animationClass per renderla compatibile con il sistema multi-animation di DirectX. Ringrazio _Fa per l'ottimo lavoro fatto.

Modifiche da apportare alla classe “animazionClass”
Innanzi tutto è necessario dichiarare alcune variabili che saranno utili per il blending delle animazioni:

Public currentTime As Single
Public currentTrack As Byte
Public animationSet() As animationSet
Private blendTime As Single

Poi vanno memorizzati i puntatori a tutti gli animationSets contenuti nel file x.

Poi vanno memorizzati i puntatori a tutti gli animationSets contenuti nel file x.

ReDim animationSet(animazione.AnimationController.NumberAnimationSets)
Dim i As Integer
For i = 0 To animazione.AnimationController.NumberAnimationSets - 1
    Me.animationSet(i) = animazione.AnimationController.GetAnimationSet(i)
Next

Per passare da un’animation set all’altro è sufficiente appoggiarsi all’animation controller

Protected Sub setAnimation(ByVal animationSetIndex As Byte)
    Dim anim As AnimationSet
    anim = animationSet(animationSetIndex)
    animazione.AnimationController.SetTrackAnimationSet(0, anim)
    animazione.AnimationController.ResetTime()
    currentTrack = 0
End Sub

A questo punto è possibile animare il modello secondo i suoi animation set, però il passaggio fra un’animazione e l’altra sarà scattoso.
Per poter passare da un’animazione all’altra in maniera fluida invece, e necessario procedere come segue:
Nella funzione update frame va inserito un contatore che tenga traccia del processing temporale dell’animazione

currentTime += t

ovviamente anche nella funzione reset timer va aggiornato

currentTime = 0

Fatto questo è possibile creare l’algoritmo di blending delle animazioni.
Il principio è quello di comunicare a directx quale animazione deve essere terminata e quale deve cominciare e per quanto deve durare questa fase di transizione.

Public Sub BlendAnimation(ByVal goalAnimation As Integer)
    Dim animazioneCorrente As AnimationSet
    Dim prossimaAnimazione As AnimationSet
    Dim newtrack As Byte

Questo controllo serve a far si che le animation Track (le animazioni attive) si alternino.

If currentTrack = 0 Then newtrack = 1 Else newtrack = 0

A questo punto viene memorizzata la nuova animazione attraverso l’indice delle animazioni

prossimaAnimazione = animationSet(goalAnimation)

viene settata l’animazione principale

With animazione.AnimationController
    .SetTrackAnimationSet(newtrack, prossimaAnimazione)
    prossimaAnimazione.Dispose()
    .UnkeyAllTrackEvents(currentTrack)
    .UnkeyAllTrackEvents(newtrack)

Viene comunicato a directX di disabilitare l’animazione corrente fra “blendTime” secondi

.KeyTrackEnable(currentTrack, False, currentTime + blendTime)
si diminuisce la velocità e l’influenza dell’animazione corrente
    .KeyTrackSpeed(currentTrack, 0.0F, currentTime, blendTime, TransitionType.Linear)
    .KeyTrackWeight(currentTrack, 0.0F, currentTime, blendTime, TransitionType.Linear)
A questo punto si procede al contrario per la nuova animazione
    .SetTrackEnable(newtrack, True)
    .KeyTrackSpeed(newtrack, 1.0F, currentTime, blendTime, TransitionType.Linear)
    .KeyTrackWeight(newtrack, 1.0F, currentTime, blendTime, TransitionType.Linear)
End With
currentTrack = newtrack

Alcune animazioni è bene siano resettate dall’inizio, specie passando in fasi di idle:

   If resetTimer Then
        animazione.AnimationController.ResetTime()
        currentTime = 0
    End If
End Sub

Il barbatrucco è comunque sempre quello di usare l’animation controller, con lo stesso principio è anche possibile mescolare le animazioni per crearne delle nuove.
Usando le istruzioni set senza il key, (ad esempio SetTrackWeight o SetTrackEnable) e pesando opportunamente le due animazioni

Creare una classe per gli oggetti animati

Alla fine è comodo per ogni oggetto animato costruirsi una struttura per la sua gestione, ad esempio per tiny_4anim, vengono usate le seguenti animazioni:


Public Class Tiniy_x : Inherits animazionClass
    Dim counter As Integer
    Public Enum ANIMATIONSET_INDEX
        WAVE_INDEX = 0
        JOG_INDEX = 1
        WALK_INDEX = 2
        LOITER_INDEX = 3
    End Enum
Quindi è possibile usare I metodi generali per muovere il modello particolare, il parametro bledingAnimationtime, serve a specificare quanto tempo deve durare il passaggio fra le due animazioni
Sub New(ByVal filesrc As String, ByVal texP As String, Optional ByVal blendingAnimationTime As Single = 0.25)
        MyBase.New(filesrc, texP)
        blendtime = blendingAnimationTime
    End Sub
    Public Shadows Sub setAnimation(ByVal animationSetIndex As ANIMATIONSET_INDEX)
        MyBase.setAnimation(animationSetIndex)
    End Sub
    Public Sub changeAnimation(ByVal animationSetIndex As ANIMATIONSET_INDEX, ByVal resetTimer As Boolean)
        Me.BlendAnimation(animationSetIndex, resetTimer)
    End Sub
End Class

Esempio VB.net - MultiSkin

Articolo Articolo  Storico Storico Stampa Stampa
I commenti sono disabilitati.
"L'importante è non smettere di fare domande."

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 7 persone collegate
Sono state visualizzate  pagine

16/08/2022 @ 05:11:06
script eseguito in 77 ms