Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Quaternion - Rotate To

I have some object in world space, let's say at (0,0,0) and want to rotate it to face (10,10,10).

How do i do this using quaternions?

like image 884
PeeS Avatar asked Dec 26 '22 15:12

PeeS


2 Answers

This question doesn't quite make sense. You said that you want an object to "face" a specific point, but that doesn't give enough information.

First, what does it mean to face that direction? In OpenGL, it means that the -z axis in the local reference frame is aligned with the specified direction in some external reference frame. In order to make this alignment happen, we need to know what direction the relevant axis of the object is currently "facing".

However, that still doesn't define a unique transformation. Even if you know what direction to make the -z axis point, the object is still free to spin around that axis. This is why the function gluLookAt() requires that you provide an 'at' direction and an 'up' direction.

The next thing that we need to know is what format does the end-result need to be in? The orientation of an object is often stored in quaternion format. However, if you want to graphically rotate the object, then you might need a rotation matrix.

So let's make a few assumptions. I'll assume that your object is centered at the world's point c and has the default alignment. I.e., the object's x, y, and z axes are aligned with the world's x, y, and z axes. This means that the orientation of the object, relative to the world, can be represented as the identity matrix, or the identity quaternion: [1 0 0 0] (using the quaternion convention where w comes first).

If you want the shortest rotation that will align the object's -z axis with point p:=[p.x p.y p.z], then you will rotate by φ around axis a. Now we'll find those values. First we find axis a by normalizing the vector p-c and then taking the cross-product with the unit-length -z vector and then normalizing again:

a = normalize( crossProduct(-z, normalize(p-c) ) );

The shortest angle between those two unit vectors found by taking the inverse cosine of their dot-product:

φ = acos( dotProduct(-z, normalize(p-c) ));

Unfortunately, this is a measure of the absolute value of the angle formed by the two vectors. We need to figure out if it's positive or negative when rotating around a. There must be a more elegant way, but the first way that comes to mind is to find a third axis, perpendicular to both a and -z and then take the sign from its dot-product with our target axis. Vis:

b = crossProduct(a, -z );

if ( dotProduct(b, normalize(p-c) )<0 ) φ = -φ;

Once we have our axis and angle, turning it into a quaternion is easy:

q = [cos(φ/2) sin(φ/2)a];

This new quaternion represents the new orientation of the object. It can be converted into a matrix for rendering purposes, or you can use it to directly rotate the object's vertices, if desired, using the rules of quaternion multiplication.

like image 137
JCooper Avatar answered Jan 16 '23 14:01

JCooper


An example of calculating the Quaternion that represents the rotation between two vectors can be found in the OGRE source code for the Ogre::Vector3 class.

like image 25
Will Avatar answered Jan 16 '23 14:01

Will