Rotating a spaceship model for a space simulator/game - c++

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

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.

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.

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

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.

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.

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.

Related

OpenGl rotations and translations

I am building a camera class to look arround a scene. At the moment I have 3 cubes just spread arround to have a good impression of what is going on. I have set my scroll button on a mouse to give me translation along z-axis and when I move my mouse left or right I detect this movement and rotate arround y-axis. This is just to see what happens and play arround a bit. So I succeeded in making the camera rotate by rotating the cubes arround the origin but after I rotate by some angle, lets say 90 degrees, and try to translate along z axis to my surprise I find out that my cubes are now going from left to right and not towards me or away from me. So what is going on here? It seems that z axis is rotated also. I guess the same goes for x axis. So it seems that nothing actually moved in regard to the origin, but the whole coordinate system with all the objects was just rotated. Can anyone help me here, what is going on? How coordinate system works in opengl?
You are most likely confusing local and global rotations. Usual cheap remedy is to change(reverse) order of some of your transformation. However doing this blindly is trial&error and can be frustrating. Its better to understand the math first...
Old API OpeGL uses MVP matrix which is:
MVP = Model * View * Projection
Where Model and View are already multiplied together. What you have is most likely the same. Now the problem is that Model is direct matrix, but View is Inverse.
So if you have some transform matrix representing your camera in oder to use it to transform back you need to use its inverse...
MVP = Model * Inverse(Camera) * Projection
Then you can use the same order of transformations for both Model and Camera and also use their geometric properties like basis vectors etc ... then stuff like camera local movements or camera follow are easy. Beware some tutorials use glTranspose instead of real matrix Inverse. That is correct only if the Matrix contains only unit (or equal sized) orthogonal basis vectors without any offset so no scale,skew,offset or projections just rotation and equal scale along all axises !!!
That means when you rotate Model and View in the same way the result is opposite. So in old code there is usual to have something like this:
// view part of matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glRotate3f(view_c,0,0,1); // ugly euler angles
glRotate3f(view_b,0,1,0); // ugly euler angles
glRotate3f(view_a,1,0,0); // ugly euler angles
glTranslatef(view_pos); // set camera position
// model part of matrix
for (i=0;i<objs;i++)
{
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glTranslatef(obj_pos[i]); // set camera position
glRotate3f(obj_a[i],1,0,0); // ugly euler angles
glRotate3f(obj_b[i],0,1,0); // ugly euler angles
glRotate3f(obj_c[i],0,0,1); // ugly euler angles
//here render obj[i]
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
note the order of transforms is opposite (I just wrote it here in editor so its not tested and can be opposite to native GL notation ... I do not use Euler angles) ... The order must match your convention... To know more about these (including examples) not using useless Euler angles see:
Understanding 4x4 homogenous transform matrices
Here is 4D version of what your 3D camera class should look like (just shrink the matrices to 4x4 and have just 3 rotations instead of 6):
reper4D
pay attention to difference between local lrot_?? and global grot_?? functions. Also note rotations are defined by plane not axis vector as axis vector is just human abstraction that does not really work except 2D and 3D ... planes work from 2D to ND
PS. its a good idea to have the distortions (scale,skew) separated from model and keep transform matrices representing coordinate systems orthonormal. It will ease up a lot of things latter on once you got to do advanced math on them. Resulting in:
MVP = Model * Model_distortion * Inverse(Camera) * Projection

Correct way to translate in a 3D world after rotating?

I have a basic cube generated in my 3D world. I can rotate correctly around the camera, but when I translate after rotating, the translations are not correct.
For example, if I rotate 90 degrees and translate into the Z axis, it would move as if translating in the X axis.
glLoadIdentity();
glRotatef(angle,0,1,0); //Rotate around the camera.
glTranslatef(movX,movY,movZ); //Translate after rotating around the camera.
glCallList(cubes[0]);
I need some help with this. Also, I tried translating before rotating, but the rotation is not at the camera. It is at the edge of the cube.
Keep in mind that in OpenGL that the transformation is applied to the camera, not the objects rendered; so you observe the inverse of the transformation you expected.
Also in OpenGL the Y and Z axes are flipped (Y is vertical), so you observe a horizontal translation instead of a vertical one.
Also, because the object is rotated though 90 degrees about Y, the X and Z axes replace each other (one of them is reversed).
willywonkadailyblah's answer is half correct. Because you are using the old OpenGL, you're using the old matrix stack. You are modifying the modelview matrix when you're doing your glRotatef and glTranslatef calls. The modelview matrix is actually the model's matrix and the camera's view matrix precombined (already multiplied together). These matrices are what determine where your object is in 3D space and where your viewing position/direction of the world is. So you can think of your calls as moving the camera, but it's probably easier to think of them as moving and rotating the world.
These rotate and translation calls are linear transformations. This has a precise definition, but for our purposes it means that you can represent the transformation as a matrix and you multiply it with the point's coordinates to apply the transformation to a point. Now matrix multiplication is not commutative, meaning AB != BA. All this to say that when you rotate, then translate it is different than translating and rotating, which I think you know. But then when you translate, rotate, and translate again, it might be a little more difficult to follow what you're actually doing. Worse even if you throw in some scaling in there. So I would suggest learning how linear transformations work and maintaining your own matrices for the objects and camera if you're serious about learning OpenGL.
learnopengl.org is an excellent website, but it teaches you Modern OpenGL, not what you're currently using. But the lesson on transformations and on coordinate systems are probably generally helpful, even without exact code for you to follow

Rotating object along all 3 axes to map to the player's camera LookAt vector

I have a simple 3D LookAt vector, and I wish to rotate the player model (a simple cube) to show where the player/cube is looking at.
For sideways camera movement I've managed to figure it out and do the following:
glTranslatef(position.x, position.y, position.z);
glRotatef(atan2(lookAt.z, lookAt.x) * 180 / PI, 0, 1, 0);
Now I know that to get up-down camera movement to map to the rendered cube model, I need to rotate the cube around it's x and z axes as well, but I can't seem to figure out what formula to use for those two.
OpenGL will rotate the whole coordinate system (whole space, not only a cube) so after first rotation you just need to rotate only around z axis.
// first rotation
glRotatef(-atan2(lookAt.z, lookAt.x) * 180 / PI, 0, 1, 0);
// second rotation
float d = sqrt(pow(lookAt.x,2) + pow(lookAt.z,2));
float pitch = atan2(lookAt.y, d);
glRotatef(pitch * 180 / PI, 0, 0, 1);
First and second rotation:
I assume your model is looking along x axis (red arrow). I also assume lookAt is given relative to the position of the model.
If you're familiar with matrix math, matrices are an easier way to think about it. If you're not familiar with matrices, this series explains how to use them to solve common game development problems: https://www.youtube.com/playlist?list=PLW3Zl3wyJwWNQjMz941uyOIq3Nw6bcDYC Getting good with matrices is a good idea if you want to be a 3D game programmer.
For your problem, you want to make a translation/rotation matrix which will transform the box to the proper place for you. You can make a translation matrix and a rotation matrix individually, and then at the end take the product of the two. I'll try to break that down.
The translation matrix is simple, if your position is then your matrix will be
To construct a rotation matrix, you need to rotate the standard basis vectors the way you want. Then when you create a matrix from those rotated basis vectors, the matrix will rotate other vectors in the same way. As an example of that, take the standard basis vectors:
Now I'm going to rotate and around by 90 degrees clockwise:
Now put them into a matrix:
and you have R is a matrix that rotates things around by 90 degrees.
In your case you want to rotate stuff such that it faces a vector that you provide. That makes things easy, we can calculate our basis vectors from that vector. If your vector is then and we can solve for the other two basis vectors using cross products. You know that the character won't ever roll their view (right?) so we can use the global up vector as well. I'll call the global up vector . In your case you're using y as the "up" dimension so the global up vector will be
Then:
In the first line you do a cross product between the view vector and the up vector to get a vector orthogonal to both - this will serve as the third basis vector after it is normalized, which is the second line. In the third line another cross product generates the second basis vector. These three vectors represent what happens when the standard basis vectors are rotated the way you want them to be. Use them as the columns in a matrix like so:
Now the last step in the math is to make a final matrix that will do both translation and rotation, and this step is easy:
Then load that matrix into OpenGL with glLoadMatrix:
glLoadMatrixf(&M);
All of this gets explained in the video series I linked as well :)

Opengl Model Matrix doesnt rotate around the origin after one rotation

I want to rotate my model Matix in x, y, and z direction, but it rotates in an unexpected way.
I use Qt.
QMatrix4x4 mMatrix;
mMatrix.setToIdentity();
mMatrix.rotate(yAngle, QVector3D(0, 1, 0));
mMatrix.rotate(zAngle, QVector3D(0, 0, 1));
mMatrix.translate(cube->getPosition());
After the first rotation the followed rotations rotate around the base of the new model Matrix, while I want the followed rotations to rotate around the origin.
I drew a little sketch so my problem might be clearer (black shows how it is right now, green is how i want it to be):
The green arrow shows how i want it to be.
I think you will get the desired result if you simply reverse the order of calls you make on the QMatrix4x4 class. To combine the two rotations:
QMatrix4x4 mMatrix;
mMatrix.setToIdentity();
mMatrix.rotate(zAngle, QVector3D(0, 0, 1));
mMatrix.rotate(yAngle, QVector3D(0, 1, 0));
The documentation is kind of lacking, but from looking at the QMatrix4x4 source code, I'm getting the impression that it applies matrix operations the way it's more or less standard with matrix libraries that are used for OpenGL, and the way the OpenGL fixed pipeline used to work.
This means that when you combine matrices, the new matrix is multiplied from the right. As a result, when the combined matrix is applied to vectors, the last specified sub-transformation is applied to the vectors first. Or putting it differently, you specify transformations in the reverse of the order you want them applied.
In your example, it you want to rotate around the y-axis first, then around the z-axis, you need to specify the z-rotation first, then the y-rotation.
I got figured it out by myself, each object needs to have its own rotation Matrix / Quaterunion.
A new rotation around the world origin ist done by creating a rotation matrix with the wanted rotation and right multiply the exiting rotation matrix of the object.
Well, if you want the green arrow thing to happen, then it means that you want a rotation around the x-axis, 90 degrees in the negative direction (or 270 degrees in the positive direction).
To make things simple, think of it like this:
Which of the axes there remains the same? x, right? Since x doesn't change, it looks like you're rotating around the x, and you are.
Now, point your thumb towards the direction that positive x is directed at and casually close the rest of your fingers like a cylinder. The direction that those rest of your fingers curling at is the direction of the rotation.
Since you want a rotation of 90 degrees in the opposite direction that those 4 fingers of yours are curling at, or 270 in the same direction... yeah.
(1, 0, 0) would be the direction vector pointing towards the positive x. While I don't know so much about the functions you're using, my guess is that the second call should be:
mMatrix.rotate(270, QVector3D(1, 0, 0));
Instead, or optionally -90 if it supports negative values.

Making an object orbit a fixed point in directx?

I am trying to make a very simple object rotate around a fixed point in 3dspace.
Basically my object is created from a single D3DXVECTOR3, which indicates the current position of the object, relative to a single constant point. Lets just say 0,0,0.
I already calculate my angle based on the current in game time of the day.
But how can i apply that angle to the position, so it will rotate?
:(?
Sorry im pretty new to Directx.
So are you trying to plot the sun or the moon?
If so then one assumes your celestial object is something like a sphere that has (0,0,0) as its center point.
Probably the easiest way to rotate it into position is to do something like the following
D3DXMATRIX matRot;
D3DXMATRIX matTrans;
D3DXMatrixRotationX( &matRot, angle );
D3DXMatrixTranslation( &matTrans, 0.0f, 0.0f, orbitRadius );
D3DXMATRIX matFinal = matTrans * matRot;
Then Set that matrix as your world matrix.
What it does is it creates a rotation matrix to rotate the object by "angle" around the XAxis (ie in the Y-Z plane); It then creates a matrix that pushes it out to the appropriate place at the 0 angle (orbitRadius may be better off as the 3rd parameter in the translation call, depending on where your zero point is). The final line multiplies these 2 matrices together. Matrix multiplications are non commutative (ie M1 * M2 != M2 * M1). What the above does is move the object orbitRadius units along the Z-axis and then it rotates that around the point (0, 0, 0). You can think of rotating an object that is held in your hand. If orbitRadius is the distance from your elbow to your hand then any rotation around your elbow (at 0,0,0) is going to form an arc through the air.
I hope that helps, but I would really recommend doing some serious reading up on Linear Algebra. The more you know the easier questions like this will be to solve yourself :)