# 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) {
base.OnLoad(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);

vbo = LoadVBO(CubeVertices, CubeElements);
}


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);
GL.LoadMatrix(ref perpective);
}


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);

GL.Clear(ClearBufferMask.ColorBufferBit | ClearBufferMask.DepthBufferBit);

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);
GL.LoadIdentity();

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? – Nicol Bolas Nov 5 '11 at 18:24
• Agreed, debug your rx, ry and Quaternion values. – deceleratedcaviar Nov 5 '11 at 23:09
• Why don't you upload your entire project somewhere to rapidshare? Would be easier. – bobobobo Nov 27 '11 at 0:50
• OK I will upload it when I get home. – gyozo kudor Nov 28 '11 at 8:02

## 3 Answers

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. – gyozo kudor Dec 1 '11 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. – Trevor Powell Jun 1 '13 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 =) – Patrick Hughes Nov 30 '11 at 19:35
• Quaternion is hard to pronounce? – notlesh Nov 30 '11 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. – Patrick Hughes Nov 30 '11 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. – Trevor Powell Nov 30 '11 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. – gyozo kudor Dec 1 '11 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 :)