Help needed with matrix rotation math

Started by
11 comments, last by MenDAKE 16 years ago
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;
Advertisement
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?
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.
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.
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]
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           |


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?
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]
Hmm, you lost me that time. Isn't it the same procedure as the 2D procedure I mentioned above? Or maybe I'm misundersanding.
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.

This topic is closed to new replies.

Advertisement