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]

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