# How do I implement a quaternion based camera?

UPDATE The error here was a pretty simple one. I have missed a radian to degrees conversion. No need to read the whole thing if you have some other problem.

I looked at several tutorials about this and when I thought I understood I tried to implement a quaternion based camera. The problem is it doesn't work correctly, after rotating for approx. 10 degrees it jumps back to -10 degrees. I have no idea what's wrong. I'm using openTK and it already has a quaternion class. I'm a noob at opengl, I'm doing this just for fun, and don't really understand quaternions, so probably I'm doing something stupid here. Here is some code: (Actually almost all the code except the methods that load and draw a vbo (it is taken from an OpenTK sample that demonstrates vbo-s))

I load a cube into a vbo and initialize the quaternion for the camera

protected override void OnLoad(EventArgs e) {

cameraPos = new Vector3(0, 0, 7);
cameraRot = Quaternion.FromAxisAngle(new Vector3(0,0,-1), 0);

GL.ClearColor(System.Drawing.Color.MidnightBlue);
GL.Enable(EnableCap.DepthTest);

}


I load a perspective projection here. This is loaded at the beginning and every time I resize the window.

protected override void OnResize(EventArgs e) {
base.OnResize(e);

GL.Viewport(0, 0, Width, Height);

float aspect_ratio = Width / (float)Height;

Matrix4 perpective = Matrix4.CreatePerspectiveFieldOfView(MathHelper.PiOver4, aspect_ratio, 1, 64);
GL.MatrixMode(MatrixMode.Projection);
}


Here I get the last rotation value and create a new quaternion that represents only the last rotation and multiply it with the camera quaternion. After this I transform this into axis-angle so that opengl can use it. (This is how I understood it from several online quaternion tutorials)

protected override void OnRenderFrame(FrameEventArgs e) {
base.OnRenderFrame(e);

double speed = 1;
double rx = 0, ry = 0;

if (Keyboard[Key.A]) {
ry = -speed * e.Time;
}

if (Keyboard[Key.D]) {
ry = +speed * e.Time;
}

if (Keyboard[Key.W]) {
rx = +speed * e.Time;
}

if (Keyboard[Key.S]) {
rx = -speed * e.Time;
}

Quaternion tmpQuat = Quaternion.FromAxisAngle(new Vector3(0,1,0), (float)ry);
cameraRot = tmpQuat * cameraRot;
cameraRot.Normalize();

GL.MatrixMode(MatrixMode.Modelview);

Vector3 axis;
float angle;

cameraRot.ToAxisAngle(out axis, out angle);
//////////////////////////////////////////////////////////////////////
// THIS IS WHAT I DID WRONG: I NEED TO CONVERT FROM RADIANS TO DEGREES
//////////////////////////////////////////////////////////////////////
//BEFORE
//GL.Rotate(angle, axis);
//AFTER
GL.Rotate(angle * (float)180.0/(float)Math.PI, axis);
GL.Translate(-cameraPos);

Draw(vbo);
SwapBuffers();
}


Here are 2 images to explain better: I rotate a while and from this:

it jumps into this

Any help is appreciated.

Update1: I add these to a streamwriter that writes into a file:

    sw.WriteLine("camerarot: X:{0} Y:{1} Z:{2} W:{3} L:{4}", cameraRot.X, cameraRot.Y, cameraRot.Z, cameraRot.W, cameraRot.Length);
sw.WriteLine("ry: {0}", ry);


The log is available here: http://www.pasteall.org/26133/text. At line 770 the cube jumps from right to left, when camerarot.Y changes signs. I don't know if this is normal.

Update2 Here is the complete project.

• I don't understand the problem. Have you tried printing out the quaternions that you're using to render with? Nov 5, 2011 at 18:24
• Agreed, debug your rx, ry and Quaternion values. Nov 5, 2011 at 23:09
• Why don't you upload your entire project somewhere to rapidshare? Would be easier. Nov 27, 2011 at 0:50
• OK I will upload it when I get home. Nov 28, 2011 at 8:02

While you haven't shown the necessary code to verify my assumption here, I can almost guarantee that your problem is actually that this line:

cameraRot.ToAxisAngle(out axis, out angle);


is returning an angle value expressed in radians, while

GL.Rotate(angle, axis);


wants angle to be provided in degrees.

To fix it, you need to convert the angle value when passing it to GL.Rotate(), like this:

GL.Rotate(angle * 180.0/3.141593, axis);

• Yes, that was the problem. :) Thanks a lot. I knew opengl expects degrees, I assumed that ToAxisAngle returns degrees. I just looked at the opentk code and it is radians. BTW I have provided full source code at the end. Dec 1, 2011 at 19:14
• @NickCaplinger correctly points out that in C#, there is a Math.Pi constant available, which should be used in preference to the literal 3.141593 value I used in that final calculation. Jun 1, 2013 at 0:04

Don't. It may seem that it would be less work to have a camera that can be manipulated like other scene objects, but in the long run it is better to have a camera where you can define a position, eye direction and up vector. Especially when you start programming motion models it is really a pain to work with quaternions.

• Agreed. I'm not a fan of the "if it's hard to pronounce it must be better" method of designing my applications, too =) Nov 30, 2011 at 19:35
• Quaternion is hard to pronounce? Nov 30, 2011 at 20:55
• A little humor goes a long way =D By inference I imply that the question comes from someone who has no idea WHY he wants a quaternion camera, just that it's a neat buzzword and OMG I want it sooo bad now! It's certainly not a subject to tackle when something like handling radians and degree parameters properly in the broken code above isn't dealt with properly. Nov 30, 2011 at 21:34
• This question isn't really about cameras; it's about how to represent rotations in game code, and how to convert those game representations into a form such that OpenGL can use them. It's a perfectly legitimate question, and I don't think mocking the OP's lack of domain experience is helpful in any way. It's not like the OP made a stupid mistake; OpenGL's insistence on using degrees when expressing angles is downright bizarre. Everyone makes this mistake their first time using OpenGL. So get off your high horses, people. Geez. Nov 30, 2011 at 22:27
• I just wanted to understand how a quaternion based camera works and I made this project in a day when I had nothing else to do. I have no real plans with this. Dec 1, 2011 at 18:57

Don't know much about OpenTK internals. In my experience I did not see math library with proper implementation of quat that keeps needed precision (machine), because all of them affects e^2-e^3 errors. So the effect you see: the precision (and epsilon value) is about 10^-5, and it 'jumps' near zero. This is my guess :)