DirectX/Trasformazioni
Una volta create le nostre immagini 3D, queste resteranno ferme al centro dello schermo. Il risultato non sarà quindi un programma dinamico, ma piuttosto un quadro realizzato con le DirectX. Per far muovere i nostri oggetti, utilizzeremo le trasformazioni. Le trasformazioni si calcolano usando le matrici e le tre principali sono Traslazione (translating), Rotazione (rotating) e Ridimensionamento (scaling).
Una volta calcolata una matrice di trasformazioni, possiamo moltiplicarla per un vettore che rappresenta un vertice. Il risultato sarà il vettore trasformato, ossia un nuovo vertice in una nuova posizione. Moltiplicando la stessa matrice per tutti i vertici dell'oggetto, l'intera figura subirà le stesse trasformazioni. In questo caso del vettore non ci interessa la direzione, in quanto rappresenta un punto nello spazio. Un termine più adatto è turpla, ossia insieme generico. Una turpla di 3 numeri float rappresenterà un punto.
Tuttavia nel capitolo precedente abbiamo specificato che le matrici in DirectX sono 4x4 e se ricordate il calcolo del prodotto Vettore x Matrice, esso può essere calcolato solo se il numero di elementi nel vettore (o nella turpla) è uguale al numero delle righe della matrice. Per questo per rappresentare i punti si utilizzano i VECTOR4D(x, y, z, w). Il quarto elemento definito w, conterrà 1 se il vettore rappresenta un punto, 0 se rappresenta un vettore stesso.
Potrebbe sorgere spontanea la domanda: perché utilizzare matrici 4x4 e non 3x3? Scopriremo che il vettore 3x3 non offre abbastanza spazio per tutte le trasformazioni. Con un vettore 4x4 invece si possono applicare tutte le trasformazioni possibili.
Ridimensionamento
modificaLa più semplice delle trasformazioni. La matrice che rappresenta un ridimensionamento è:
Dove Rx è il fattore per cui si vuole alterare la dimensione lungo l'asse X, stesso dicasi per Ry e Rz
Ponendo Rx = 3, la figura verrà allargata di 3 volte lungo l'asse X. Se invece Ry = 0.33, la figura verrà accorciata ad 1/3 lungo l'asse Y.
Rotazione
modificaLa rotazione ha una matrice molto complessa. Volendo ruotare la figura di gradi intorno ad un arbitrario asse (n è un vettore normalizzato, in quanto indica solo la direzione dell'asse), la matrice di rotazione è ( ):
Una proprietà interessante della matrice di rotazione è che la sua matrice inversa è la sua trasposta. Questa è una eccezione e non vale per tutte le matrici. Quindi per calcolare la rotazione opposta di una matrice, per tornare alla posizione originale, anziché usare D3DXMatrixInverse, si potrà usare D3DXMatrixTranspose, molto più efficiente, richiedendo molti meno calcoli.
Per rotazioni lungo l'asse X, basta porre n = (1, 0, 0), per l'asse Y, n = (0, 1, 0) e per l'asse Z, n = (0, 0, 1). Ciò non toglie che sono possibili rotazioni lungo un asse arbitrario. Nei tre casi particolari le matrici di rotazione sono molto più semplici:
Moltiplicando questa matrice ottenuta per una turpla con w = 1, che indica un vertice, il vertice verrà spostato in modo da simulare una rotazione. Applicando questa matrice a tutti i vertici della figura essa sembrerà ruotata.
Traslazione
modificaIl vettore di traslazione è molto semplice:
Moltiplicando questa matrice per una turpla v si ottiene:
Avrete notato che questo corrisponde perfettamente alla somma di una turpla (x, y, z, 1) rappresentante un punto ed un vettore (x, y, z, 0). Il risultato è un vettore/turpla con v = 1, quindi rappresentante un punto. Tra l'altro l'operazione di differenza tra punti rappresentati da turple restituirà una turpla con w = 0, ossia un vettore. Il modulo di questo vettore sarà la distanza tra i punti.
Utilità delle matrici
modificaAllora perché usare le matrici per la traslazione e non direttamente i vettori? Perché le matrici presentano una particolare proprietà: volendo applicare tre trasformazioni ad un dato vertice dovrei fare:
D3DXVECTOR4 Vertex(3, 2, 4.3, 1);
D3DXMATRIX Scale, Rotation, Traslation;
// Riempire le matrici qui...
D3DXVec4Transform(&Vertex, &Vertex, &Scale);
D3DXVec4Transform(&Vertex, &Vertex, &Rotation);
D3DXVec4Transform(&Vertex, &Vertex, &Traslation);
ma si dimostra che moltiplicando tra loro le tre matrici: si ottiene una matrice equivalente e che quindi ci si può ridurre al semplice codice:
D3DXVector4 Vertex;
D3DXMATRIX S, R, T;
D3DXMATRIX Transformation = S * R * T;
D3DXVec4Transform(&Vertex, &Vertex, &Transformation);
L'importanza di questo procedimento la si avverte quando si devono trasformare migliaia di vertici ed applicare tre matrici è alquanto lento. E' molto più rapido calcolare la matrice di trasformazione a priori e poi applicarla ad ogni vertice.
Attenzione
modificaLa moltiplicazione tra matrici e anti-commutativa. Quindi:
S * R * T != R * S * T;
Ve ne accorgerete dopo i primi esperimenti. Infatti se disegnamo un cubo di lato due il cui centro coincide con il centro degli assi, quindi di vertici (-1, -1, -1), (1, -1, -1), (-1, 1, -1), ..., (1, 1, 1), se lo ruotiamo intorno all'asse X, otteremo una rotazione del cubo su se stesso, poi traslandolo otterremo un cubo ruotato e traslato. Ma se il cubo lo portiamo ad Y = 5 con una traslazione, la stessa rotazione intorno all'asse X diventerà stavolta una rivoluzione intorno all'asse X.
DirectX e le trasformazioni
modificaD3DX mette a disposizione una serie di funzioni per generare matrici di trasformazioni:
D3DXMATRIX *WINAPI D3DXMatrixScaling(D3DXMATRIX *pOut, float sx, float sy, float sz);
D3DXMATRIX *WINAPI D3DXMatrixRotationX(D3DXMATRIX *pOut, float Angle);
D3DXMATRIX *WINAPI D3DXMatrixRotationY(D3DXMATRIX *pOut, float Angle);
D3DXMATRIX *WINAPI D3DXMatrixRotationZ(D3DXMATRIX *pOut, float Angle);
D3DXMATRIX *WINAPI D3DXMatrixRotationAxis(D3DXMATRIX *pOut, D3DXVECTOR3 *pV, float Angle);
D3DXMATRIX *WINAPI D3DXMatrixTranslation(D3DXMATRIX *pOut, float x, float y, float z);
- D3DXMatrixScaling produce un vettore di ridimensionamento in pOut, basandosi sui valori sx, sy ed sz.
- D3DXMatrixRotationX/Y/Z producono un vettore di rotazione intorno all'asse X/Y/Z in pOut di Angle gradi radianti. In pratica passano come vettore asse sottinteso (1, 0, 0), (0, 1, 0), (0, 0, 1).
- D3DXMatrixTranslation invece produce un vettore di traslazione basato sui parametri x, y, z in pOut.