1
\$\begingroup\$

I'm developing a flight simulator based on Riemer's Blog tutorial (XNA C#). To control the aircraft, I use the following code:

Quaternion additionalRotation = Quaternion.Identity;
additionalRotation *= Quaternion.CreateFromAxisAngle(Vector3.Forward, roll);
additionalRotation *= Quaternion.CreateFromAxisAngle(Vector3.Right, pitch);
model_ROTATION *= additionalRotation;

This only executes pitch and roll. I wanted to add code so that if the aircraft is rolling, then it should rotate to right or left (yaw) so I changed the code to the following:

Quaternion additionalRotation = Quaternion.Identity;
additionalRotation *= Quaternion.CreateFromAxisAngle(Vector3.Forward,roll);
additionalRotation *= Quaternion.CreateFromAxisAngle(Vector3.Up, yaw);
additionalRotation *= Quaternion.CreateFromAxisAngle(Vector3.Right, pitch);
model_ROTATION *= additionalRotation;

This behaviour is not so realistic; when I roll the aircraft rotates to right/left (yaws), but at the same time it loses altitude and I must pitch up (pull handle) to avoid crashing.

Is there any solution to make slew rotation (yaw) without losing altitude.

\$\endgroup\$
6
  • \$\begingroup\$ Are you experience gimbal lock? When you rotate on three axis' you experience this rotational issue. The first parameter of CreateFromAxisAngle takes a normalized vector in the direction of the axis you want to rotate around. Then the second parameter is magnitude of the rotation, usually in radians. Quaternions were made primarily to avoid gimbal lock by not rotating on the three axis'. It seems you just used the quaternions to rotate on the three anyways. So you wouldn't really be avoiding it. \$\endgroup\$ Commented Mar 26, 2015 at 2:32
  • \$\begingroup\$ Andrew, lets talk only about 2 axis - about yaw and roll - I want to get following: If model makes roll then model simultaneously begins rotation around GLOBAL WORLD axis Y (changes heading) \$\endgroup\$
    – Kave
    Commented Mar 27, 2015 at 22:03
  • \$\begingroup\$ you say it "loses altitude" implying something would be wrong with the translational values? The only way you would visually see a difference in position with rotational values would be if you were rotating around the origin of the world rather than the origin of the object itself. \$\endgroup\$ Commented Mar 28, 2015 at 1:13
  • \$\begingroup\$ msdn.microsoft.com/en-us/library/bb463935.aspx I found this on msdn. A single method provided with XNA to compute roll, pitch, and yaw if you think that is what is causing your problem. \$\endgroup\$ Commented Mar 28, 2015 at 7:49
  • \$\begingroup\$ @Andrew, Is Quaternion.CreateFromYawPitchRoll related to Euler angles ? (I avoid to use them) \$\endgroup\$
    – Kave
    Commented Mar 28, 2015 at 21:55

2 Answers 2

1
\$\begingroup\$

I avoid Euler angles in aircraft pitch, roll, yaw orientations because aircraft rotate about thier local axis and trying to resolve this to Euler angles about the world (or global) axis adds uneccesary complication to the code. Instead of 3 Euler angles, I store the current orientation as a matrix or quat and simply modify the matrix/quat depending on input since last frame. A matrix or a quat is equally sufficient but the matrix has the advantage of being in the same format that you need to send to the shader anyway and it has properties that are the exact axes you need to do the rotations about. A quat is useful if you want steady slerp rates. Gimbal lock is absolutly NOT an issue when working with matrices this way.

//class scope variables
Matrix aircraftOrientationMatrix = Matrix.Identity;
float pitchChangeThisFrame, yawChangeThisFrame, rollChangeThisFrame;

//in the Update method
pitchChangeThisFrame = ?.f;//actual value based on player input
yawChangeThisFrame = ?.f;
rollChangeThisFrame = ?.f;

Vector3 pitch = aircraftOrientationMatrix.Right * pitchChangeThisFrame;//local pitch axis * amount of pitch change to apply this frame
Vector3 yaw = aircraftOrientationMatrix.Up * yawChangeThisFrame;
Vector3 roll = aircraftOrientationMatrix.Forward * rollChangeThisFrame;

Vector3 overallOrientationChangeThisFrame = pitch + yaw + roll;//
float overallAngularChangeThisFrame = overallOrientationChangeThisFrame.Length();//magnitude of all changes added together
Vector3 overallRotationAxis = Vector3.Normalize(overallOrientationChangeThisFrame);

Matrix orientationChangeThisFrame = Matrix.CreateFromAxisAngle(overallRotationAxis, overallAngularChangeThisFrame);

aircraftOrientationMatrix *= orientationChangeThisFrame;
\$\endgroup\$
3
  • \$\begingroup\$ Steve, Thank you for answer. Now I study your articles. Then I'll try to implement it in my code. Your posts are very useful. Regards, Kave \$\endgroup\$
    – Kave
    Commented Apr 2, 2015 at 16:14
  • \$\begingroup\$ Steve, Your code and articles helped me to solve problem. Thank you. \$\endgroup\$
    – Kave
    Commented Apr 12, 2015 at 20:09
  • \$\begingroup\$ Glad to hear that. Happy coding. \$\endgroup\$
    – Steve H
    Commented Apr 13, 2015 at 0:59
1
\$\begingroup\$

You're using vector3.up, vector3.forward and vector3.right to calculate the needed rotations. These axes don't move along with your plane. What you need to do is rotate the plane around its very own up, forward and right vectors. You could do that like this:

Matrix rotMat = Matrix.CreateFromQuaternion(model_ROTATION);
Quaternion additionalRotation = Quaternion.Identity;
additionalRotation *= Quaternion.CreateFromAxisAngle(rotMat.Forward,roll);
additionalRotation *= Quaternion.CreateFromAxisAngle(rotMat.Up, yaw);
additionalRotation *= Quaternion.CreateFromAxisAngle(rotMat.Right, pitch);
model_ROTATION *= additionalRotation;
\$\endgroup\$
3
  • \$\begingroup\$ Peethor, in my code vector3.up, vector3.forward and vector3.right are not global, they local relatively to model (100 %). Your solution unfortunately didn't help me - moreover it fully destroys pitch down/pitch up if I do roll and yaw. My goal - if I press arrow RIGHT/LEFT keys, model makes roll (banks) and begin to turn (rotate around GLOBAL WORLD axis Y ) without losing altitude. \$\endgroup\$
    – Kave
    Commented Mar 27, 2015 at 21:45
  • \$\begingroup\$ my code works assuming your roll pitch and yaw are relative to the plane. I realize now that you calculate yours differently. What you could do is calculate yaw pitch and roll relative to plane rotation, as would make the most sense to me, and add another rotation (yaw along global y axis) Which is relative to the amount of roll your plane has. Let's say that rotation's size is 0.1 * roll. Assuming roll stays between -pi/2 and pi/2. \$\endgroup\$
    – Peethor
    Commented Mar 29, 2015 at 9:45
  • \$\begingroup\$ I tried to do pitch and roll relative to plane rotation, and then add rotation (yaw) along global y axis - but here there is another problem - what is global Y axis in this context- in my code Vector3.Up is local axis - Only solution is to calculate global Y axis relatively to model in each frame. Anyway, thanks for help. \$\endgroup\$
    – Kave
    Commented Mar 29, 2015 at 16:21

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .