ci saranno problemi se si interpolare i valori di matrice direttamente, per angoli molto piccoli i inaccuraties non possono essere osservati, ma nel più lungo termine si dovrà affrontare problemi. Anche se normalizzi le matrici, gli angoli maggiori renderanno i problemi visivamente ovvi.
La rotazione 2D è piuttosto semplice, quindi è possibile fare la fine senza l'approccio della matrice di rotazione. Il metodo migliore potrebbe essere utilizzare i quaternioni, ma forse sono più adatti per le trasformazioni 3D.
Le operazioni da effettuare sono:
- calcolare la rotazione, la scala e trasformare valori. Se ne hai già, puoi saltare questo passaggio. Potrebbe essere più semplice mantenere questi valori separati per le trasformazioni della matrice 2D.
- Poi applly interpolazione a quei valori
- costruire una nuova matrice basata sui calcoli
All'inizio dell'animazione si deve calcolare valori da passaggio 1 volta e quindi applicare passaggi 2 e 3 per ogni telaio.
Fase 1: ottenere la rotazione, la scala, trasformare
Assumere il Matrix inizio è S e Matrix finale è E.
I valori di trasformazione sono semplicemente le ultime colonne del, per esempio
var start_tx = S[0][2];
var start_ty = S[1][2];
var end_tx = E[0][2];
var end_ty = E[1][2];
la scala per non inclinazione matrice 2D è semplicemente lunghezza sia uno dei vettori di base nello spazio della matrice è spanning, per esempio
// scale is just the length of the rotation matrixes vector
var startScale = Math.sqrt(S[0][0]*S[0][0] + S[1][0]*S[1][0]);
var endScale = Math.sqrt(E[0][0]*E[0][0] + E[1][0]*E[1][0]);
La parte più difficile è ottenere i valori di rotazione per la matrice. La cosa buona è che deve essere calcolato solo una volta per interpolazione.
L'angolo di rotazione per due matrici 2D può essere calcolato in base all'angolo tra i vettori creati dalle colonne delle matrici. Se non c'è rotazione, la prima colonna ha valori (1,0) che rappresentano l'asse x e la seconda colonna ha valori (0,1) che rappresentano l'asse y.
Generalmente posizione asse x per Matrix S è rappresentato da
(S [0] [0], S [0] [1])
e l'asse y è indicando direzione
(S [1] [0], S [1] [1])
e lo stesso per qualsiasi matrice 2D 3x3, come E.
Utilizzando queste informazioni è possibile determinare l'angolo di rotazione tra le due matrici utilizzando solo la matematica vettoriale standard, se si assume che non vi sia una distorsione.
// normalize column vectors
var s00 = S[0][0]/ startScale; // x-component
var s01 = S[0][1]/ startScale; // y-component
var e00 = E[0][0]/ endScale; // x-component
var e01 = E[0][1]/ endScale; // y-component
// calculate dot product which is the cos of the angle
var dp_start = s00*1 + s01*0; // base rotation, dot prod against x-axis
var dp_between = s00*e00 + s01*e01; // between matrices
var startRotation = Math.acos(dp_start);
var deltaRotation = Math.acos(dp_between);
// if detect clockwise rotation, the y -comp of x-axis < 0
if(S[0][1]<0) startRotation = -1*startRotation;
// for the delta rotation calculate cross product
var cp_between = s00*e01 - s01*e00;
if(cp_between<0) deltaRotation = deltaRotation*-1;
var endRotation = startRotation + deltaRotation;
Qui il startRotation è calcolato solo da acos del primo valore della matrice. Tuttavia, il primo valore della seconda colonna, che è -sin (angolo) è maggiore di zero, quindi la matrice è stata ruotata in senso orario e l'angolo deve essere negativo. Questo deve essere fatto perché acos fornisce solo valori positivi.
Un altro modo di pensare a ciò sarebbe considerare il prodotto incrociato s00 * e01 - s01 * e00 dove posizione iniziale (s00, s01) è l'asse x, dove s00 == 1 e s01 == 0 e la fine (e00, e01) è la (S [0] [0], S [0] [1]) creando prodotto incrociato
1 * S[0][1] - 0 * S[0][0]
Quale è S [0] [1]. Se quel valore è negativo, l'asse x è stato girato in senso orario.
Per endRotation, è necessaria la rotazione delta da S a E. Questo può essere calcolato in modo simile dal prodotto punto tra i vettori che la matrice si estende. Allo stesso modo, testiamo il cross-product per vedere se la direzione di rotazione è in senso orario (angolo negativo).
Fase 2: interpolare
Durante animazione ottenere nuovi valori è l'interpolazione banale:
var scale = startScale + t*(endScale-startScale);
var rotation = startRotation + t*(endRotation-startRotation);
var tx = start_tx + t*(end_tx-start_tx);
var ty = start_ty + t*(end_ty-start_ty);
Passaggio 3 costrutto matrice
Per ogni frame costruire la matrice finale tuo posizionare i valori nella matrice matrice di trasformazione
var cs = Math.cos(rotation);
var sn = Math.sin(rotation);
var matrix_values = [[scale*cs, -scale*sn, tx], [scale*sn, scale*cs, ty], [0,0,1]]
E quindi si dispone di una matrice 2D che è facile da alimentare per qualsiasi acceleratore hardware 3D.
NOTA BENE: alcuni codici sono stati testati, alcuni non sono stati testati, quindi è probabile che si possano trovare errori.
Questa è stata la prima risposta che ci ha dato il suggerimento giusto: la scala di conservazione non può essere eseguita con una sola combinazione lineare. Era anche la soluzione al nostro problema, quindi ti ricompenserò con la generosità. Ma ha portato un nuovo problema: il centro di rotazione è arbitrario e non controllabile. Per gestire questo, abbiamo utilizzato un tweak della soluzione @miks. Ora calcoliamo un centro di rotazione per ogni passo dell'animazione e con questo costruiamo una matrice per ogni t. –
Grazie. Regolare le matrici per preservare il centro di rotazione per i diversi spazi di trasformazione può essere a volte un compito leggermente pungente ... contento che tu l'abbia fatto! –
@JulianHabekost nella mia soluzione ho provato prima a unire tutte le trasformazioni tranne la rotazione in una matrice (in realtà due di esse: una prima e una dopo la rotazione), ma mi sembrava troppo complicata; poi ho modificato la mia risposta. Se fai clic su "modificato ..." vedrai la prima variante. – mik