   Quaternion Camera trouble (SlimDX)
  I'm trying to create a free-fly camera (6dof).Since I've used XNA before, I figured I'd go with a right-handed system, since that's what XNA used.Anyways, here's my current class, which I thought was working fine at first...using System;using System.Collections.Generic;using System.Linq;using System.Text;using SlimDX;using SlimDX.DXGI;using Keys = System.Windows.Forms.Keys;using Point = System.Drawing.Point;namespace slimdxtest{    public class Camera    {   Game game;   public Matrix View;   public Matrix Projection;   public Vector3 position;   Quaternion rotation;   public Camera(Game game)   {  this.game = game;  position = new Vector3(0, 0, 10);  rotation = Quaternion.Identity;  updateView();  Projection = Matrix.PerspectiveFovRH(Const.degToRad(75), 16.0f / 9.0f, 0.1f, 100.0f);  game.inputHandler.AddMouseListener(new InputHandler.MouseCallBack(OnMouseControl));   }   private void updateView()   {  View = Matrix.Translation(position) * Matrix.RotationQuaternion(rotation);   }   public void Translate(Vector3 translate)   {    position += Vector3.TransformCoordinate(translate, Matrix.Invert(Matrix.RotationQuaternion(rotation)));  updateView();   }   public void Rotate(float yaw, float pitch, float roll)   {  rotation = Quaternion.Multiply(Quaternion.RotationYawPitchRoll(yaw, pitch, roll), rotation);  rotation.Normalize();    updateView();   }   public void OnMouseControl(Point delta)   {  Rotate((float)delta.X / 100.0f, (float)delta.Y / 100.0f, 0);   }   public void Update(GameTime gameTime)   {  float elapsedTime = gameTime.delta;  float speed = 100 * 0.025f * elapsedTime;  if(game.inputHandler.IsKeyPressed(Keys.A)) Translate(new Vector3(speed, 0, 0));  if(game.inputHandler.IsKeyPressed(Keys.D)) Translate(new Vector3(-speed, 0, 0));  if (game.inputHandler.IsKeyPressed(Keys.W)) Translate(new Vector3(0, 0, speed));  if (game.inputHandler.IsKeyPressed(Keys.S)) Translate(new Vector3(0, 0, -speed));  if (game.inputHandler.IsKeyPressed(Keys.Q)) Rotate(0, 0, -speed/3);  if (game.inputHandler.IsKeyPressed(Keys.E)) Rotate(0, 0, speed/3);   }    }}As I said, I thought this was working fine... if I pressed A my camera moved to the left and rotating was working fine...until I noticed that my input was actually inverted.See, if I press A for example, I increase the X component of my position Vector.Now this is obviously wrong, since the X Vector points to the right, not left.After some more investigating I found out that:Translating an object by (10, 0, 0) moves it to the right (so far so good)Translating the camera by (10, 0, 0) moves it to the left (this is wrong)So I assume I'm doing something wrong with the quaternion calculations, resulting in an incorrect View Matrix.This could also explain other oddities happening right now, such as specular highlights moving to the opposite direction then they should:http://www.gamedev.net/community/forums/topic.asp?topic_id=570884However I'm not yet convinced that this is the cause of this issue.The specular issue may very well be caused by an error in my shader code.Any thoughts on this?I have to admit I'm still a little confused by quaternions occasionally, but I thought I nailed it this time.Guess I thought wrong :(Thanks,HyuEdit: Yes, the specular problem is definitely related, if I use Matrix.LookAtRH to build my View matrix the specular highlights are correct.[Edited by - Hyunkel on May 12, 2010 5:12:30 PM]
  I'm not sure, but maybe this has something to do with it:http://code.google.com/p/slimdx/issues/detail?id=657   ;  First, make sure you're clear on the quaternion multiplication order used by XNA (as suggested by tgrand). I kind of doubt that's the problem (since that would mess up your rotation, not linear motion or your view transform), but it's probably worth double checking.Next, this:View = Matrix.Translation(position) * Matrix.RotationQuaternion(rotation);Looks a little suspicious. If this is actually intended to be a view (i.e. inverse camera) matrix, it should probably be (not sure what the syntax for the 'conjugate' function is):View = Matrix.Translation(-position) * Matrix.RotationQuaternion(rotation.Conjugate());This looks a little suspicious as well:position += Vector3.TransformCoordinate(translate, Matrix.Invert(Matrix.RotationQuaternion(rotation)));Why are you inverting the matrix here?   ;  Yes, you were absolutely right, that was the problem.I kept thinking of rotation matrices and completely forgot that I'm actually working an a view matrix.Failing to use the conjugate obviously resulted in the calculated view vector being inverted, so I inverted the rotation matrix for my translation function *cough*To make things worse, in my rotation function, I multiplied my quaternions in the wrong order, and that actually made it appear like everything was working fine.It took me until the specular highlight problem to realize that my view matrix was messed up.Anyways, everything is working fine now, thanks for getting me back on track :)Here's the fixed code for future reference:using System;using System.Collections.Generic;using System.Linq;using System.Text;using SlimDX;using SlimDX.DXGI;using Keys = System.Windows.Forms.Keys;using Point = System.Drawing.Point;namespace slimdxtest{    public class Camera    {   Game game;   public Matrix View;   public Matrix Projection;   public Vector3 position;   Quaternion rotation;   public Camera(Game game)   {  this.game = game;  position = new Vector3(0, 0, 10);  rotation = Quaternion.Identity;  updateView();  Projection = Matrix.PerspectiveFovRH(Const.degToRad(75), 16.0f / 9.0f, 0.1f, 100.0f);  game.inputHandler.AddMouseListener(new InputHandler.MouseCallBack(OnMouseControl));   }   private void updateView()   {  View = Matrix.Translation(-position) * Matrix.RotationQuaternion(Quaternion.Conjugate(rotation));   }   public void Translate(Vector3 translate)   {  position += Vector3.TransformCoordinate(translate, Matrix.RotationQuaternion(rotation));  updateView();   }   public void Rotate(float yaw, float pitch, float roll)   {  rotation = Quaternion.Multiply(rotation, Quaternion.RotationYawPitchRoll(yaw, pitch, roll));  rotation.Normalize();    updateView();   }   public void OnMouseControl(Point delta)   {  Rotate(-(float)delta.X / 100.0f, -(float)delta.Y / 100.0f, 0);   }   public void Update(GameTime gameTime)   {  float elapsedTime = gameTime.delta;  float speed = 100 * 0.025f * elapsedTime;  if(game.inputHandler.IsKeyPressed(Keys.A)) Translate(new Vector3(-speed, 0, 0));  if(game.inputHandler.IsKeyPressed(Keys.D)) Translate(new Vector3(speed, 0, 0));  if (game.inputHandler.IsKeyPressed(Keys.W)) Translate(new Vector3(0, 0, -speed));  if (game.inputHandler.IsKeyPressed(Keys.S)) Translate(new Vector3(0, 0, speed));  if (game.inputHandler.IsKeyPressed(Keys.Q)) Rotate(0, 0, speed/3);  if (game.inputHandler.IsKeyPressed(Keys.E)) Rotate(0, 0, -speed/3);   }    }}