Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm a beginner using XNA to try and make a 3D Asteroids game.

Update: I'm having a slightly hard time describing this so I made a little animation to show what I'm talking about: http://www.youtube.com/watch?v=4TyGQX_iRI4&feature=youtu.be

I'm really close to having my space ship drive around as if it had thrusters for pitch and yaw.

The problem is I can't quite figure out how to translate the rotations, for instance, when I pitch forward 45 degrees and then start to turn - in this case there should be rotation being applied to all three directions to get the "diagonal yaw" - right? I thought I had it right with the calculations below, but they cause a partly pitched forward ship to wobble instead of turn.... :(

So my quesiton is: how do you calculate the X, Y, and Z rotations for an object in terms of pitch and yaw?

In this picture the first is the starting position, the second is after pitch is applied, and the third is after both pitch and yaw are applied. I'm trying to figure out how to get the fourth picture to be the result of consecutive pitch and yaw operations (yaw being applied to already pitched ship).

enter image description here

Here's current (almost working) calculations for the Rotation acceleration:

        float accel = .75f;

        // Thrust +Y / Forward
        if (currentKeyboardState.IsKeyDown(Keys.I))
        {
            this.ship.AccelerationY += (float)Math.Cos(this.ship.RotationZ) * accel;
            this.ship.AccelerationX += (float)Math.Sin(this.ship.RotationZ) * -accel;
            this.ship.AccelerationZ += (float)Math.Sin(this.ship.RotationX) * accel;
        }

        // Rotation +Z / Yaw
        if (currentKeyboardState.IsKeyDown(Keys.J))
        {
            this.ship.RotationAccelerationZ += (float)Math.Cos(this.ship.RotationX) * accel;
            this.ship.RotationAccelerationY += (float)Math.Sin(this.ship.RotationX) * accel;
            this.ship.RotationAccelerationX += (float)Math.Sin(this.ship.RotationY) * accel;
        }

        // Rotation -Z / Yaw
        if (currentKeyboardState.IsKeyDown(Keys.K))
        {
            this.ship.RotationAccelerationZ += (float)Math.Cos(this.ship.RotationX) * -accel;
            this.ship.RotationAccelerationY += (float)Math.Sin(this.ship.RotationX) * -accel;
            this.ship.RotationAccelerationX += (float)Math.Sin(this.ship.RotationY) * -accel;
        }

        // Rotation +X / Pitch
        if (currentKeyboardState.IsKeyDown(Keys.F))
        {
            this.ship.RotationAccelerationX += accel;
        }

        // Rotation -X / Pitch
        if (currentKeyboardState.IsKeyDown(Keys.D))
        {
            this.ship.RotationAccelerationX -= accel;
        }

I'm combining that with drawing code that does a rotation to the model:

public void Draw(Matrix world, Matrix view, Matrix projection, TimeSpan elsapsedTime)
{
    float seconds = (float)elsapsedTime.TotalSeconds;

    // update velocity based on acceleration
    this.VelocityX += this.AccelerationX * seconds;
    this.VelocityY += this.AccelerationY * seconds;
    this.VelocityZ += this.AccelerationZ * seconds;

    // update position based on velocity
    this.PositionX += this.VelocityX * seconds;
    this.PositionY += this.VelocityY * seconds;
    this.PositionZ += this.VelocityZ * seconds;

    // update rotational velocity based on rotational acceleration
    this.RotationVelocityX += this.RotationAccelerationX * seconds;
    this.RotationVelocityY += this.RotationAccelerationY * seconds;
    this.RotationVelocityZ += this.RotationAccelerationZ * seconds;

    // update rotation based on rotational velocity
    this.RotationX += this.RotationVelocityX * seconds;
    this.RotationY += this.RotationVelocityY * seconds;
    this.RotationZ += this.RotationVelocityZ * seconds;

    Matrix translation = Matrix.CreateTranslation(PositionX, PositionY, PositionZ);

    Matrix rotation = Matrix.CreateRotationX(RotationX) * Matrix.CreateRotationY(RotationY) * Matrix.CreateRotationZ(RotationZ);

    model.Root.Transform = rotation * translation * world;

    model.CopyAbsoluteBoneTransformsTo(boneTransforms);

    foreach (ModelMesh mesh in model.Meshes)
    {
        foreach (BasicEffect effect in mesh.Effects)
        {
            effect.World = boneTransforms[mesh.ParentBone.Index];

            effect.View = view;

            effect.Projection = projection;

            effect.EnableDefaultLighting();
        }

        mesh.Draw();
    }
}
share|improve this question
    
What's the question? –  Maik Semder Nov 1 '12 at 22:22
    
I made an edit so my question is more clear –  Aaron Anodide Nov 1 '12 at 23:15

1 Answer 1

Issues with the code

Two things are not making sense in the code:

  • changing the yaw should only modify the rotation around axis Z, not X or Y.
  • the angular acceleration should be set immediately, and not depend on the current ship orientation

So your rotation acceleration code should IMHO look like this:

    // Rotation +Z/-Z -- Yaw
    if (currentKeyboardState.IsKeyDown(Keys.J))
        this.ship.RotationAccelerationZ = accel;
    else if (currentKeyboardState.IsKeyDown(Keys.K))
        this.ship.RotationAccelerationZ = -accel;
    else
        this.ship.RotationAccelerationZ = 0;

    // Rotation +X/-X -- Pitch
    if (currentKeyboardState.IsKeyDown(Keys.F))
        this.ship.RotationAccelerationX = accel;
    else if (currentKeyboardState.IsKeyDown(Keys.D))
        this.ship.RotationAccelerationX = -accel;
    else
        this.ship.RotationAccelerationX = 0;

About Euler and Tait-Bryan angles

There are two main ways to describe a rotation in terms of angles and XYZ axes:

  • when the 3rd axis is the same as the 1st axis, eg. XYX (also known as Euler angles)
  • when all 3 rotation axes are distinct, eg. XYZ (also known as Tait-Bryan angles)

The Wikipedia article on Euler angles has more information, but I must admit the article is a real mess. And then there are two basic conventions for axes:

  • when all rotations are performed around fixed axes, for instance XYZ for a rotation around axes X, Y and Z in that order
  • when each rotation also rotates the referential used for subsequent rotations; in that case the notation XY'Z" is used instead of XYZ

One nice property of the above is that a rotation of angles a, b and c around X, Y' then Z" is equivalent to a rotation of angles c, b and a around Z, Y then X.

The common understanding of pitch, yaw and roll for aircrafts is that they are Tait-Bryan angles with the referential rotating with the aircraft. So assuming Z is up and Y is forward, it is a ZX'Y" rotation. Which we just saw is equivalent to a YXZ rotation.

What you are calling “yaw being applied to already pitched ship” is actually no longer yaw: there is some roll involved, too. But one way to achieve what you want is simply to switch the order of the rotations for pitch and yaw.

share|improve this answer
    
Say the ship is pitched 45 degrees, then you're flying along and want to apply yaw in the already pitched place that the ship is in.. does that make sense? –  Aaron Anodide Nov 2 '12 at 7:43
    
@AaronAnodide if what you describe doesn't work as is, it could be that you need to switch the rotation order when you compute the rotation matrix. I’m adding more information to the answer. –  Sam Hocevar Nov 2 '12 at 7:57

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.