XNA – Quaternion

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
), although it’s very hard to understand mathematically (it makes my head blown away) a quaternion is VERY very easy to use.

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







SocialVibe