2010-11-04 12 views
12

Ho due matrici di rotazione che descrivono rotazioni arbitrarie. (Compatibile con 4x4 opengl)interpolazione tra matrici di rotazione

ora voglio interpolarli tra di loro, in modo che segua un percorso radiale da una rotazione all'altra. pensa a una macchina fotografica su un treppiede che guarda in un modo e poi ruota.

se interpolo ogni componente ottengo un risultato di spremitura, quindi penso di dover interpolare solo alcuni componenti della matrice. ma quali?

risposta

1

È necessario convertire la matrice in una rappresentazione diversa - i quaternioni funzionano bene per questo e l'interpolazione dei quaternioni è un'operazione ben definita.

+0

grazie! quindi, come posso convertire una matrice in un quaternion? – clamp

+0

Ti suggerisco di iniziare leggendo questo: http://en.wikipedia.org/wiki/Quaternion – tdammers

14

È necessario utilizzare SLERP per le parti rotazionali delle matrici e lineare per le altre parti. Il modo migliore è trasformare le matrici in quaternioni e utilizzare lo SLERP (più semplice) quaternario: http://en.wikipedia.org/wiki/Slerp.

Suggerisco di leggere Graphic Gems II o III, in particolare le sezioni relative alla scomposizione delle matrici in trasformazioni più semplici. Ecco fonte Spencer W. Thomas' per questo capitolo:

http://tog.acm.org/resources/GraphicsGems/gemsii/unmatrix.c

Naturalmente, vi consiglio di imparare a fare da soli. Non è poi così difficile, solo un sacco di algebra fastidiosa. E, infine, ecco una grande carta su come trasformare una matrice in un quaternione, e ritorno, dal software Id: http://cache-www.intel.com/cd/00/00/29/37/293748_293748.pdf


Edit: Questa è la formula più o meno tutti cita, è da un 1985 SIGGRAPH carta.

alt text

Dove:

- qm = interpolated quaternion 
- qa = quaternion a (first quaternion to be interpolated between) 
- qb = quaternion b (second quaternion to be interpolated between) 
- t = a scalar between 0.0 (at qa) and 1.0 (at qb) 
- θ is half the angle between qa and qb 

Codice:

quat slerp(quat qa, quat qb, double t) { 
    // quaternion to return 
    quat qm = new quat(); 
    // Calculate angle between them. 
    double cosHalfTheta = qa.w * qb.w + qa.x * qb.x + qa.y * qb.y + qa.z * qb.z; 
    // if qa=qb or qa=-qb then theta = 0 and we can return qa 
    if (abs(cosHalfTheta) >= 1.0){ 
     qm.w = qa.w;qm.x = qa.x;qm.y = qa.y;qm.z = qa.z; 
     return qm; 
    } 
    // Calculate temporary values. 
    double halfTheta = acos(cosHalfTheta); 
    double sinHalfTheta = sqrt(1.0 - cosHalfTheta*cosHalfTheta); 
    // if theta = 180 degrees then result is not fully defined 
    // we could rotate around any axis normal to qa or qb 
    if (fabs(sinHalfTheta) < 0.001){ // fabs is floating point absolute 
     qm.w = (qa.w * 0.5 + qb.w * 0.5); 
     qm.x = (qa.x * 0.5 + qb.x * 0.5); 
     qm.y = (qa.y * 0.5 + qb.y * 0.5); 
     qm.z = (qa.z * 0.5 + qb.z * 0.5); 
     return qm; 
    } 
    double ratioA = sin((1 - t) * halfTheta)/sinHalfTheta; 
    double ratioB = sin(t * halfTheta)/sinHalfTheta; 
    //calculate Quaternion. 
    qm.w = (qa.w * ratioA + qb.w * ratioB); 
    qm.x = (qa.x * ratioA + qb.x * ratioB); 
    qm.y = (qa.y * ratioA + qb.y * ratioB); 
    qm.z = (qa.z * ratioA + qb.z * ratioB); 
    return qm; 
} 

Da: http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/

+0

ok, grazie diciamo che uso Quaternions invece. devo solo interpolare ciascuno dei 4 componenti per ottenere una transizione graduale? – clamp

+0

Modificato la mia risposta con la formula e un codice più semplice da digerire. –

+0

Il primo mazzo di link non funziona più :( – Narfanator