Given a direction(vector) and a wanted direction(vector), how do you get a rotation?

Started by
4 comments, last by tthibault 17 years, 10 months ago
Given a direction(vector) and a wanted direction(vector), how do you get a rotation, like, quaternion?? E.g. I am facing 1,0,1. And I want to face 2,5,4. How do I get the thing(either in quaternion or angle-rotating axis form) that, when applied to 1,0,1 would become 2,5,4? All I can find is telling you how to get the resulting direction with a starting direction and a rotation, but not what I mentioned. Please help.
Advertisement
>>Given a direction(vector) and a wanted direction(vector), how do you get a rotation, like, quaternion??

Cross product!!!

Vector3 rotation_vec = Direction cross Wanted_Direction

You'd want to normalize the direction and wanted direction vectors. Then, the inverse sine (asin) will give you the angle to rotate through, and the direction that rotation_vec points in is the axis.

double angle = asinf(rotation_vec.Length());
rotation_vec.Normalize();

Quaternion quat_rotation;
quat_rotation.w = angle;
quat_rotation.xyz = rotation; //normalized at this point

That should give you a basic idea.
...and do not wildly extrapolate. Just because Saddam Hussein gassed Kurds in 1990 doesn't mean he eats babies' brains.
Quote:

Vector3 rotation_vec = Direction cross Wanted_Direction
double angle = asinf(rotation_vec.Length());
rotation_vec.Normalize();

Quaternion quat_rotation;
quat_rotation.w = angle;
quat_rotation.xyz = rotation; //normalized at this point



tthibault, I dont think that actually works.

Taking the cross product of two normalized angles will yield another normalized vector(length always equal to one). Although this is indeed your "axis of rotation", you cannot obtain how far to rotate between the two directions by taking the length of an already normalized vector (it will always be one). I think you need ot use the cross product to find the axis to rotate on and the dot product to find out how far to rotate along this axis.

This is the code I would use:

// Note: Directions should be normalizedDirStart.Normalize();DirEnd.Normalize();// Find axis to rotate alongVECTOR3 rotAxis = DirStart.Cross(DirEnd);    // Use dot product and arccos to detrmin how far to rotate along previous axisfloat   angle = acos( DirStart.Dot(DirEnd));// and borrowing from tthibault to fill in a quaternion...quat_rotation.w = angle;quat_rotation.xyz = rotAxis; // or you can use something like this in direct3d to build a rotational matrixD3DMatrixRotationAxis(rotMat, &axis, angle);


Hope this helps
Boo ya grandma.. boo ya!
The dot-product shows the correspondence
a . b = |a| * |b| * cos( < a,b > )

The cross-product shows the correspondence
|a x b| = |a| * |b| * |sin( < a,b > )|

So, even if both input vectors show unit length, the length of the resulting vector (in the case of the cross-product) _is_ depending on the included angle. Else a cross-product of self
a x a
were not able to disappear for any non zero length vector. But, looking at the computation formula for the cross-product, one can see that e.g.
(a x a)x := ay*az - az*ay
(and similarly for y and z) always disappears.
In addition to the axis-angle method, there are some other methods for directly computing the quaternion that rotates one vector onto another. It's covered in one of the first two GPG books, but there's an even nicer algorithm that I've seen online (among other things, it doesn't require the input to be unit length).

One nice thing about the 'direct' methods is that unlike the axis-angle methods you don't have to handle near-aligned vectors (parallel and pointing in the same direction) as a special case.

I just googled for the algorithm I had in mind, but couldn't find it; I'm pretty sure though that it's discussed somewhere on this site.

Oh, and here's one more method; it does require unit-length input, but handles near-aligned vectors uniformly:
vector3 mid = normalize(v1+v2);q.set(cross(v1,mid),dot(v1,mid));
(I may or may not have gotten that right...)

[Edit: Fixed error in code.]

[Edited by - jyk on May 30, 2006 11:03:47 AM]
>>Taking the cross product of two normalized angles will yield another normalized vector(length always equal to one)

Wait, no, it still works...

|A x B| = |A| * |B| * sin(theta)


if A and B are have a length of 1, you just take the asin of the length, getting theta.
...and do not wildly extrapolate. Just because Saddam Hussein gassed Kurds in 1990 doesn't mean he eats babies' brains.

This topic is closed to new replies.

Advertisement