Get the quaternion rotation between two points

Started by
9 comments, last by Manonthemoon 16 years, 10 months ago
How do I do that? This was the process I was using: * Find a vector v from p1 to p2. <-- Simple, just do p2 - p1, and normalize it. * Express an axis angle orientation A between the two points, with theta = 0 (or some other arbitrary value) and the axis equal to the vector v defined above. <-- a.theta = 0, a.x = v.x, a.y = v.y, a.z = v.z * Convert that axis angle to a quaternion <-- Really simple math; it's on this website. This doesn't seem to work, so I made an incorrect assumption somewhere. For the life of me I can't find an article that explains how to find a quaternion between two points. Can anyone show me where? Thanks
Advertisement
Quote:This doesn't seem to work, so I made an incorrect assumption somewhere.
The incorrect assumption is that the axis of rotation of an object is somehow the same as (i.e. aligned with) its 'direction'. This usually won't be the case; generally speaking, the axis of rotation will be arbitrarily oriented with respect to the object's direction vector (if it has one - some objects, such as a sphere, might not have an associated 'forward direction' at all).

The problem that you describe is generally solved by an 'aim at' function of some sort. There are a few different ways to build such a transform, each of which has different behavior with respect to selecting an orientation that satisfies the given constraints (for the 'position-target' problem, there is an infinite number of such orientations).

If you can describe what this is for exactly (that is, why you need an orientation that 'aims' the object at the particular point), I or someone else can probably recommend a specific algorithm that will meet your needs.
It's for a missile tracking algorithm that's part of a larger space game; essentially I need to be able to figure out what direction the missile has to orient itself to.

I plan to use that same function to get the camera to orient itself at a given point.

I've been thinking of adding in a third point; that way I could define a plane and have the rotation occur within that plane.

Thanks
to do that you can use the following method:

let the vector defining the direction the object should be facing in as 'z' consequently, the z vector of the objects basis.

then let x = [z.z, 0, -z.x]/sqrt(z.x*z.x+z.z*z.z);
then let y = z cross x;

the three vectors, x,y,z will define a base that will rotate the object to face with the z-axis pointing towards whatever it is:

basicly, it projects the z axis onto the xz plane, rotates it 90's degrees in the plane for the x axis, then uses the cross product to get the y'axis

the only degenerate case is when both z.x and z.z are 0, in which case you would set x and y to be:

x : <1,0,0>, y:<0,0,-z.y>

that'll give a rotation matrix:

[x.x y.x z.x 0]
[x.y y.y z.y 0]
[x.z y.z z.z 0]
[ 0 0 0 1]

this works especcialy well for camera transformations, because the x-axis always lies in the xz plane, so it gives it a natural feel, i.e the view is always 'upright' and never swivveled around
I think that might work, except I need the actual quaternion, not just the matrix; and there are times when I might need to use a plane other than the XZ plane.
Quote:Original post by jckut10
I think that might work, except I need the actual quaternion, not just the matrix; and there are times when I might need to use a plane other than the XZ plane.
For the quaternion, just build the matrix and then extract the quaternion directly from it.

You might also consider adjusting the missile's orientation using relative rotations instead (this would have a few advantages over the 'create an orientation from scratch' method). There's a very nice algorithm for computing the quaternion that rotates from one vector to another over the shortest arc that you could use for this, which I could post if it would be helpful.
I think I've actually derived a version of that type of algorithm.

It takes the two vectors (vecCurrent, vecToTarget) and does a cross product to get a vector normal to both of them (vecAxis). Then it uses a dot product formula to find the angle between the two original vectors (theta). vecAxis and theta then become an angle-axis orientation, which can be converted to a quaternion.

It seems to work, but please post yours if it's not too much trouble -- your code might be more efficient than mine.

Quote:For the quaternion, just build the matrix and then extract the quaternion directly from it.

Is there a computationally inexpensive way to do this?
Quote:Original post by jckut10
I think I've actually derived a version of that type of algorithm.

It takes the two vectors (vecCurrent, vecToTarget) and does a cross product to get a vector normal to both of them (vecAxis). Then it uses a dot product formula to find the angle between the two original vectors (theta). vecAxis and theta then become an angle-axis orientation, which can be converted to a quaternion.

It seems to work, but please post yours if it's not too much trouble -- your code might be more efficient than mine.
It's not so much an issue of efficiency as of robustness. Your method (which is the 'standard' method, more or less) requires that nearly aligned input vectors be handled as a special case. The algorithm I have in mind is very elegant and handles all cases except for opposite alignment (which will always be a special case) uniformly.

Here's some code:

template < class E,class A,class O,class C,class VecT_1,class VecT_2 > voidquaternion_rotation_vec_to_vec(    quaternion<E,A,O,C>& q,    const VecT_1& v1,    const VecT_2& v2,    bool unit_length_vectors = false){    typedef quaternion<E,A,O,C> quaternion_type;    typedef typename quaternion_type::value_type value_type;    typedef vector< value_type, fixed<3> > vector_type;     vector_type c = cross(v1,v2);    if (unit_length_vectors) {        q = quaternion_type(value_type(1) + dot(v1,v2), c.data());    } else {        q = quaternion_type(            std::sqrt(v1.length_squared() * v2.length_squared()) + dot(v1,v2),            c        );    }    q.normalize();}
Quote:
Quote:For the quaternion, just build the matrix and then extract the quaternion directly from it.
Is there a computationally inexpensive way to do this?
Again, I wouldn't worry about efficiency too much for these sorts of operations - they're unlikely to be a bottleneck (and if they are, you might want to reconsider your choice of rotation representations).

Anyway, the algorithm for converting a matrix to a quaternion is pretty standard. Here's an implementation:

template < class E, class A, class O, class C, class MatT > voidquaternion_rotation_matrix(quaternion<E,A,O,C>& q, const MatT& m){    typedef quaternion<E,A,O,C> quaternion_type;    typedef typename quaternion_type::value_type value_type;    typedef typename quaternion_type::order_type order_type;    /* Checking */    detail::CheckMatLinear3D(m);    enum {        W = order_type::W,        X = order_type::X,        Y = order_type::Y,        Z = order_type::Z    };    value_type tr = trace_3x3(m);    if (tr >= value_type(0)) {        q[W] = std::sqrt(tr + value_type(1)) * value_type(.5);        value_type s = value_type(.25) / q[W];        q[X] = (m.basis_element(1,2) - m.basis_element(2,1)) * s;        q[Y] = (m.basis_element(2,0) - m.basis_element(0,2)) * s;        q[Z] = (m.basis_element(0,1) - m.basis_element(1,0)) * s;    } else {        size_t largest_diagonal_element =            index_of_max(                m.basis_element(0,0),                m.basis_element(1,1),                m.basis_element(2,2)            );        size_t i, j, k;        cyclic_permutation(largest_diagonal_element, i, j, k);        const size_t I = X + i;        const size_t J = X + j;        const size_t K = X + k;        q =            std::sqrt(                m.basis_element(i,i) -                m.basis_element(j,j) -                m.basis_element(k,k) +                value_type(1)            ) * value_type(.5);        value_type s = value_type(.25) / q;        q[J] = (m.basis_element(i,j) + m.basis_element(j,i)) * s;        q[K] = (m.basis_element(i,k) + m.basis_element(k,i)) * s;        q[W] = (m.basis_element(j,k) - m.basis_element(k,j)) * s;    }}

Let me know if you need any help stripping out the implementation-specific stuff (templates, enumerations, the basis_element() function, and so forth).
Hi all,

I think this is the thread I have been looking for...

I have recently taken up Scripting using the Torque Game Engine (TGE), and at the moment I have a very simple problem getting one of my objects to rotate. [It has been a long time since I looked into vector mathematics and I am a little rusty.]

I have currently rezzed two spheres and a cylinder. I want to rotate the cylinder so that its ends are at the center of the two spheres.

I have moved the cylinder so that its center is halfway between the two spheres, and I have scaled it so that it is long enough. I have functions to set the "rotation" and "rotation theta" for an object - but I can't figure out how to calculate these so that I can get the cylinder to point in the right direction.

Above is mentioned a "aimAt" method or similar, if I could get some help to calculate my rotation and theta that would be greatly appreciated.

p.s. TGE already has maths functions like: VectorAdd(), VectorCross(), VectorDot(), VectorNormalize(), VectorOrthoBasis(), VectorScale(), VectorSub(), VectorDist(), VectorLen()...

Thanks
Quote:Original post by Manonthemoon
I have functions to set the "rotation" and "rotation theta" for an object - but I can't figure out how to calculate these so that I can get the cylinder to point in the right direction.
What do the 'rotation' and 'rotation theta' represent exactly?

This topic is closed to new replies.

Advertisement