views:

648

answers:

6

I been working on a space sim for sometime now. At first I was using my own 3d engine with software rasterizer.

But I gave up when the time for implementing textures was due. Now I started again after sometime and now I'm using Opengl (with SDL) instead to render the 3d models.

But now I hit another brick wall.

I can't figure out how to make proper rotations. Being a space-simulator I want similar controls to a flighsim

using

glRotatef(angleX, 1.0f, 0.0f, 0.0f);
glRotatef(angleY, 0.0f, 1.0f, 0.0f);
glRotatef(angleZ, 0.0f, 0.0f, 1.0f);

or similar,
does not work properly if I rotate the model(spaceship) first 90 degrees to the left and then rotate it "up". Instead it rolls.

Here's a image that illustrate my problem.

Image Link

I tried several tricks to try and counter this but somehow I feel I missing something. It doesn't help either that simulator style rotation examples are almost impossible to find.

So I'm searching for examples, links and the theory of rotating a 3d model (like a spaceship, airplane).

Should I be using 3 vectors (left, up, forward) for orientation as I'm also going to have to calculate things like acceleration from thrusters and stuff that will change with the rotation (orientation?) and from the models perspective points in a direction like rocket-engines.

I'm not very good with math and trying to visualize a solution just give a headache

A: 

What you're going to want to use here is quaternions. They eliminate the strange behaviors you are experiencing. Thinking of them as a matrix on steroids with similar functionality. You CAN use matrices better than you are (in your code above) by using whatever OpenGL functionality that allows you to create a rotational matrix upon a particular rotational axis vector, but quaternions will store your rotations for future modification. For example, You start with an identity quaternion and rotate it upon a particular axis vector. The quaternion then gets translated into a world matrix for your object, but you keep the quaternion stored within your object. Next time you need to perform a rotation, then just further modify that quaternion instead of having to try and keep track of X, Y, and Z axis rotation degrees, etc.

My experience is within directx (sorry, no OpenGL experience here), though I did once run into your problem when I was attempting to rotate beachballs that were bouncing around a room & rotating as they encountered floors, walls, and each other.

Google has a bunch of options on "OpenGL Quaternion", but this, in particular, appears to be a good source:

http://gpwiki.org/index.php/OpenGL:Tutorials:Using_Quaternions_to_represent_rotation

As you may have guessed by now, Quaternions are great for handling cameras within your environment. Here's a great tutorial:

http://nehe.gamedev.net/data/lessons/lesson.asp?lesson=Quaternion_Camera_Class

hamlin11
+3  A: 

I'm not sure I entirely understand the situation, but it sounds like you might be describing gimbal lock. You might want to look at using quaternions to represent your rotations.

Mike Daniels
I'm been experimenting with quaternions before, but gave it a try again.Well it seems to make the rotations more correct, however now the box get a little bit distorted when I rotate it.
kvasan
+4  A: 

Getting this right certainly can be challenging. The problem I think you are facing is that you are using the same transformation matrices for rotations regardless of how the 'ship' is already oriented. But you don't want to rotate your ship based on how it would turn when it's facing forward, you want to rotate based on how it's facing now. To do that, you should transform your controlled turn matrices the same way you transform your ship.

For instance, say we've got three matrices, each representing the kinds of turns we want to do.

float theta = 10.0*(pi/180.0)

matrix<float> roll = [[ cos(theta), sin(theta), 0]
                       [ -sin(theta), cos(theta), 0]
                       [ 0, 0, 1]

matrix<float> pitch = [[ cos(theta), 0, sin(theta)]
                      [ 0, 1, 0]
                      [ -sin(theta), 0, cos(theta)]

matrix<float> yaw = [[1, 0, 0]
                     [0, cos(theta), sin(theta)]
                     [0, -sin(theta), cos(theta)]]

matrix<float> orientation = [[1, 0, 0]
                            [0, 1, 0]
                            [0, 0, 1]]

each which represent 10 degrees of rotation across each of the three flight attitude axes. Also we have a matrix for your ship's orientation, initially just strait forward. You will transform your ship's vertices by that orientation matrix to display it.

Then to get your orientation after a turn, you need to do just a bit of cleverness, first transform the attitude control matrices into the player's coordinates, and then apply that to the orientation to get a new orientation: something like

function do_roll(float amount):
    matrix<float> local_roll = amount * (roll * orientation)
    orientation = orientation * local_roll

function do_pitch(float amount):
    matrix<float> local_pitch = amount * (pitch * orientation)
    orientation = orientation * pitch_roll

function do_yaw(float amount):
    matrix<float> local_yaw = amount * (yaw * orientation)
    orientation = orientation * local_yaw

so that each time you want to rotate in one way or another, you just call one of those functions.

TokenMacGuy
+1  A: 

Quaternions may help, but a simpler solution may be to observe a strict order of rotations. It sounds like you're rotating around y, and then rotating around x. You must always rotate x first, then y, then z. Not that there's anything particularly special about that order, just that if you do it that way, rotations tend to work a little bit closer to how you expect them to work.

Edit: to clarify a little bit, you also shouldn't cumulatively rotate across time in the game. Each frame you should start your model out in identity position, and then rotate, x, y, then z, to that frame's new position.

Breton
damnit I can only vote for this once
Jim T
+1  A: 

General rotations are difficult. Physicist tend to use some set of so-called Euler angles to describe them. In this method a general rotation is described by three angles taken about three axis in fixed succession. But the three axis are not the X-, Y- and Z- axis of the original frame. They are often the Z-, Y- and Z- axis of the original frame (yes, it really is completely general), or two axis from the original frame followed by an axis in the intermediate frame. Many choices are available, and making sure that you are following the same convention all the way through can be a real hassle.

dmckee
+1  A: 

You should study 3D mathematics so that you can gain a deeper understanding of how to control rotations. If you don't know the theory it can be hard to even copy and paste correctly. Specifically texts such as 3D Math Primer(Amazon), and relevant sites like http://gamemath.com will greatly aid you in your project (and all future ones).

I understand you may not like math now, but learning the relevant arithmetic will be the best solution to your issue.

viperld002
I already have 3D Math Primer and it helped a lot when I started.Was sometime I read trough it tho, seems like I need to read trough it again.
kvasan