   Interpolation of quaternions
  Okay, first of all, how do you say "quaternion"? This is the way I currently say it, and please correct me if I'm wrong. I say "quater" like "crater" and "ni" like the knights who say "ni", and then the "on".With that out of the way, I'm looking for a way to interpolation between two quaternions. I'm looking around, but I'm just finding ways for linear interpolation between matrices, using quaternions.Is there a way to do it without taking the time to construct the rotation matrices? I create the matrices by creating one for each rotation. So, one for x axis, one for y axis, one for z axis.So, that'll be 2 trig calls for each matrix, and 2 multiplications to get the final rotation matrix.So, 2+2+2 trig calls (for x,y,z), and then "final_matrix_1 = xmat*ymat*zmat" So, in all, that's 12 trig calls and 4 multiplications just to get to a stage where I'll be able to use quaternions to perform the interpolation. Is there a way to do it without having to construct the matrices? Just using the quaternions?   
  The technique that you are looking for is called Slerp.   ;Slerping (spherical linear interpolation) is what you are looking for, i think.As a note, if you are using the D3DX toolkit, then it provides a function, D3DXQuaternionSlerp() for you already.<edit> Damn, beaten again - and with the same link, nonetheless! </edit>   ;  There is- "lerp" which means linear interpolation between 2 quaternions- "slerp" which means spherical linear interpolation between 2 quaternions- "squad" which means spherical cubic interpolation between 3 quaternions (similar to de-Casteljau algorithm)The slerp is the most often used scheme. The lerp doesn't produce a constant angle velocity, and hence is suitable most often only for small angles.EDIT: To give an impression of the costs I post the code in use by me:template<typename scalar_g>RotationN<3,scalar_g>RotationN<3,scalar_g>::lerp(const Rotation_t& q0,const Rotation_t& q1,float blending) {// does clipping of blending factor if needed ...if(blending<=0.0f) {return q0;}if(blending>=1.0f) {return q1;}//float alpha = 1.0f-blending;float omega = blending;// changes to the shorter path if got the longer one ...if(q0.spansLongerArcTo(q1)) {omega = -omega;}// interpolates and normalizes (the bare interpolation doesn't yield quaternions of unit length)return Rotation_t(alpha*q0.r()+omega*q1.r(),alpha*q0.i().s0+omega*q1.i().s0,alpha*q0.i().s1+omega*q1.i().s1,alpha*q0.i().s2+omega*q1.i().s2,true);}template<typename scalar_g>RotationN<3,scalar_g>RotationN<3,scalar_g>::slerp(const Rotation_t& q0,const Rotation_t& q1,float blending) {// does clipping of blending factor if needed ...if(blending<=0.0f) {return q0;}if(blending>=1.0f) {return q1;}// the angle between both quaternionsregister double cosineOfTheta = q0.dot(q1);// the weight of 'start'; here it is initialized for straight linear interpolationregister double alpha = 1.0f-blending;// the weight of 'end'; here it is initialized for straight linear interpolationregister double omega = blending;// whether or not 'end' should be mirrored to get the shorter pathregister bool mirroring = cosineOfTheta<0;// switch to the shorter path if necessary ...if(mirroring) {cosineOfTheta = -cosineOfTheta;}// does a spherical interpolation only if both quaternions aren't too close ...if(1.0f-cosineOfTheta>0.000001f) {register double theta = XMath<double>::acos(cosineOfTheta);register double invSineOfTheta = 1.0/XMath<double>::sin(theta);alpha = XMath<double>::sin(alpha*theta)*invSineOfTheta;omega = XMath<double>::sin(omega*theta)*invSineOfTheta;}// concludes switching to the shorter path if necessary ...if(mirroring) {alpha = -alpha;}// does the actual interpolationreturn Rotation_t(alpha*q0.r()+omega*q1.r(),alpha*q0.i().s0+omega*q1.i().s0,alpha*q0.i().s1+omega*q1.i().s1,alpha*q0.i().s2+omega*q1.i().s2,false // FIXME is it right to supress normalization here ??);}template<typename scalar_g>RotationN<3,scalar_g>RotationN<3,scalar_g>::squad(const Rotation_t& q0,const Rotation_t& q1,const Rotation_t& q2,const Rotation_t& q3,float blending) {return slerp(slerp(q0,q3,blending),slerp(q1,q2,blending),(1.0f-blending)*2.0f*blending);}inlinetemplate<typename scalar_g>boolRotationN<3,scalar_g>::spansLongerArcTo(const Rotation_t& other) const {return dot(other)<0;}where Rotation<3,scalar_g> == Rotation_t is just the class of unit quaternions. Handle w/ care since under active development ;-)[Edited by - haegarr on January 18, 2006 8:18:40 AM];  "qua-" as in "quality".Also, a lerp of a quaternion followed by normalization is frequently good enough and it is much faster than slerp.   ;  I say it as: [kwa-ter-neon]In all probability your either after slerp or lerp.As John hinted, a slerp is better quality than a lerp, but a lerp with a normalization is often good enough and more efficient.Most people won't ever realise any difference (and even if some body actually did notice - would they really care?)   ;Quote:Original post by dmatterMost people won't ever realise any difference (and even if some body actually did notice - would they really care?)It really depends on the application. I tried lerping w/ normalization for my dodecahellspawn project (see my showcase) and it look like crud.   ;  Okay, raising a quaternion to a power.I've got a little book, Real Time Rendering that says:qt = sin(qt)uq + cos(qt)Now, t is the parameter we're interpolating/blending, whatever you call it, that is between 0 and 1, right?I'm assuming that uq is the vector part of the quaternion. But, I'm a little fuzzy on what q represents.Edit::Real Time Rendering also gives an equation for slerp:s(q,r,t) = (rq-1)tqSo, I've taken this to mean: (('r' multiplied by the inverse of 'q') raised to power 't') multiplied by 'q'But, the book also gives another method, which I'm not sure about. It says that this equation is more appropriate for software implementations:s(q,r,t) = ( ((sin(q(1-t)) / sin(q) ) * q) + (( sin(qt) / sin(q) ) * r)(why is it so ridiculously hard to write equations in html?)[Edited by - Endar on January 19, 2006 12:46:35 AM];Quote:Original post by EndarOkay, raising a quaternion to a power.I've got a little book, Real Time Rendering that says:qt = sin(qt)uq + cos(qt)Now, t is the parameter we're interpolating/blending, whatever you call it, that is between 0 and 1, right?I'm assuming that uq is the vector part of the quaternion. But, I'm a little fuzzy on what q represents.I believe q is the half-angle encoded in q.[Edit: Oop, might not have answered the question. 'q' is the quaternion, uq is the vector part of the quaternion, and q is the half-angle, i.e. acos(wq), more or less.]   ;  So, I'll end up with a quaternion in the form of:q = ( cos(qt), sin(qt)*uq )Right? The first part being the 'w' and the second being the vector part.   