Aim vector rotation help

Aim vector rotation help

Hi all, I'm fairly new to 3d math but i'm making steady progress.

At present I'm trying to write some code which orients an object in 3d
to aim at another.   In 2d my steps work fine, they are:

-Create a vector U by subtracting the 2 object positions.
-Normalize the vector U
-Create a unit vector which represents the y-axis (0,1) called V
-rotation.z = acos(U dot V)

But in 3d dimensions i'm having troubles using the same kind of
approach.

I'm looking at finding the individual x,y or z rotations of the
object, but the axis vector I use in conjuction with the aim vector to
get the dot product is not enough - they give me incorrect results.
If I use the Y-axis and the aim vector to calculate the Z rotation, it
will only give accurate results if there is no movement in Z, as soon
as I move the target object in Z the rotation goes weird.

So, based on my 2d approach can someone please explain how I calculate
from a 3d vector the individual X,Y and Z rotation in relation to the
axis at the origin?

Thankyou!

Aim vector rotation help

Quote:>At present I'm trying to write some code which orients an object in 3d
>to aim at another. [snip]

You will find one answer in the FAQ for this newsgroup.

"Subject 5.26:  How can I aim a camera in a specific direction?"
<http://www.faqs.org/>

That method creates a quaternion, easily converted to a matrix. The
FAQ has a discussion and links.

"Subject 5.25: What's the big deal with quaternions?"

It is also possible to directly create a matrix, to find an axis and
angle, or to find a suitable pair of Euler angles. Someone who has
only worked in 2D may be drawn to the Euler approach, but in 3D it's
the most awkward of the four.

Aim vector rotation help

Rotate around the cross product of the two vectors by the angle
between them (which you calculate via the dot product.)  This will
give you a matrix to take "vec1" (direction o1 is facing) and rotate
it to face "vec2" (direction o2 is facing.)  Since I have it right
here, the code I usu. use is this function:

void D3DXMatrixFace(D3DXMATRIX &m, D3DXVECTOR3 vec1, D3DXVECTOR3 vec2)
{
D3DXVECTOR3 axis;
float rotation;

D3DXVec3Normalize(&vec1,&vec1);
D3DXVec3Normalize(&vec2,&vec2);
D3DXVec3Cross(&axis,&vec1,&vec2);
rotation = (float)acos(D3DXVec3Dot(&vec1,&vec2));
D3DXMatrixRotationAxis(&m,&axis,rotation);

Quote:}

void D3DXQuaternionFace(D3DXQUATERNION &q, D3DXVECTOR3 &vec1,
D3DXVECTOR3 &vec2)
{
D3DXVECTOR3 axis;
D3DXVec3Cross(&axis,&vec1,&vec2);
float rotation = (float)acos(D3DXVec3Dot(&vec1,&vec2));
D3DXQuaternionRotationAxis(&q,&axis,rotation);

Quote:}

although I make no gurantees since I haven't used them in a while
(they give you problems if you try to do smooth interpolations)

Matt

Aim vector rotation help

Thanks guys.

Firstly I think i'll move into using quarternions in the future.  For
now i'll try to make sense of Eulers - I have a lot to learn still.

Matt, I don't think the code you supplied will help me too much.  It's
geared towards rotation an object to orient it in the same direction
as another object's orientation.  I want to do something different, to
aim an object at another - regardless of the direction that 2nd object
is facing.

I think I need to project my aim vector onto 3 vectors representing
the axis, and then calculate the dot product with each rotation with
each.  Does this seem reasonable?

Aim vector rotation help

> Hi all, I'm fairly new to 3d math but i'm making steady progress.

> At present I'm trying to write some code which orients an object in 3d
> to aim at another.   ....

Lets assume: an aircraft nose (x-axis) should point to a target.
Quite clear that the roll angle phi is arbitrary.

The yaw angle psi and the pitch angle the can be calculated easily:

X1=(x,y,z)^T    Target position in ground fixed coordinates 1

A1=(a,b,c)^T    Aircraft position in ground fixed coordinates 1

R4=(1,0,0)^T    Ray vector in aircraft coordinates 4 , nose direction

Euler angle rotation

X4 = T41*X1
X1 = T14*X4   with T14=T41^T

Physical vector relation, ray has length lam (lambda)

A + lam*R = X    (this is the geometrical vector sum)

In matrices of coordinate system 1

A1 + lam*R14*R4 = X1

lam*R14*R4 = X1-A1

(1)  lam*cos(the)*cos(psi) = x-a
(2)  lam*cos(the)*sin(psi) = y-b
(3) -lam*sin(the)          = z-c

Three nonlinear equations for the,psi,lam (lam is not interesting)

(4)  Sqrt(Sqr(Eq.1)+Sqr(Eq.2))
lam*cos(the) = Sqrt(Sqr(x-a)+Sqr(y-b))

(Eq2):(Eq1)  tan(psi) = (y-b)/(x-a)
psi = atan2[y-b,x-a]

(Eq3):(Eq4)  tan(the) = -(z-c)/Sqrt(Sqr(x-a)+Sqr(y-b))
the = atan2[-(z-c),Sqrt(Sqr(x-a)+Sqr(y-b))]

Fortunately no arcsin and no arccos. Only our friend, the four-
quadrant arcustangent atan2 .

Coordinate and Euler angle definitions:
http://www.fho-emden.de/~hoffmann/euler26112001.pdf

me directly. Cannot exclude typos.

Best regards  --Gernot Hoffmann

Aim vector rotation help

Correction (a typo):

Euler angle rotation T

X4 = T41*X1
X1 = T14*X4   with T14=T41^T

Physical vector relation, ray has length lam (lambda)

A + lam*R = X    (this is the geometrical vector sum)

In matrices of coordinate system 1

A1 + lam*T14*R4 = X1

lam*T14*R4 = X1-A1

Best regards  --Gernot Hoffmann

Aim vector rotation help

Correction ( a typo):

Euler angle rotation

X4 = T41*X1
X1 = T14*X4   with T14=T41^T

Physical vector relation, ray has length lam (lambda)

A + lam*R = X    (this is the geometrical vector sum)

In matrices of coordinate system 1

A1 + lam*T14*R4 = X1

lam*T14*R4 = X1-A1

Sorry for the confusion.

G.Hoffmann

Aim vector rotation help

Quote:>Firstly I think i'll move into using quarternions in the future.  For
>now i'll try to make sense of Eulers - I have a lot to learn still.

>Matt, I don't think the code you supplied will help me too much.  It's
>geared towards rotation an object to orient it in the same direction
>as another object's orientation.  I want to do something different, to
>aim an object at another - regardless of the direction that 2nd object
>is facing.

>I think I need to project my aim vector onto 3 vectors representing
>the axis, and then calculate the dot product with each rotation with
>each.  Does this seem reasonable?

I know it's tempting to think Euler angles are the simplest approach,
so save the more complicated ideas like quaternions for later. It just
isn't true. A much better intermediate step is to keep only one angle
but also specify an axis vector. (See the end of my post for how to
solve your problem this way.)

Here's why. In 2D all rotations are planar, because the whole space is
just a plane. In 3D all rotations are planar, though the reason is
more subtle, and we have many planes to choose from. (In 4D and beyond
all rotations are *not* planar.) Euler angles artificially cut up this
single planar turn into three somewhat arbitrary axis-aligned turns.
Again and again in many different ways that dissection proves awkward.

In 2D we have two coordinate axes, but only one rotation angle. That
should give you a hint. In 3D we have three coordinate axes and three
Euler angles, but that is accidental and Euler angles do not act at
all like vectors! (In 4D we have four axes and six angles.) Although
in 2D you can reverse a rotation by negating that single angle, no
such simple prescription works with 3D Euler angles; it *does* work
with axis-angle. In 2D we can combine two rotations by adding their
angles, but in 3D with Euler angles that completely fails.

There is nothing wrong with learning Euler angles; I encourage you to
do so. Just don't delude yourself into thinking that's the simple way
to start.

Specifically, your proposal for computing the three angles is *not*
correct. A correct calculation is much more complicated to describe,
and involves the fact that Euler angles describe rotations in sequence
with a critical dependence on order. You are naively ignoring the need
to consider the sequential aspect.

Your dismissal of Matt's code is also not correct. He gives what is
essentially an axis-angle approach to do exactly what you want, if you
use it properly. He *does not* orient one object to match another. I'm
sure he expected you to understand how his code applies to your needs;
I will be more explicit.

SOLUTION.
Here's the setup. Some vector in the object you want to aim acts as a
"nose direction". In 2D you took that to be the +y unit vector (0,1),
and in 3D you seem happy to again use +y vector (0,1,0). You calculate
a desired aim vector U as a difference of object centers, normalized,
and that is correct. Now let's look at where you went wrong.

In 3D you *must* consider the plane of rotation along with the angle.
The angle between Y and U is still to be found in their dot product,
but only if you rotate *in their plane*. In axis-angle form we give
the plane of rotation by a perpendicular vector, the axis. As Matt
told you, the cross product produces it. The rotation axis will not
usually be a coordinate axis; it will be some arbitrary direction.

To summarize, you want a rotation by angle

angle = arccos(Y.U)

and axis (which you must normalize)

axis = Y x U

Be careful, because the axis calculation can give a zero vector. In
that case either you are already aiming correctly, or you must look
directly behind you by rotating 180 degrees around z. Also be careful
that you are not positioned on the point at which you wish to aim!

Aim vector rotation help

Ok, thankyou for your help all - it's starting to make sense.  Sorry
but this is all new to me.  I've hunted around the net trying to
understand quarternions - what they are and how to implement them and
I'm slowly getting the big picture.

A good link:  http://www.gamedev.net/reference/articles/article1095.asp

I managed to make my more primitive version using Eulers to work by
ensuring my vectors from source to target were "flattened" out onto an
axis plane, ie. I calculated  a vector bu subtracting the two points,
but ignoring X Y or Z depending on the axis I wanted to "flatten".

So now as everyone seems to suggest using quaternions to solve my
problem looks like something I should really be attempting next -
especially when I look towards interpolating between angles and
avoiding gimbal lock in the future.

My understanding of quaternions is growing steadily, suffice to say
I've managed to implement them into my code but with some freaky
results.

Here's the extract of the test code i'm working with to rotate a
source object to aim at another based on the code posted above.

D3DXQuaternionFace(&arrows[1],
&arrows[1].translation,&arrows[0].translation);
...
(where arrow[0] is the target, and .translation is a D3DVECTOR3)

void D3DXQuaternionFace(CArrow *tmpArrow, D3DXVECTOR3
*vec1,D3DXVECTOR3 *vec2)
{
D3DXVECTOR3 vec1tmp, vec2tmp;
D3DXMATRIX matWorld;
D3DXMATRIX matRot;

D3DXVec3Normalize(&vec1tmp, vec1);
D3DXVec3Normalize(&vec2tmp, vec2);

D3DXVec3Cross(&tmpArrow->qaxis,&vec1tmp,&vec2tmp);
tmpArrow->qrotation =(float)acos(D3DXVec3Dot(&vec1tmp,&vec2tmp));

D3DXQuaternionRotationAxis(&tmpArrow->q,&tmpArrow->qaxis,tmpArrow->qrotation);

(not sure if I need to normalize the vectors but the results are less
freaky this way...)

D3DXMatrixRotationQuaternion(&matRot,&tmpArrow->q );
D3DXMatrixMultiply(&matWorld, &matWorld, &matRot);

g_pd3dDevice->SetTransform( D3DTS_WORLD, &matWorld );
g_pd3dDevice->SetStreamSource( 0, g_pVB, 0, sizeof(CUSTOMVERTEX) );
g_pd3dDevice->SetFVF( D3DFVF_CUSTOMVERTEX );
g_pd3dDevice->DrawPrimitive( D3DPT_LINESTRIP, 0,  7);

Quote:}

As far as I can see I'm either missing the point completely, or I need
to add some more code somewhere, because this all seems to makes sense
but the results are wrong.... the source object wiggles around aiming
randomly as the target moves around.

Thanks for your time so far, any further assistance you can offer is
very much appreciated.

Aim vector rotation help

Quote:>As far as I can see I'm either missing the point completely, or I need
>to add some more code somewhere, because this all seems to makes sense
>but the results are wrong.... the source object wiggles around aiming
>randomly as the target moves around.

It's hard for me to be sure of the assumptions used in your code, so
hard to know where you've gone wrong. Instead, I'll just summarize a
way to do it right.

First, we must decide whether we want incremental aim or absolute aim.
The direction we point our nose is the same either way, but where we
start is different. For an absolute aim we start with our nose in its
original direction, never having been rotated in the world; then the
total rotation matrix will be the one we compute. For an incremental
aim we start with our nose aimed where we last pointed it, affected by
all the rotations so far; then we combine a small rotation with the
accumulated rotation. Both methods work if you're consistent.

Second, we must choose to do our rotation in either world coordinates
or body coordinates.

Third, despite the suggestion I saw in a prior post, quaternion aiming
can be done without the need for acos. The FAQ method is easier.

I will use incremental aim, world coordinates, and FAQ methods. So,
where is our nose pointed now? To find out, we either remember from
the last time we aimed, or else rotate our original nose direction
using our current rotation matrix. Let's call that unit vector N, for
"nose" or "now". Subtracting our present position from the aim point
of interest, and normalizing, we get unit aim vector U. We construct a
quaternion whose vector part is NxU and whose scalar part is (N.U)+1,
then normalize it. That describes the incremental rotation we need to
achieve our aim, in world coordinates. We multiply that into our
present rotation (also in world coordinates), accumulating a new
rotation.

The explicit formulae in the FAQ use absolute aim, always starting
with our nose aimed along -z. That's more efficient and accurate, but
my best guess is that your code is trying to use incremental aim. All
aiming formulae fail when we must pivot 180. The FAQ includes a fixup
for that, but it's more awkward to correct with incremental aim.

I'm curious as to know if there is a workaround for the following
issue:

The source code below is very similiar to what I am using to establish
object rotation matrices. It also suffers from the same problem that I
am encountering in that if the forward vector is close to or equal to
the world up vector (0,1,0 in my case) the matrix produced isn't
ideal. I know that this is down to the cross product and was wondering
if there is a simple workaround?

Any help is appreciated.

D3DXMATRIX* WINAPI D3DXMatrixLookAtLH
( D3DXMATRIX *pOut, const D3DXVECTOR3 *pEye, const D3DXVECTOR3
*pAt,
const D3DXVECTOR3 *pUp )
{
#if DBG
if(!pOut || !pEye || !pAt || !pUp)
return NULL;
#endif

D3DXVECTOR3 XAxis, YAxis, ZAxis;

// Get the z basis vector, which points straight ahead; the
// difference from the eye point to the look-at point. This is the
// direction of the gaze (+z).
D3DXVec3Subtract(&ZAxis, pAt, pEye);

// Normalize the z basis vector.
D3DXVec3Normalize(&ZAxis, &ZAxis);

// Compute the orthogonal axes from the cross product of the gaze
// and the pUp vector.
D3DXVec3Cross(&XAxis, pUp, &ZAxis);
D3DXVec3Normalize(&XAxis, &XAxis);
D3DXVec3Cross(&YAxis, &ZAxis, &XAxis);

// Start building the matrix. The first three rows contain the
// basis vectors used to rotate the view to point at the look-at
// point. The fourth row contains the translation values.
// Rotations are still about the eyepoint.
pOut->_11 = XAxis.x;
pOut->_21 = XAxis.y;
pOut->_31 = XAxis.z;
pOut->_41 = -D3DXVec3Dot(&XAxis, pEye);

pOut->_12 = YAxis.x;
pOut->_22 = YAxis.y;
pOut->_32 = YAxis.z;
pOut->_42 = -D3DXVec3Dot(&YAxis, pEye);

pOut->_13 = ZAxis.x;
pOut->_23 = ZAxis.y;
pOut->_33 = ZAxis.z;
pOut->_43 = -D3DXVec3Dot(&ZAxis, pEye);

pOut->_14 = 0.0f;
pOut->_24 = 0.0f;
pOut->_34 = 0.0f;
pOut->_44 = 1.0f;

return pOut;

2. sail