XNA – Quaternion

Posted: July 24, 2009 in C#, Game Programming, Programming, XNA
Tags: , ,

xna_logo

The XNA Framework provides the Quaternion structure to represent and calculate the efficient rotation about a vector around a specified angle. Quaternions represent a rotation. Typically, they are used for smooth interpolation between two angles, and for avoiding the gimbal lock problem that can occur with euler angles.

A Quaternion is much like a Matrix, but can only store a rotation. Don’t let the name of this thing scare you away (for first time i hear it, i thinks it is a weird planet’s name :D ), although it’s very hard to understand mathematically (it makes my head blown away) a quaternion is VERY very easy to use.

Untitled

In this tutorial, we will create a simple example program using quaternion, we will draw a spacecraft and it would be flying through 3D world.



First, we define two variabel below

Vector3 spacecraftPosition;
Quaternion spacecraftRotation;



Initial state for our variables

spacecraftPosition = new Vector3(-1, 1, 50);
spacecraftRotation = Quaternion.Identity;



Get the rotation

Quaternion additionalRotation = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), updownRotation) * Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), leftrightRotation);
spacecraftRotation *= additionalRotation;
AddToSpacecraftPosition(new Vector3(0, 0, -1)); // moving forward



Update spacecraft position

float moveSpeed = 0.05f;
Vector3 rotatedVector = Vector3.Transform(vectorToAdd, spacecraftRotation);
spacecraftPosition += moveSpeed * rotatedVector;



Complete code of Game1.cs

using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;

namespace BookCode
{
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        GraphicsDevice device;
        CoordCross cCross;
        Model spacecraftModel;
        Matrix[] modelTransforms;

        Matrix viewMatrix;
        Matrix projectionMatrix;

        QuaternionRotation quatRotation;

        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            Window.Title = "Quaternion Example";
        }

        protected override void Initialize()
        {
            base.Initialize();

            float viewAngle = MathHelper.PiOver4;
            float aspectRatio = graphics.GraphicsDevice.Viewport.AspectRatio;
            float nearPlane = 0.5f;
            float farPlane = 100.0f;
            projectionMatrix = Matrix.CreatePerspectiveFieldOfView(viewAngle, aspectRatio,
                nearPlane, farPlane);

            quatRotation = new QuaternionRotation();
            UpdateViewMatrix();
        }

        protected override void LoadContent()
        {
            device = graphics.GraphicsDevice;
            cCross = new CoordCross(device);
            spacecraftModel = Content.Load<Model>("p1_pencil");
            modelTransforms = new Matrix[spacecraftModel.Bones.Count];
        }

        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);
            KeyboardState keyState = Keyboard.GetState();

            if (gamePadState.Buttons.Back == ButtonState.Pressed || keyState.IsKeyDown(Keys.Escape))
                this.Exit();

            quatRotation.Update();
            UpdateViewMatrix();
            base.Update(gameTime);
        }

        private void UpdateViewMatrix()
        {
            Vector3 cameraOriginalPosition = new Vector3(0, 0, 1);
            Vector3 cameraRotatedPosition = Vector3.Transform(cameraOriginalPosition, quatRotation.SpacecraftRotation);
            Vector3 cameraFinalPosition = quatRotation.SpacecraftPosition + cameraRotatedPosition;

            Vector3 cameraOriginalUpVector = new Vector3(0, 1, 0);
            Vector3 cameraRotatedUpVector = Vector3.Transform(cameraOriginalUpVector, quatRotation.SpacecraftRotation);

            viewMatrix = Matrix.CreateLookAt(cameraFinalPosition, quatRotation.SpacecraftPosition, cameraRotatedUpVector);
        }

        protected override void Draw(GameTime gameTime)
        {
            device.Clear(ClearOptions.Target | ClearOptions.DepthBuffer, Color.CornflowerBlue, 1, 0);

            //draw coordcross
            cCross.Draw(viewMatrix, projectionMatrix);

            //draw model
            Matrix worldMatrix = Matrix.CreateScale(1.0f / 5000.0f) * Matrix.CreateFromQuaternion(quatRotation.SpacecraftRotation) * Matrix.CreateTranslation(quatRotation.SpacecraftPosition);
            spacecraftModel.CopyAbsoluteBoneTransformsTo(modelTransforms);
            foreach (ModelMesh mesh in spacecraftModel.Meshes)
            {
                foreach (BasicEffect effect in mesh.Effects)
                {
                    effect.EnableDefaultLighting();
                    effect.World = modelTransforms[mesh.ParentBone.Index] * worldMatrix;
                    effect.View = viewMatrix;
                    effect.Projection = projectionMatrix;
                }
                mesh.Draw();
            }

            base.Draw(gameTime);
        }
    }
}



Complete code of QuaternionRotation.cs

using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Storage;

namespace BookCode
{
    class QuaternionRotation
    {
        Vector3 spacecraftPosition;
        Quaternion spacecraftRotation;

        public QuaternionRotation()
        {
            spacecraftPosition = new Vector3(-1, 1, 50);
            spacecraftRotation = Quaternion.Identity;
        }

        public void Update()
        {
            GamePadState gamePadState = GamePad.GetState(PlayerIndex.One);

            float updownRotation = 0.0f;
            float leftrightRotation = 0.0f;

            leftrightRotation -= gamePadState.ThumbSticks.Left.X / 500.0f;
            updownRotation += gamePadState.ThumbSticks.Left.Y / 500.0f;

            KeyboardState keys = Keyboard.GetState();
            if (keys.IsKeyDown(Keys.Up)  || keys.IsKeyDown(Keys.W))
                updownRotation = 0.025f;
            if (keys.IsKeyDown(Keys.Down) || keys.IsKeyDown(Keys.S))
                updownRotation = -0.025f;
            if (keys.IsKeyDown(Keys.Right) || keys.IsKeyDown(Keys.D))
                leftrightRotation = -0.025f;
            if (keys.IsKeyDown(Keys.Left) || keys.IsKeyDown(Keys.A))
                leftrightRotation = 0.025f;

            leftrightRotation -= gamePadState.ThumbSticks.Left.X / 500.0f;
            updownRotation += gamePadState.ThumbSticks.Left.Y / 500.0f;

            Quaternion additionalRotation = Quaternion.CreateFromAxisAngle(new Vector3(1, 0, 0), updownRotation) * Quaternion.CreateFromAxisAngle(new Vector3(0, 1, 0), leftrightRotation);
            spacecraftRotation *= additionalRotation;

            AddToSpacecraftPosition(new Vector3(0, 0, -1));  // moving forward
        }

        private void AddToSpacecraftPosition(Vector3 vectorToAdd)
        {
            float moveSpeed = 0.05f;
            Vector3 rotatedVector = Vector3.Transform(vectorToAdd, spacecraftRotation);
            spacecraftPosition += moveSpeed * rotatedVector;
        }

        public Vector3 SpacecraftPosition
        {
            get { return spacecraftPosition; }
            set { spacecraftPosition = value; }
        }

        public Quaternion SpacecraftRotation
        {
            get { return spacecraftRotation; }
            set { spacecraftRotation = value; }
        }

    }
}



References:
http://www.riemers.net/eng/Tutorials/XNA/Csharp/Series2/Quaternions.php
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.quaternion.aspx
http://msdn.microsoft.com/en-us/library/microsoft.xna.framework.quaternion_members.aspx

Comments
  1. Binyam berhane says:

    This tutorial is help full and its beater if the full sourse of the project is available to download

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s