Essential Math Weblog Thoughts on math for games

5/15/2004

Correction: Quaternion Creation

Filed under: Erratical,Mathematical — Jim @ 8:37 pm

This is both a correction, and an improvement to the creation of a quaternion from two vectors. Or as it is commonly known, Shortest RotationArc.

The current code doesn’t handle the case where the two vectors are opposing; there’s an if statement to detect it, and a comment, but no recovery code. The problem is that there are an infinite number of orthogonal rotation axes — we just need to pick one. The solution is to check to see which axis the start vector (it could be the finish vector, it doesn’t matter) is generally pointing along. If it’s pointing generally along the -axis, then we take the cross product with the -axis to get our rotation axis. Otherwise we take the cross product with the -axis.

The improvement is from a poster on flipcode and GameDev.net named “minorlogic” — who may have gotten it from another source that I’m not aware of. If we take the dot product and cross product of the two vectors (call them and ), then we end up with and , where is our normalized rotation axis. Sticking this in a quaternion and normalizing gives us .

This is close to what we want, but we need . The trick is to add 1 to the value and renormalize. This will end up dividing each element by . From here, things should look familiar, as this is similar to Melax’s approach. Using trigonometric identities and reducing shows that this will give us .

The updated code looks like:
[cpp]
void
IvQuat::Set( const IvVector3& from, const IvVector3& to )
{
// get axis of rotation
IvVector3 axis = from.Cross( to );
// get scaled cos of angle between vectors and set initial quaternion
Set( axis.x, axis.y, axis.z, from.Dot( to ) );

// normalize to get cos theta, sin theta r
Normalize();

// set up for half angle calculation
w += 1.0f;

// if vectors are opposing
if ( w < = kEpsilon ) { // find orthogonal vector // take cross product with x axis if ( from.z*from.z > from.x*from.x )
Set( 0.0f, 0.0f, from.z, -from.y );
// or take cross product with z axis
else
Set( 0.0f, from.y, -from.x, 0.0f );
}

// normalize again to get rotation quaternion
Normalize();
}
[/cpp]

1 Comment »

  1. There is a better explanation of this formula.
    http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/transforms/halfAngle.htm

    So , if we know that quaternion of sum , represent rotation between source orientations.

    The sum of any quaternion with (0,0,0,1) exacly give us half rotation. So it is very simple to explain, without trigonometry.

    Comment by Michael Norel — 8/28/2005 @ 6:24 am

RSS feed for comments on this post. TrackBack URL

Leave a comment

Powered by WordPress