Camera rotation problem
I know this is one of the most basic problems in 3D graphics, but as a self-taught programmer I admit I'm having some trouble working it out. What I'm trying to do is take an object's yaw, pitch and roll values and convert them to a correct matrix or axis/angle representation for submission to OpenGL. The problems I'm trying to avoid are gimbal lock, and rotation about world rather than local axes.
For the second problem, I understand that in principal the axes of the object need to be rotated as well as the object; that is, a 45 degree yaw should also rotate the x axis 45 degrees, so that the subsequent pitch rotation will occur around the local rather than world x axis. I could do this manually, or course, but I don't think that's the way it's usually done.
I'm reasonably well versed in quaternion and matrix math and have a class for each, but I'm having trouble putting all the pieces together. At the moment I'm trying to create a Descent-style 6DOF camera. I'm sure many of you have already done this, so any input would be appreciated.
For the second problem, I understand that in principal the axes of the object need to be rotated as well as the object; that is, a 45 degree yaw should also rotate the x axis 45 degrees, so that the subsequent pitch rotation will occur around the local rather than world x axis. I could do this manually, or course, but I don't think that's the way it's usually done.
I'm reasonably well versed in quaternion and matrix math and have a class for each, but I'm having trouble putting all the pieces together. At the moment I'm trying to create a Descent-style 6DOF camera. I'm sure many of you have already done this, so any input would be appreciated.
Don't use yaw pitch and roll at all, ever.
Always use a quaternion or axis-angle representation (they're essentially equivalent; converting one to the other is trivial).
glRotatef takes the axis-angle form.
Always use a quaternion or axis-angle representation (they're essentially equivalent; converting one to the other is trivial).
glRotatef takes the axis-angle form.
Quote:Don't use yaw pitch and roll at all, ever.
Always use a quaternion or axis-angle representation (they're essentially equivalent; converting one to the other is trivial).
glRotatef takes the axis-angle form.
Ok, I'm listening. But how does one get from the user input stage to a quaternion/axis-angle representation? Mapping user input to yaw, pitch and roll is of course fairly trivial, but I'm not sure how to bypass that and go directly to the less intuitive mathematical form. If you could elaborate just a little I'd really appreciate it.
Thanks.
Well, OK, if your user input is coming in as yaw/pitch/roll, you don't have much choice.
Make a quaternion for each individual input, and multiply them in turn with your existing orientation quaternion to get the new orientation.
Make a quaternion for each individual input, and multiply them in turn with your existing orientation quaternion to get the new orientation.
Quote:Well, OK, if your user input is coming in as yaw/pitch/roll, you don't have much choice.
Make a quaternion for each individual input, and multiply them in turn with your existing orientation quaternion to get the new orientation.
Thanks very much for your input (although I'm still not clear on what alternatives there are to yaw, pitch and roll as far as user input is concerned).
In any case, I do have a Descent-style 6DOF camera working now, although I'm not sure if it's the most efficient implementation. Here's what I'm doing:
1. Read user input
2. Construct 3 quaternions (as necessary) using the three rotation deltas (yaw, pitch, roll) and the three local axes of the camera
3. Multiply the camera quaternion (which is retained frame to frame) by the three rotation quaternions
4. Normalize the camera quaternion (how often do I need to do this?)
5. Convert the camera quaternion to a matrix for submission to OpenGL
6. Extract the new local axes from the matrix for movement and rotation purposes
If anybody sees any problems with this, or knows of a more efficient method, I would love to hear your suggestions.
Quote:Originally posted by Jesse
Thanks very much for your input (although I'm still not clear on what alternatives there are to yaw, pitch and roll as far as user input is concerned).
There may well not be sensible alternatives if the user is controlling the camera movement. If the camera is on rails or whatever, there probably is.
Quote:4. Normalize the camera quaternion (how often do I need to do this?)
I'd say at least every frame, more often as empirically necessary (if you notice jumps or jerks, or can't turn an exact circle, you may need to normalize more often).
Quote:5. Convert the camera quaternion to a matrix for submission to OpenGL
6. Extract the new local axes from the matrix for movement and rotation purposes
There may be a more efficient way of doing this. You'd have to profile to find out if it was better, though, so it's probably not worthwhile, but I'll mention it.
Converting the quaternion to axis-angle form (θ = 2 acos w; v = (x / sin (θ / 2), y / sin (θ / 2), z / sin (θ / 2)) lets you submit it directly to glRotatef.
Rotating the axis vectors (1, 0, 0), (0, 1, 0) and (0, 0, 1) by this quaternion (inverse(q) (0, v) q) will get you the new axes.
Quote:Originally posted by OneSadCookie
I'd say at least every frame, more often as empirically necessary (if you notice jumps or jerks, or can't turn an exact circle, you may need to normalize more often).
In my implementation, quaternion corruption is very, very rare (every few minutes, sometimes), so you can probably get away with a quick non-square-root magnitude check each frame and normalize if it's diverged by more than, say, .00001.
Also, if you want "real" Descent-style movement, the camera rotation caused by the controls depends on the camera's current orientation, so you'll need to alter the axes of the Y/P/R quaternions before you add them to the camera.
Quote:Originally posted by Mark Levin
In my implementation, quaternion corruption is very, very rare (every few minutes, sometimes), so you can probably get away with a quick non-square-root magnitude check each frame and normalize if it's diverged by more than, say, .00001.
Yeah, but the overhead of the branch is probably more than the overhead of normalizing the quaternion each time. And if you can notice the extra 0.000001 seconds per frame caused by normalizing a quaternion, you're much more observant than I am
Quote:Also, if you want "real" Descent-style movement, the camera rotation caused by the controls depends on the camera's current orientation, so you'll need to alter the axes of the Y/P/R quaternions before you add them to the camera.
That's why he extracts the new axes from the rotation matrix.
Thanks for all the input - it's been very helpful.
If I can get away with the sqrt(), I may just normalize every frame for peace of mind. Mark, if I interpret what you're saying correctly, if I do want to normalize only when necessary I can just check the squared length, right (since it's a unit quaternion)?
Thanks again for your help.
Quote:There may be a more efficient way of doing this. You'd have to profile to find out if it was better, though, so it's probably not worthwhile, but I'll mention it.Yeah, I'd considered this, but guessed that the total cost would be more or less equivalent. I should find out for sure, though.
Converting the quaternion to axis-angle form (q = 2 acos w; v = (x / sin (q / 2), y / sin (q / 2), z / sin (q / 2)) lets you submit it directly to glRotatef.
Rotating the axis vectors (1, 0, 0), (0, 1, 0) and (0, 0, 1) by this quaternion (inverse(q) (0, v) q) will get you the new axes.
Quote:Also, if you want "real" Descent-style movement, the camera rotation caused by the controls depends on the camera's current orientation, so you'll need to alter the axes of the Y/P/R quaternions before you add them to the camera.As OneSadCookie mentioned, I'm extracting the local axes from the rotation matrix, so I think I'm doing this part correctly.
If I can get away with the sqrt(), I may just normalize every frame for peace of mind. Mark, if I interpret what you're saying correctly, if I do want to normalize only when necessary I can just check the squared length, right (since it's a unit quaternion)?
Thanks again for your help.
Quote:Originally posted by Jesse
Mark, if I interpret what you're saying correctly, if I do want to normalize only when necessary I can just check the squared length, right (since it's a unit quaternion)?
Right, numbers that close to 1 are so close to their roots/squares it really doesn't matter.
You can look at my camera tutorial.
http://kengine.sourceforge.net/tutorial/...ra-eng.htm
This tutorial describe the descent, first person and spectate camera moving.
http://kengine.sourceforge.net/tutorial/...ra-eng.htm
This tutorial describe the descent, first person and spectate camera moving.
Possibly Related Threads...
Thread: | Author | Replies: | Views: | Last Post | |
Strange problem while using 4x4 Rotation Matrix | Man With No Name | 6 | 6,046 |
Mar 11, 2008 08:00 AM Last Post: Man With No Name |