14
\$\begingroup\$

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:

this

it jumps into this

enter image description here

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.

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

3 Answers 3

9
\$\begingroup\$

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);
\$\endgroup\$
2
  • \$\begingroup\$ 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. \$\endgroup\$ Dec 1, 2011 at 19:14
  • \$\begingroup\$ @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. \$\endgroup\$ Jun 1, 2013 at 0:04
1
\$\begingroup\$

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.

\$\endgroup\$
5
  • 1
    \$\begingroup\$ Agreed. I'm not a fan of the "if it's hard to pronounce it must be better" method of designing my applications, too =) \$\endgroup\$ Nov 30, 2011 at 19:35
  • \$\begingroup\$ Quaternion is hard to pronounce? \$\endgroup\$
    – notlesh
    Nov 30, 2011 at 20:55
  • 1
    \$\begingroup\$ 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. \$\endgroup\$ Nov 30, 2011 at 21:34
  • 3
    \$\begingroup\$ 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. \$\endgroup\$ Nov 30, 2011 at 22:27
  • \$\begingroup\$ 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. \$\endgroup\$ Dec 1, 2011 at 18:57
0
\$\begingroup\$

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

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .