Quaternions has a 90 deg dead angle

Started by
4 comments, last by GameDev.net 18 years, 9 months ago
Hi I am using quaternions for both animations and my camera and I am encountering the same problem in both cases. It seems like the quaternions have a dead angle of 90 degrees. Passing that angle will either make the quaternion roll around rotating the other direction, or break it. By break it I mean that any rotation matrix made from the quaternion ends up havid bad right, up, and at vectors causing the entire frustum to collapse in the camera case. In the animations some joints sometime flip around an entire lap and get twisted. Here are the funcitons I use. Sorry if its a lot of code I'm kind of new to quaternions so go easy on me please // SLERP void SiCQuaternion::Slerp(const SiVector4T *pQuaternion1, const SiVector4T *pQuaternion2, float fDelta) { SiVector4T v4Quat2 = *pQuaternion2; float fDot = pQuaternion1->Dot(*pQuaternion2); if( fDot < 0.0f ) { fDot =-fDot; v4Quat2.fX = -v4Quat2.fX; v4Quat2.fY = -v4Quat2.fY; v4Quat2.fZ = -v4Quat2.fZ; v4Quat2.fW = -v4Quat2.fW; } if (fDot <= 1.f && fDot > 0.999f) { Lerp(pQuaternion1, &v4Quat2, fDelta); return; } float fTheta = acosf(fDot); float fT = 1.f / sinf(fTheta); m_v4Quaternion.Add(*pQuaternion1 * sinf( (1.f - fDelta) * fTheta), v4Quat2 * sinf(fDelta * fTheta)); m_v4Quaternion = m_v4Quaternion * fT; } // BUILD ROTATION MATRIX float fWX, fWY, fWZ, fXX, fYY, fZZ, fYZ, fXY, fXZ, fX2, fY2, fZ2; // Clean the matrix memset(pOutMatrix, 0, sizeof(SiMatrix4T)); pOutMatrix->_44 = 1.0f; fX2 = m_v4Quaternion.fX + m_v4Quaternion.fX; fY2 = m_v4Quaternion.fY + m_v4Quaternion.fY; fZ2 = m_v4Quaternion.fZ + m_v4Quaternion.fZ; fXX = m_v4Quaternion.fX * fX2; fYY = m_v4Quaternion.fY * fY2; fZZ = m_v4Quaternion.fZ * fZ2; fXY = m_v4Quaternion.fX * fY2; fXZ = m_v4Quaternion.fX * fZ2; fYZ = m_v4Quaternion.fY * fZ2; fWX = m_v4Quaternion.fW * fX2; fWY = m_v4Quaternion.fW * fY2; fWZ = m_v4Quaternion.fW * fZ2; pOutMatrix->_11 = 1.f - (fYY + fZZ); pOutMatrix->_12 = fXY - fWZ; pOutMatrix->_13 = fXZ + fWY; pOutMatrix->_21 = fXY + fWZ; pOutMatrix->_22 = 1.f - (fXX + fZZ); pOutMatrix->_23 = fYZ - fWX; pOutMatrix->_31 = fXZ - fWY; pOutMatrix->_32 = fYZ + fWX; pOutMatrix->_33 = 1.f - (fXX + fYY); } // And finally build from matrix. This can not be the problem in the animation case since I export quaternions from maya { float fTemp = pMatrix->_11 + pMatrix->_22 + pMatrix->_33 + pMatrix->_44; float fFour; int i,j,k; if (fTemp >= 1.f) { fFour = 2.f * sqrt(fTemp); m_v4Quaternion.fW = fFour * 0.25f; m_v4Quaternion.fX = (pMatrix->_32 - pMatrix->_23) / fFour; m_v4Quaternion.fY = (pMatrix->_13 - pMatrix->_31) / fFour; m_v4Quaternion.fZ = (pMatrix->_21 - pMatrix->_12) / fFour; } else { if (pMatrix->_11 > pMatrix->_22) { i = 0; } else { i = 1; } if (pMatrix->_33 > pMatrix->fMatrix) { i = 2; } j = (i+1)%3; k = (j+1)%3; fFour = 2.f * sqrt(pMatrix-&gt;fMatrix - pMatrix-&gt;fMatrix - pMatrix-&gt;fMatrix[k * 4 + k] + 1.f); m_v4Quaternion.fVec<span style="font-weight:bold;"> = fFour * 0.25f; m_v4Quaternion.fVec[j] = (pMatrix-&gt;fMatrix[j* 4 + i] + pMatrix-&gt;fMatrix[i* 4 + j]) / fFour; m_v4Quaternion.fVec[k] = (pMatrix-&gt;fMatrix[k* 4 + i] + pMatrix-&gt;fMatrix[i* 4 + k]) / fFour; m_v4Quaternion.fW = (pMatrix-&gt;fMatrix[j * 4 + k] - pMatrix-&gt;fMatrix[k * 4 + j]) / fFour; } Thanks
Advertisement
Quote:Original post by tealrabbit
// And finally build from matrix. This can not be the problem in the animation case since I export quaternions from maya

and
Quote:
fFour = 2.f * sqrt(pMatrix->fMatrix - pMatrix-&gt;fMatrix - pMatrix-&gt;fMatrix[k * 4 + k] + 1.f);<br><!–QUOTE–></td></tr></table></BLOCKQUOTE><!–/QUOTE–><!–ENDQUOTE–><br><br>Is this correct?<br><br>
In addition to the line Dave pointed out, I think you may also have a problem in this line:

if (pMatrix->_33 > pMatrix->fMatrix)<br><br>Also it seems that your slerp function could fail if the two input quaternions are very close to equal. To avoid this I would change this line:<br><br>if (fDot &lt;= 1.f && fDot &gt; 0.999f)<br><br>To:<br><br>if (fDot &gt; 0.999f)
Thanks a lot for the quick answers. You where both right. Those two fixes took care of the quaternions breaking and making bad matrices. The only problem now is that the quaternions still seems to switch direction when they hit a certain angle and get "inverted".

This is in the Lerp or Slerp I am pretty sure.

Thanks for the help. I'm sure I'll figure this out.
Quote:Original post by tealrabbit
The only problem now is that the quaternions still seems to switch direction when they hit a certain angle and get "inverted".
This is in the Lerp or Slerp I am pretty sure.


This is fairly common with Lerp and Slerp algorithms, it happens whenever the quaternions are are at such a rotation that any axis will do for the rotation. My fix was to use the first quaternions up vector as the axis for the rotation, if any axis is acceptable.

Sorry if that isn't very clear,

SwiftCoder

Tristam MacDonald. Ex-BigTech Software Engineer. Future farmer. [https://trist.am]

regarding the "switching directions" on your interpolation.
i'm imagining that you have these keyframes:

time 0: 0 degrees
time 30: 90 degrees
time 60: 0 degrees.

at time 31, there is nothing in the slerp math that can tell which direction you want to go in -- it can't tell whether 91 or 89 degrees is the right answer for frame 31..

maya, internally, uses function curves for this, so maya knows more information than your quaternion...

the solution is to have your artist put in keyframes at, say, time 45..
or to put them in programmaticall as you are pulling the animation out of maya.

that's what we do where i work.

This topic is closed to new replies.

Advertisement