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

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.

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...

• Thanks for the explanation! My mathematical background isn't enough to understand this completely, but it is a good jump off point for me to learn from. If this works with what I'm doing I will mark it as correct! – Markus T. Jul 26 '18 at 21:53
• @MarkusT. Yeah, I noticed your other "community" is stackoverflow, and figured you're likely heading in this direction (but for this type of stuff, python might not be your best choice:) – John Forkosh Jul 26 '18 at 22:40
• I thought about that, but If I only need to call the quaternion once wouldn't it not be that bad? The plan is that I'm given a vector and I need to move a robotic arm to that position based on the quaternion. In that regard would I really need to iterate through the program that much? – Markus T. Jul 26 '18 at 23:16
• @MarkusT. Sure, if you're only doing it a few times, python (or an abacus, for that matter:) "wouldn't be that bad". – John Forkosh Jul 27 '18 at 8:46

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.

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$.