How to rotate a vector about an Arbitrary Axis in 3D to align two vectors?

1.3k Views Asked by At

What I'm trying to do...

Say I have two vectors. I want to align these vectors so that they one of my vectors is pointing directly at the other. For example, imagine there is this point and I want to position my camera so that my camera's center is directly aligned with said point.

From my understanding to do this, I would calculate the cross product between the two vectors and use that as an arbitrary axis of rotation.

From there I would need an angle $\theta,$ which can be determined by taking the dot product between the two vectors and dividing by the product of their magnitudes. Then I would solve for $\theta$ using $\cos^{-1}$

$$\theta=\cos^{-1}{A \cdot B\over |A||B|}$$

I'm stuck on how to determine the appropriate rotation matrix which to rotate about.

Also, I'm not sure if my process is correct I was looking online to figure this out.

3

There are 3 best solutions below

4
On BEST ANSWER

I'm guessing you're intending to program this. So an implementation of @EmilioNovati's reference is illustrated below in C. You give it a rotation axis and a $\theta$, and then one function gives you the corresponding quaternion, and then another gives you the $3\mbox{x}3$ rotation matrix corresponding to that quaternion. And a third just conveniently multiplies a vector times a matrix to do the rotation for you. Here's the code, followed by a sample animation using it for rotation calculations...

/* ---
 * Point and line datatype structs
 * ---------------------------------- */
#define POINT struct point_struct       /* "typedef" for point_struct*/
#define LINE struct line_struct         /* "typedef" for line_struct*/
#define QUAT struct quaternion_struct   /* "typedef" for quaternion_struct */
POINT   { double x, y, z; } ;           /* 3d pts */
LINE    { POINT pt1, pt2; } ;           /* for vectors, pt1=tail, pt2=head */
QUAT    { double q0, q1, q2, q3; } ;    /* quat = q0 + q1*i + q2*j + q3*k */

/***************************************************************************
 ** +===================================================================+ **
 ** | Low-level quaternion functions, etc                               | **
 ** +===================================================================+ **
 ***************************************************************************/

/* ==========================================================================
 * Function:    qrotate ( LINE axis, double theta )
 * Purpose:     returns quaternion corresponding to rotation
 *              through theta (**in radians**) around axis
 * --------------------------------------------------------------------------
 * Arguments:   axis (I)        LINE axis around which rotation by theta
 *                              is to occur
 *              theta (I)       double theta rotation **in radians**
 * --------------------------------------------------------------------------
 * Returns:     ( QUAT )        quaternion corresponding to rotation
 *                              through theta around axis
 * --------------------------------------------------------------------------
 * Notes:     o Rotation direction determined by right-hand screw rule
 *              (when subsequent qmultiply() is called with istranspose=0)
 * ======================================================================= */
/* --- entry point --- */
QUAT    qrotate ( LINE axis, double theta ) {
 /* --- allocations and declarations --- */
 QUAT   q = { cos(0.5*theta), 0.,0.,0. } ; /* constructed quaternion */
 double x = axis.pt2.x - axis.pt1.x,    /* length of x-component of axis */
        y = axis.pt2.y - axis.pt1.y,    /* length of y-component of axis */
        z = axis.pt2.z - axis.pt1.z;    /* length of z-component of axis */
 double r = sqrt((x*x)+(y*y)+(z*z));    /* length of axis */
 double qsin = sin(0.5*theta);          /* for q1,q2,q3 components */
 /* --- construct quaternion and return it to caller */
 if ( r >= 0.0000001 ) {                /* error check */
   q.q1 = qsin*x/r;                     /* i-component */
   q.q2 = qsin*y/r;                     /* j-component */
   q.q3 = qsin*z/r; }                   /* k-component */
 return ( q );
 } /* --- end-of-function qrotate() --- */


/* ==========================================================================
 * Function:    qmatrix ( QUAT q )
 * Purpose:     returns 3x3 rotation matrix corresponding to quaternion q
 *              ( can just be called as qmatrix(qrotate(axis,theta))
 *                for rotation matrix around axis through theta )
 * --------------------------------------------------------------------------
 * Arguments:   q (I)           QUAT q for which a rotation matrix
 *                              is to be constructed
 * --------------------------------------------------------------------------
 * Returns:     ( double * )    3x3 rotation matrix, stored row-wise
 * --------------------------------------------------------------------------
 * Notes:     o The matrix constructed from input q = q0+q1*i+q2*j+q3*k is:
 *                    (q0 +q1 -q2 -q3 )    2(q1q2-q0q3)     2(q1q3+q0q2)
 *                Q  =   2(q2q1+q0q3)   (q0 -q1 +q2 -q3 )   2(q2q3-q0q1)
 *                       2(q3q1-q0q2)      2(q3q2+q0q1)  (q0 -q1 -q2 +q3 )
 *            o The returned matrix is stored row-wise, i.e., explicitly
 *                --------- first row ----------
 *                qmatrix[0] = (q0 +q1 -q2 -q3 )
 *                       [1] =    2(q1q2-q0q3)
 *                       [2] =    2(q1q3+q0q2)
 *                --------- second row ---------
 *                       [3] =    2(q2q1+q0q3)
 *                       [4] = (q0 -q1 +q2 -q3 )
 *                       [5] =    2(q2q3-q0q1)
 *                --------- third row ----------
 *                       [6] =    2(q3q1-q0q2)
 *                       [7] =    2(q3q2+q0q1)
 *                       [8] = (q0 -q1 -q2 +q3 )
 *            o qmatrix maintains a static buffer of 128 3x3 matrices
 *              returned to the caller one at a time. So you may issue
 *              128 qmatrix() calls and continue using all returned matrices.
 *              The 129th call re-uses the memory used by the 1st call, etc.
 * ======================================================================= */
/* --- entry point --- */
double  *qmatrix ( QUAT q ) {
 /* --- allocations and declarations --- */
 static double Qbuff[128][9];           /* up to 128 calls before wrap-around*/
 static int    ibuff = (-1);            /* Qbuff[ibuff][] index 0<=ibuff<=63 */
 double *Q = NULL;                      /* returned ptr Q=Qbuff[ibuff] */
 double q0=q.q0, q1=q.q1, q2=q.q2, q3=q.q3; /* input quaternion components */
 double q02=q0*q0, q12=q1*q1, q22=q2*q2, q32=q3*q3; /* components squared */
 /* --- first maintain Qbuff[ibuff][] buffer --- */
 if ( ++ibuff > 127 ) ibuff=0;          /* wrap Qbuff[ibuff][] index */
 Q = Qbuff[ibuff];                      /* ptr to current 3x3 buffer */
 /* --- just do the algebra described in the above comments --- */
 Q[0] = (q02+q12-q22-q32);
 Q[1] =  2.*(q1*q2-q0*q3);
 Q[2] =  2.*(q1*q3+q0*q2);
 Q[3] =  2.*(q2*q1+q0*q3);
 Q[4] = (q02-q12+q22-q32);
 Q[5] =  2.*(q2*q3-q0*q1);
 Q[6] =  2.*(q3*q1-q0*q2);
 Q[7] =  2.*(q3*q2+q0*q1);
 Q[8] = (q02-q12-q22+q32);
 /* --- return constructed quaternion to caller */
 return ( Q );
 } /* --- end-of-function qmatrix() --- */


/* ==========================================================================
 * Function:    qmultiply ( double *Q, POINT u, int istranspose )
 * Purpose:     returns Q*u (u a column vector) if istranspose=0,
 *                   or u*Q (u a row vector)    if istranspose=1.
 * --------------------------------------------------------------------------
 * Arguments:   Q (I)           double *Q to rotation matrix returned
 *                              by qmatrix (or by some similar construction)
 *              u (I)           POINT u to column vector (or to row vector
 *                              if istranspose=1) to be multiplied by Q
 *                              (or to multiply Q if istranspose=1)
 *              istranspose (I) int istranspose=0 to return Q*u (u a col vec),
 *                              or  istranspose=1 to return u*q (u a row vec)
 * --------------------------------------------------------------------------
 * Returns:     ( POINT )       Q*u (istranspose=0), or u*Q (istranspose=1)
 * --------------------------------------------------------------------------
 * Notes:     o Q assumed to be a 3x3 matrix stored row-wise
 * ======================================================================= */
/* --- entry point --- */
POINT   qmultiply ( double *Q, POINT u, int istranspose ) {
 /* --- allocations and declarations --- */
 POINT  Qu = { 0.,0.,0. };              /* Q*u (or u*Q if istranspose=1) */
 double x=u.x, y=u.y, z=u.z;            /* x(i),y(j),z(k)-components of u */
 /* --- Q*u --- */
 if ( !istranspose ) {
   Qu.x = Q[0]*x + Q[1]*y + Q[2]*z;     /*  first row of Q * column vector u */
   Qu.y = Q[3]*x + Q[4]*y + Q[5]*z;     /* second row of Q * column vector u */
   Qu.z = Q[6]*x + Q[7]*y + Q[8]*z;     /*  third row of Q * column vector u */
   } /* --- end-of-if(!istranspose) --- */
 /* --- u*Q --- */
 if ( istranspose ) {
   Qu.x = x*Q[0] + y*Q[3] + z*Q[6];     /* row vector u *  first column of Q */
   Qu.y = x*Q[1] + y*Q[4] + z*Q[7];     /* row vector u * second column of Q */
   Qu.z = x*Q[2] + y*Q[5] + z*Q[8];     /* row vector u *  third column of Q */
   } /* --- end-of-if(istranspose) --- */
 /* --- return product to caller --- */
 return ( Qu );
 } /* --- end-of-function qmultiply() --- */

And here's a sample animation that uses the above functions to perform the frame-by-frame rotations... enter image description here

0
On

Yes, the rotation axis is oriented by the vector orthogonal to the two vectors, but we have to use a normalized vector $$\vec u=\frac{\vec a \times \vec b}{|\vec a||\vec b|}$$, and the angle $\theta$ of rotation is obtained from the inner product of the two vectors as you have done.

The matrix that represents the rotation around the axis $\vec u$ of angle $\theta$ is given here.

0
On

If you look at https://wikimedia.org/api/rest_v1/media/math/render/svg/f259f80a746ee20d481f9b7f600031084358a27c formula from wikipedia(I don't have enough rep to include the image)

we obtain the general formula for a rotation matrix about an axis defined by the vector $(u_x,u_y,u_z)$. As you said, we obtain the angle between two vectors $v$ and $w$ with $\frac{v\cdot w}{|v||w|}$ and plug that in for theta. Then we take $v\times w$ to be the vector $u$.