# Can a fellow programmer give me a suggestion please?

#### Def

##### Spaceman
Hey guys,

I have been trying to figure out this stupid rotation algorithim for my fighter to direct him to a nav point in my own D3D engine I'm playing with. Problem is I keep finding bugs in it that make it look like it's being piloted by a drunk. So far I've been able to make him fly from the origin to any point in space with no problem, he just points and shoots. But here is another math issue that has me dead in the water:

Here are my knowns: vDir(0,1,0) vPos(-50,0,100) vNav(50,0,100)

I decided I needed to break it down into 2 planes, one for the Y rotation and one for the X rotation. The rotation along the objects X axis works fine in this instance, but the Y rotation seems to break because the direction vector is (0,0) as the direction is directly up... If I pitch the fighter down the vector changes but it increases along the Nav vector, screwing everything up...

Does anyone have a solution to by-pass this rotation mess? I suspect I'll have the exact same problem yawing my fighter if it's direction vector is (1,0,0) and the nav vector is (0,1,0).

D3DXVec3Normalize(&vDir,&vDir);

D3DXVECTOR2 vDirX(vDir.y, vDir.z);
D3DXVECTOR2 vPosX(vPos.y, vPos.z);
D3DXVECTOR2 vNavX(vNav.y, vNav.z);

D3DXVECTOR2 vDirY(vDir.z, vDir.x);
D3DXVECTOR2 vPosY(vPos.z, vPos.x);
D3DXVECTOR2 vNavY(vNav.z, vNav.x);

if(vNavX != vPosX)
vNavX = vNavX - vPosX;

if(vNavY != vPosY)
vNavY = vNavY - vPosY;

D3DXVec2Normalize(&vNavX,&vNavX);
D3DXVec2Normalize(&vNavY,&vNavY);

float anglex = 0;
float angley = 0;

float xSpeed =0;
float ySpeed =1;

if(((vNavX.y * vDirX.y)+(vNavX.x * vDirX.x)))
anglex = acos( ((vNavX.y * vDirX.y)+(vNavX.x * vDirX.x)) / (D3DXVec2Length(&vNavX) * D3DXVec2Length(&vDirX)) );
else
anglex= acos(0.0f);

if(((vNavY.y * vDirY.y)+(vNavY.x * vDirY.x)))
angley = acos( ((vNavY.y * vDirY.y)+(vNavY.x * vDirY.x)) / (D3DXVec2Length(&vNavY) * D3DXVec2Length(&vDirY)) );
else
angley= acos(0.0f);

if(vNav.z < 0){
anglex = anglex * -1;
xSpeed = xSpeed * -1;
}

if(anglex > 0.001){ //Need to round it off cause of floating point accuraccy.
if(xSpeed > anglex)
xSpeed = anglex;
}
else if(anglex < -0.001){
if(xSpeed < anglex)
xSpeed = anglex;
}
else xSpeed = 0;

if(vNavY.y < 0){
angley = angley * -1;
ySpeed = ySpeed * -1;
}

if(angley > 0.001){
if(ySpeed > angley)
ySpeed = angley;
}
else if(angley < -0.001){
if(ySpeed < angley)
ySpeed = angley;
}
else ySpeed = 0;

Obj->Rotate(xSpeed,ySpeed,0);

Hmm, are you aware of quaternions? I made the mistake initially of using euler angles, that approach does not work.

I've heard of them, and I remember doing reading on them quite a bit while trying to get my ship to rotate along it's own Right, Up and Forward vectors.

But I never thought of looking into them to rotate my ships direction vector into a nav point. I will read some more into it.

What would you like to know about my engine? I'm using DirectX 9, so far I have only basic Direct sound and direct input implementation. I can load meshes, rotate them on their own axis, as well as translate them along their right, up and direction vectors. That about sums it up for now. Also I have a basic controller for my object which i'll plug my ai into to move ships around as I get things done. I havent implemented any effects yet. Just working on getting the core to work a bit better.

As a note, for a space sim, for proper rotation, you need to implement a tri-vector camera (you probably have but I did see mention of it).

I did a simple point towards the navpoint algorithm for a shaders demo a while back, I limited it to rotation on the y axis for purposes of the demo, but it can easily be expanded:

Normalise the direction vector, then use
D3DXVec3Cross(&m_rotAxis, &defaultDir, &dir);
(defualtDir will normally be (0, 0, 1)
This will give you an axis orthogonal to both the desired direction and default direction, about which to rotate.

The angle about which to rotate is
m_yAngle = acos(D3DXVec3Dot(&defaultDir, &dir));

When rendering:
Get the rotation matrix:
D3DXMATRIX rot;
D3DXMatrixRotationAxis(&rot, &m_rotAxis, m_yAngle);

Use that rotation matrix, combined with the translation matrix in the world matrix. Boom your ship should be oriented in the right direction.

Quaternions will have advatange of allowing the ship to smoothly rotate between the rotation the ship starts in and its final position using SLERP, just limiting the rotation angle will look a little funny... but it will work.

For a more robust solution use the rotation matrix on the vectors of your camera and then construct the model matrix from these.

Actaully Pedro that's pretty much how I do the rotation of the actual object... But then I exposed a public method to access the rotation for that object. So I wan't to code my AI to basically steer the ship by yawing and pitching it the required amount to get to where it needs to go.

I'll have to read on this more. I figured I would use the xSpeed and ySpeed to be the degrees per second that the fighter can turn, and plug it in that way.

Also I had another speed variable for the ships current speed... plus I have a method that increases a ships direction along a direction vector by a magnitude...

Sorry, I was in a bit of a hurry at the time (still am, off out in a mo)

Not quite sure what you're after in that case however?

Well I have been able to rotate my fighter along an arbitrary axis... I mean I can make him yaw, pitch, roll properly no matter his orientation or location on the screen...

My problem is, I am trying to make an AI that flies the fighter using the "human inputs" I am giving it.

So for instance. The AI knows where the next nav point is. Know he has to either yaw or pitch his way to the point. So in an essanse I am trying to get the amount of force, of the direction on the stick he'd be pushing/pulling in either direction to complete the turn.

I'm not sure that is the approach most solutions i've seen yet take.... Maybe it is but I am just not understanding what people are doing then?

Eurgh a little drunk, so forgive me if this is drunk (off the top of my head) but you could multiply the desired direction vector by the inverse of the rotation matrix from (0, 0, 1) to the desired direction to get the direction in the local co-ordinate system for the model, then the maths should be very simple.

Well i figured out a way to get around this problem, some what. I noticed that I was basically telling the AI to pitch forward, but the problem is the ship is already facing the right direction, it has to just yaw over 90 degrees. So I told it in the instance like this where the vector is inline with the plane to calculate the 3 dimensional vector and used that to roll and pitch my ship. Should the direction vector be on a plane. That worked like a charm....

Now next problem. Ship flies say from (0,0,0) to (0,0,100), then his next nav pops up as (-50,0,100). Since the ship is in forward motion it will pass the 100 mark on the Z plane, that means the direction to the Nav is now in a negative vector... So the ship begins to pitch and yaw to the new vector... But it seems like the ship just can't pitch and yaw fast enough to re-align to the new vector and it starts spinning wildley all over the place. But I set the forward motion to only 1 pixel per frame... should be more than slow enough to re-adjust... or maybe that's the problem it's too slow and the ship turns so fast it keeps flicking back and forth never ending... Hmmmm

Haha I tried re-adjusting the speed i'm allowing the ship to rotate by.... If I set it any lower than 1 it spins like crazy when I set the ships velocity to 0... I guess this is one of those problems you gotta let sit on the side burner for a few weeks.

Aghh... it's all to do with the accuracy of my floating point... I guess I'm trying to make my ship point a bit TOO accurately.. if i tell it to rotate only if it's greater than 0.02 radians (1.14 degrees) thn it works... well from a standstill.

I discovered the little check I was doing to make the ship turn left or right based on the direction of the nav kinda screwed it up a bit... Say I was trying to turn 180 degrees, it'd do the first rotation, then it'd notice the nav is in a negitive position now and then it'd flip it back and then it'd go until it swayed big enough to finally turn. So have to scrap that part for now hmm.

Hey guys, can you give me a suggestion as how to grab a negative angle?

Like take for example, a vector that goes (1,1) as the nav point. Now you have a vector (0,1) as your direction vector. Just by looking at it it, you know that your ship has to yaw to the right by 45 degrees to match the nav vector. But how can I tell the ship he needs to yaw to the left 45 degrees if my vector would be at (1,0) ... That's what's killing my whole flight thing right now... You can see my cheap ass if statement that does the decision based on what quadrant the Nav point is in, but obviously that is flawed because it's not taking into account where the ships direction vector is pointing.

Hey guys, I think I'm getting closer... I have actually been able to get my fighter to fly from point to point now without getting lost in space... But the route he takes to get there is still sporadic. As you know from my last post I've been having issues trying to tell my fighter whether it should turn left, right or pitch up and down....

I figured out a little piece of code I figured might work, and it's made him fly from point to point but he still seems to snap left and right, and up and down with no middle ground, it's like he has to always turn, he can't just let the stick go and straighten out. Beside that he makes it to his nav, and then flies to the next nav on his list. Here is the code I have so far, can some one see some holes in it that would cause him to turn to his extremes always and never level out?

Obj->GetCurrentDir(vDir);
Obj->GetCurrentUp(vUp);
Obj->GetCurrentRight(vRight);

D3DXVec3Normalize(&vDir,&vDir);
D3DXVec3Normalize(&vUp,&vUp);
D3DXVec3Normalize(&vRight,&vRight);

D3DXVECTOR2 vDirX(vDir.y, vDir.z);
D3DXVECTOR2 vPosX(vPos.y, vPos.z);
D3DXVECTOR2 vNavX(vNav.y, vNav.z);
D3DXVECTOR2 vUpX(vUp.y, vUp.z);

D3DXVECTOR2 vDirY(vDir.z, vDir.x);
D3DXVECTOR2 vPosY(vPos.z, vPos.x);
D3DXVECTOR2 vNavY(vNav.z, vNav.x);
D3DXVECTOR2 vRightY(vRight.z, vRight.x);

if(vNavX != vPosX)
vNavX = vNavX - vPosX;

if(vNavY != vPosY)
vNavY = vNavY - vPosY;

vNav = vNav - vPos;

D3DXVec3Normalize(&vNav,&vNav);
D3DXVec2Normalize(&vNavX,&vNavX);
D3DXVec2Normalize(&vNavY,&vNavY);

D3DXVec3Normalize(&vDir,&vDir);
D3DXVec2Normalize(&vDirX,&vDirX);
D3DXVec2Normalize(&vDirY,&vDirY);

D3DXVec2Normalize(&vRightY,&vRightY);
D3DXVec2Normalize(&vUpX,&vUpX);

float anglex = 0;
float angley = 0;

float xSpeed =0.5;
float ySpeed =0.5;

if(vDirX.y == 0 && vNavX.y == 0)
xSpeed=0;
else
anglex = acos( D3DXVec2Dot(&vNavX, &vDirX));

if(vDirY.x == 0 && vNavY.x == 0)
angley = acos( ((vNav.y * vDir.y)+(vNav.x * vDir.x)+(vNav.z * vDir.z)) / (D3DXVec3Length(&vNav) * D3DXVec3Length(&vDir)) );
else
angley = acos( D3DXVec2Dot(&vNavY,&vDirY) );

if( acos( D3DXVec2Dot(&vNavX,&vUpX) ) < 1.570796327f){
anglex = anglex * -1;
xSpeed = xSpeed * -1;
}

if(anglex > 0.02){ //Need to round it off cause of floating point accuraccy.
if(xSpeed > anglex)
xSpeed = anglex;
}
else if(anglex < -0.02){
if(xSpeed < anglex)
xSpeed = anglex;
}
else xSpeed = 0;

if(acos( D3DXVec2Dot(&vNavY,&vRightY)) > 1.570796327f){
angley = angley * -1;
ySpeed = ySpeed * -1;
}

if(angley > 0.02){
if(ySpeed > angley)
ySpeed = angley;
}
else if(angley < -0.02){
if(ySpeed < angley)
ySpeed = angley;
}
else ySpeed = 0;

Obj->Rotate(xSpeed,ySpeed,0);
Obj->Dir(Speed);