# Help needed with matrix rotation math

This topic is 3607 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

## Recommended Posts

I realize I'm not a top matrix math guy, but I've learned a lot over the last months especially, yet I'm still having an extremely difficult time getting a turret to rotate toward a target only on the X and Y axis, while matching its Z axis to the parent ship. I have two meshes -- my ship and my turret. The turret points at an enemy fine, but as I move my ship it will twist and rotate on the Z axis in an undesirable way. I've been working on this for weeks now, studying matrix math, searching these boards, and really giving it my best shot, but I'm simply unable to fully understand the math involved. Perhaps I have a matrix math mental block or something. I'm not sure. Can anyone help me? I'm really, really stuck right now. I feel like it's something really simple, and I'm just not seeing it. Below is the code I have so far. It's using the Truevision3D engine and C#, but it's pretty basic stuff, and should be easy enough for anyone with matrix experience to understand. It separates the X and Y axis, but I'm not sure how to then match the Z axis to the Z axis of my ship (this.weapon.Ship.RotationMatrix).
TV_3DMATRIX yawMatrix = new TV_3DMATRIX();
TV_3DMATRIX pitchMatrix = new TV_3DMATRIX();
TV_3DMATRIX finalMatrix = new TV_3DMATRIX();
TV_3DVECTOR newDV = new TV_3DVECTOR();
TV_3DVECTOR axis = new TV_3DVECTOR();

TV_3DVECTOR pos = this.Target.Position;
TV_3DVECTOR tarpos = this.weapon.Position;

TV_3DVECTOR WPV = VNormalize(VSubtract(pos, tarpos));
TV_3DVECTOR DV = new TV_3DVECTOR(0, 0, 1);

TV_3DVECTOR yawWPV = new TV_3DVECTOR(pos.x, 0, pos.z);
yawWPV = VNormalize(yawWPV);

// Yaw.
float angle = ACos(GraphicEngine.Math.VDotProduct(DV, yawWPV));

axis = VCrossProduct(DV, yawWPV);

TVMatrixRotationAxis(ref yawMatrix, axis, angle);
this.weapon.RotationMatrix = yawMatrix;

TVVec3TransformCoord(ref newDV, DV, yawMatrix);

// Pitch.
angle = ACos(GraphicEngine.Math.VDotProduct(newDV, WPV));

axis = VCrossProduct(newDV, WPV);
TVMatrixRotationAxis(ref pitchMatrix, axis, angle);
this.weapon.RotationMatrix = pitchMatrix;

TVMatrixMultiply(ref finalMatrix, yawMatrix, pitchMatrix);

weapon.RotationMatrix = finalMatrix;


##### Share on other sites
How does your ship move exactly? Is it a boat or some similar object that always remains more or less upright? Or is it a spaceship-like object that can change its orientation arbitrarily?

Also, can you describe the 'undesirable' behavior of the turret in more detail? What's it doing that it's not supposed to do?

##### Share on other sites
Thanks for taking the time to respond, jyk. My ship is a space ship that can move in any direction, and so the turret could also be on any plane, aim in any direction.

What I mean by "undesireable behavior" is simply that the Z axis does not match that of the space ship. So if I rotate my ships pitch and yaw, say, 45 degrees my turret's Z rotation will not match the Z rotation of the ship.

By the way, the code above does not include the code I use to attach the turret to the ship. I figured it wasn't important because it's rotation I'm concerned about right now.

##### Share on other sites
Ok, this might be a little complicated, but I'll try to describe how I'd do it.

First of all, it's important to be clear about the difference between the turret's local space and the turret's relationship to world space.

In local space, the turret is always aligned with the same 'up' axis (I'd use +z), and can only rotate about this 'up' axis (yaw).

At any time, you can build a local transform for the turret using this angle and the turret's position relative to the ship (in the ship's local space). When you combine this matrix with the ship's world transform matrix, you get the world transform for the turret. You'll need both for rendering, and for AI (as we'll see).

The AI problem is solved in local space. First, we transform the target position into the local space of the turret by multiplying the target position by the inverse of the turret's world transform matrix. Then, we project the target position onto the plane in which the turret can yaw by (e.g.) zeroing the 'z' component.

This leaves us with a fairly simple 2-d problem to solve; given the target position in local space, which way do we need to turn to aim at it?

I know there are quite a few details there, so post back if you have questions.

##### Share on other sites
Okay, I think I'm getting it.

For now I'm ignoring the turret's relation to the ship, because the important thing for me is to understand how to get one mesh to aim at another mesh on only the X & Y axis. If I understand your instructions correctly, the code below should provide me with the local coordinates if the target object. So now I'm just not sure how to how to solve that the "simple 2D" problem of using those coordinates to figure out which direction to turn.

TV_3DMATRIX mat = new TV_3DMATRIX();TV_3DVECTOR localTarget = new TV_3DVECTOR();float determinant = 0f;GraphicEngine.Math.TVMatrixInverse(ref mat, ref determinant, this.weapon.Matrix);GraphicEngine.Math.TVVec3TransformNormal(ref localTarget, this.Target.Position, mOrientation);

Does it look like I'm doing it right so far? I'm using the turret's matrix, and not its rotation matrix. That's the way to do it, right? If I've gotten this part down then all I should need now is to know how to figure out which way to turn the turret.

[Edited by - MenDAKE on April 2, 2008 9:59:40 AM]

##### Share on other sites
First know how to do it in math, then do it in code. This, among other things, lets you test to make sure you are doing the right thing in the code with asserts. :)

Do you know how to generate a unit vector that aims at the * on the following graph?
           |           5      *    |           |           |           |           |-0----5----+----5----0-           |           |           |           |           5           |

##### Share on other sites
Thanks. I can use all the step by step help I can get.

I believe what I need to do is subtract the target from the source, get the length of that vector and then divide the vector by its length. Is that correct?

##### Share on other sites
Ayep, that works!

Next step: what if you have a point in 3 dimensional space, and you want to have a unit vector on the (x,y,0) plane pointing in it's direction?

[Edited by - NotAYakk on April 2, 2008 2:47:42 PM]

##### Share on other sites
Hmm, you lost me that time. Isn't it the same procedure as the 2D procedure I mentioned above? Or maybe I'm misundersanding.

##### Share on other sites
Mostly the same -- but you do have to ignore the z coordinate.

Now the tricky part. We define a plane through the origin as the points:
a(x1,y1,z1) + b(x2,y2,z2)
for fixed x1,x2,y1,y2,z1,z2 and any a,b real numbers.

Traditionally, you make the two vectors (x1,y1,z1) and (x2,y2,z2) unit vectors that are orthogonal (at right angles).

The x,y plane can be viewed as the set of points {a(1,0,0) + b(0,1,0)}.

Now, you have an arbitrary point in 3d space, and you want to find out what unit vector on an arbitrary plane through the origin is pointing at it. :)

There are at least 3 ways of doing it off of the top of my head.

##### Share on other sites
Okay, I think get what you mean about the Z component. I suppose I just ignore it by keeping at 0 at all times, right?

I'm unfortunately starting to get lost with your last point, though. Forgive my ignorance. Can you explain a bit more about why we're defining a plane? It's not super clear to me.

##### Share on other sites
Take two vectors that aren't parallel. v1 and v2.

Now imagine all linear combinations of the two -- for all numbers a and b, look at what the value of a*v1 + b*v2 is.

To think about it concretely, hold up two fingers. Now imagine what points you can reach by adding any distance along the direction pointed by one finger, plus any distance along the direction pointed by another. You can use your index finger and your thumb to see this easily.

You could see how this is two dimensional? The set of "linear combinations of v1 and v2", or the points a*v1 + b*v2, is also known as the "span" of your vectors. (these are all just different ways of saying the same thing: span, linear combinations, or a*v1 + b*v2 for any number a and b).

So: two non-parallel vectors in this sense define a plane.

Now, this plane is rooted at (0,0,0) -- so it isn't quite an arbitrary plane -- so you need a third vector to offset the plane from (0,0,0). This produces an equation:

plane(a,b) = v0 + a*v1 + b*v2

If you are careful and make sure that v1 and v2 are at right angles, and are both length 1, then you have some really nice bonus properties.

Now, we can play with some math.

Remember how you dropped the z coordinate to move a point from (x,y,z) to the x,y plane? This is known as projecting your vector onto the plane.

It is a method of finding a point that is on the plane, such that the "height" vector from the point on the plane to the point off of the plane is at right angles to the plane. Whew. A way of thinking about it is that it is a "shadow" of the point on the plane.

The dot product is very useful for doing this.

(a,b,c) dot (x,y,z) is simply a*x + b*y + c*z -- it takes two vectors, and produces a number.

The beauty of the dot product is:
(w dot v1) times v1 (assuming v1 is length 1)
is the projection of w onto the line spanned by v1. (take all linear combinations of v1 -- or all multiples of v1. For any non-zero vector, this forms a line, right?)

(w dot v1) is like the x coordinate of a vector.

Look at (x,y,z) dot (1,0,0). It equals x.
And (x,y,z) dot (0,1,0) equals y.
And (x,y,z) dot (0,0,1) equals z.

Now try (x,y,z) dot (1,0,0) times (1,0,0) plus (x,y,z) dot (0,1,0) times (0,1,0).

It equals (x,y,0). That isn't a coincidence.

What I just did was find the point on the xy plane that is the projection of an arbitrary point (x,y,z) -- ie, (x,y,0).

This works so long as your vectors that define your plane are of length 1 and at right angles to each other.

So for a plane(a,b) = a*v1 + b*v2
we can project an arbitrary point (x,y,z) onto this plane via
(x,y,z)dot v1 * v1 + (x,y,z)dot v2 * v2

And that is a point on the plane(a,b) that is the projection of (x,y,z).

That works for planes that pass through (0,0,0). For arbitrary planes, we first shift (x,y,z) and the plane by our v0 vector, then do the projection trick, then shift everything back by our v0 vector.

projection(x,y,z) = (((x,y,z)-v0)dot v1 * v1 + ((x,y,z)-v0)dot v2 * v2) + v0

Viola!

Now, the next step is doing this with vectors.

Remember the definition of dot?

(a,b,c) dot (x,y,z)
= ax+by+cz

What happens when you multiply two vectors shaped matrix-like?

[x y z] * [a]           = [ax + by + cz]          [c]

Any lightbulbs going off? That should look like matrix math.

Arrange your matrix right, and you can make a matrix that projects a vector onto your plane!

Using a bit more mojo, you can even slip the translations in...

[Edited by - NotAYakk on April 6, 2008 1:16:38 AM]

##### Share on other sites
Thanks for taking the time to explain all that. I haven't studied it yet, and it turns out I have to do some traveling, so I won't get to this for a few more days, but definitely intend to get back to it. It looks very, very helpful. I think I'm finally on track to start understanding rotations better.