Sign in to follow this  

A Basic 3D Rotation Question

This topic is 4136 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I've decided to start learning how to use OpenGL this summer in preparation for my high school senior tech project. I've gotten to the point where I'm trying to make my first, very very simple game. However, I'm stuck on just getting the camera to work for me. I'm trying to make a game with flight-simulator-like controls. That is, my requirements are: When the user gives "up" or "down" input, the camera rotates along its local x-axis (local pitch) AND When the user gives "right" or "left" input, the camera rotates along its local z-axis (local bank). I can get either of these to work independently, but I can't get them both to work. In search of the solution, I pulled out my 3D Math Primer and learned about Euler Angles, Matrices, and Quaternions, but I don't know how to implement this technology. That is, I have classes that represent each of these and perform the necessary conversions and rotations, but I don't know how to use these high-level classes to determine the camera rotation. So far, everytime I try to implement both the local pitch and local bank controls, one of them is not local. That is, the camera will be able to bank locally (pointing at the same point), but rotates around the global x-axis for pitch, or vice-versa. So I turn to these forums for help. Can anyone give me a basic idea of how to tackle this problem? I'll try to monitor this thread frequently and keep up a dialogue until I understand the problem enough to solve it.

Share this post


Link to post
Share on other sites
The easiest way to do flight controls is to use euler angles. Most straight forward because euler angles use "flight" orientations roll/pitch/yaw. Though beware of gimbal lock though its not a terrible deal for a simple game.

The function would look like:

// Clear out whatever was in the active matrix
glLoadIdentity();

glRotatef(roll, 0.0f, 0.0f, 1.0f); // rotate about the z axis

glRotatef(yaw, 0.0f, 1.0f, 0.0f); // rotate about the y axis

glRotatef(pitch, 1.0f, 0.0f, 0.0f); // rotate about the x axis

// Remember that translating a camera is the opposite of translating an object. Its all about frame of reference
glTranslate(-positionX,-positionY,-positionZ);

// By pushing the matrix on the stack all following points will be in the frame of reference of the camera, dont forget to glPopMatrix() at the end
glPushMaxtrix();

Share this post


Link to post
Share on other sites
Yes, I'm aware of that method of rotation for the world.

My problem lies in the distinction between local and global axes. I'll give an example:

Let's say that all I've done is to bank 90 degrees so far. If the user inputs "up", the camera should rotate along the local x-axis. Increasing a global pitch angle, however, rotates along the global x-axis. From my 90-degree-banked perspective, this would make the camera turn to my left, not above me like I'm going for.

I need some method where I can tell the camera to pitch up locally and this is reflected in the global orientation.

Share this post


Link to post
Share on other sites
Quote:
Original post by Tetragrammaton
Yes, I'm aware of that method of rotation for the world.

My problem lies in the distinction between local and global axes. I'll give an example:

Let's say that all I've done is to bank 90 degrees so far. If the user inputs "up", the camera should rotate along the local x-axis. Increasing a global pitch angle, however, rotates along the global x-axis. From my 90-degree-banked perspective, this would make the camera turn to my left, not above me like I'm going for.

I need some method where I can tell the camera to pitch up locally and this is reflected in the global orientation.


You can use this to orient yourself: http://www.gamemath.com/Euler.htm

Share this post


Link to post
Share on other sites
Hey,

Your problem seems to be post-mutiply and pre-multiply of matrices.
i.e. transform-matrix * Object is not equal to Object * transform-matrix.

This is what is written in the OpenGL FAQ



9.070 How do I transform my objects around a fixed coordinate system rather than the object's local coordinate system?


If you rotate an object around its Y-axis, you'll find that the X- and Z-axes rotate with the object. A subsequent rotation around one of these axes rotates around the newly transformed axis and not the original axis. It's often desirable to perform transformations in a fixed coordinate system rather than the object’s local coordinate system.

The OpenGL Game Developer’s FAQ contains information on using quaternions to store rotations, which may be useful in solving this problem.

The root cause of the problem is that OpenGL matrix operations postmultiply onto the matrix stack, thus causing transformations to occur in object space. To affect screen space transformations, you need to premultiply. OpenGL doesn't provide a mode switch for the order of matrix multiplication, so you need to premultiply by hand. An application might implement this by retrieving the current matrix after each frame. The application multiplies new transformations for the next frame on top of an identity matrix and multiplies the accumulated current transformations (from the last frame) onto those transformations using glMultMatrix().

You need to be aware that retrieving the ModelView matrix once per frame might have a detrimental impact on your application’s performance. However, you need to benchmark this operation, because the performance will vary from one implementation to the next.


Basically there are 2 ways you can solve this.
1) Quaternions. Which can be tedious depending on your implementation.
2) Retrive the ModelView matrix and Pre multiply by using a Matrix library. Which can be slow because, you may have to retrive ModelView matix per-frame.(Though I am not sure it is that slow, we do it every frame and it's pretty quick).

Share this post


Link to post
Share on other sites
Quote:
Original post by _neutrin0_
1) Quaternions. Which can be tedious depending on your implementation.
2) Retrive the ModelView matrix and Pre multiply by using a Matrix library. Which can be slow because, you may have to retrive ModelView matix per-frame.(Though I am not sure it is that slow, we do it every frame and it's pretty quick).
Just to give the OP the full story, those aren't the only two ways to solve the problem.

First of all, you don't need quaternions: any solution to the problem that involves quaternions can be implemented just as easily using matrices. Second of all, if you have your own matrix class with the necessary operations defined, there's no need to ever query the OpenGL matrix state.

As for what solution is most appropriate, it depends on exactly what behavior you want for your object. @The OP: I have OpenGL-compatible code for 6DOF motion, if that's what you're after; I can post it if you wish. There are similar solutions for other behaviors as well (such as, say, local pitch and roll rotations but a global yaw rotation).

Share this post


Link to post
Share on other sites
Oh, thank heaven for this forum.

The problem is now solved.

As it happens, I was not storing a "current" orientation at all. Including this minor detail has made the whole thing so much easier.

Thank you to all who responded here. I appreciate the help.

I'm actually sort of glad that I stumbled around so much with this. It's been a real learning experience.

Share this post


Link to post
Share on other sites

This topic is 4136 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this