How do I rotate an object on it's own axes after I already did a view transformation?

Hello everyone!

I’m not an absolute beginner to C/C++ & OpenGL and I understand the basics of matrix multiplication and trigonometry but I seem to be stumped on something that I thought would be simple to figure out with regard to rotations and translations. Especially with a powerful GL like OpenGL.

I’ve read and done the exercises that teach the principle in OpenGL that you have to position your camera first and then plot the rest of your objects by rotating them first before translating them if you just want them to spin to face a certain direction. And you translate the object first and then do a rotation if you want them to orbit around the origin. The solar system exercises of a Sun, Moon and Earth in a couple of my books explained that really well.

I’m able to create a first person view by doing all the necessary axis-angle rotations through matrix multiplication, then I do the translation of where my view is located. I pull the look vector, up vector and right vector to know where to translate my view next and that all works fine.

The problem is that after I do the rotations and transform for my first-person camera view (which is what OpenGL instructions say comes first: the view transformations), I can’t make any other objects I want to place in my world rotate on their own axes. I have tried to find information and do searches all over the place, and other than people saying to “use gluLookAt” to solve the problem, I haven’t found anything to solve this issue. gluLookAt seems to be a special function but it wasn’t designed to be used as a real-time first-person camera for a game. At least that’s what I’ve seen written.

It’s impossible to position everything in the world first and then use rotations and a transform afterwards for my first-person camera view because they don’t work in that order. If I had the option of doing it that way: rotate things at the origin and then translate them to their final position in the world before setting up the camera view, then I wouldn’t have this problem.

Did I miss something simple here or is this a common problem/limitation with the tools OpenGL already comes with? I hope I don’t have to do a ton of matrix manipulation to get this to work but I’m more than willing to do it to make this work.

Any help that anyone can give me would be very much appreciated. :slight_smile:

Thank you.

You seem to have that backwards.

To make an object rotate about its own origin, the glRotate() needs to be the last transformation before rendering the object. So to give an object a specific position and orientation, you use glTranslate() followed by glRotate().

To make an object “orbit” about a given point, you need to use glRotate() first to followed by glTranslate().

In effect, any vectors or coordinates given as parameters to matrix functions are interpreted in the coordinate system established by all of the previous transformations. This is why the “camera” transformations have to come first. You start in “eye” coordinates, then the camera transformations establish a “world” coordinate system, from which you can then establish coordinate systems for individual objects (you would typically call glPush() before establishing any object coordinate system so that you can restore the world coordinate system afterwards using glPop()).

OpenGL matrix functions multiply each new transformation on the right of the previous ones, so the last transformation always comes immediately before the vertex position. If you think in terms of starting with the vertex coordinates passed to glVertex() etc then applying transformations until you have the coordinates in eye space, the transformations are applied in the reverse order; the last transformation command executed is the first transformation applied to the vertex position, while the “camera” transformations are the last ones applied, transforming from world space to eye space.

[QUOTE=GClements;1280891]You seem to have that backwards.

To make an object rotate about its own origin, the glRotate() needs to be the last transformation before rendering the object. So to give an object a specific position and orientation, you use glTranslate() followed by glRotate().
[/QUOTE]

I’m clearly messing something up then. :slight_smile: This is the code in my rendering function that I’m trying to get working properly:

void display()
{
// clear (has to be done at the beginning)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3ub(255, 255, 255);

// save the matrix before updating the position of the entire universe
glPushMatrix();

MultiplyTheMatrices();  // take my pitch, yaw, and roll angles and create a final matrix:  rot_tot_mat

glMultMatrixf(rot_tot_mat);  // take my rotation matrix and multiply it against the MODELVIEW matrix

// copy the current values located in the MODELVIEW_MATRIX into a GLfloat array
glGetFloatv(GL_MODELVIEW_MATRIX, view_mat);

cam_right_vector_x = view_mat[0];
cam_right_vector_y = view_mat[4];
cam_right_vector_z = view_mat[8];
cam_up_vector_x = view_mat[1];
cam_up_vector_y = view_mat[5];
cam_up_vector_z = view_mat[9];
cam_look_vector_x = view_mat[2];
cam_look_vector_y = view_mat[6];
cam_look_vector_z = view_mat[10];

// view coordinate update
move_dist_x = user_speed * (-cam_look_vector_x);
move_dist_y = user_speed * (-cam_look_vector_y);
move_dist_z = user_speed * (-cam_look_vector_z);

spaceship_x = spaceship_x + move_dist_x;
spaceship_y = spaceship_y + move_dist_y;
spaceship_z = spaceship_z + move_dist_z;

glTranslatef(-spaceship_x, -spaceship_y, -spaceship_z);  // place the view at the coordinates I want by "moving the universe"

// place the spaceship that I'm sitting in at the exact center of my view (it's just a wire sphere for now)
glPushMatrix();
glTranslatef(spaceship_x, spaceship_y, spaceship_z);  // move my "spaceship" to my view coordinates so I'm in the centre
glColor3ub(220, 220, 220);
glutWireSphere(20.0f, 20, 20);
glMultMatrixf(rot_tot_mat); // THIS IS THE PART THAT DOESN'T WORK.  I want the Wire Sphere to rotate in the same direction as my viewpoint.
glPopMatrix();                    //  It just stays pointing down the Z axis.

// place some extra wire spheres around
glPushMatrix();
glTranslatef(0.0, 0.0, -7500.0);
glColor3ub(80, 150, 255);
glutWireSphere(500.0f, 20, 20);
glPopMatrix();

glPushMatrix();
glTranslatef(0.0, 0.0, 300.0);
glColor3ub(255, 0, 0);
glutWireSphere(200.0f, 20, 20);
glPopMatrix();

glPopMatrix();

glutSwapBuffers();

}

I want the sphere I’m sitting in to rotate as I rotate so that it proves that I can get any spaceship, avatar or object I’m sitting in to turn with me as well.

If you could help me figure this out, that would be awesome.

The glMultMatrix() call has no effect because it’s immediately followed by glPopMatrix(), which discards the current matrix, replacing it with whatever is at the top of the matrix stack (i.e. the current matrix at the last call to glPushMatrix()).

If you’re trying to implement cumulative movement, you should probably forget about OpenGL matrix functions such as glRotate() and glTranslate() and just provide the constructed matrices via glLoadMatrix() or glMultMatrix().

For the camera transformation, call glLoadMatrix() with the inverse of the matrix for the object to which the viewpoint is attached.

For each object, call glPushMatrix(), glMultMatrix() with the object’s matrix, draw the object, then call glPopMatrix().

I felt really stupid about that one. I don’t know how I ended up missing it. Thank you. :slight_smile:

If you’re trying to implement cumulative movement, you should probably forget about OpenGL matrix functions such as glRotate() and glTranslate() and just provide the constructed matrices via glLoadMatrix() or glMultMatrix().

That sounds like a good idea. Multiplying a 4x4 matrix with a translation vector just gives me a 1x4 array so I don’t know how to add it to the rotation matrix to make it cumulative. For now, I used glTranslate() since I have to pull the look vector out from the results of the rotation matrix before I can translate into the direction I’m pointed and then I copied the results from GL_MODELVIEW_MATRIX and inverted that value into an inverted matrix to glLoadMatrixf() for the spaceship/sphere that I’m in.

For the camera transformation, call glLoadMatrix() with the inverse of the matrix for the object to which the viewpoint is attached.

For each object, call glPushMatrix(), glMultMatrix() with the object’s matrix, draw the object, then call glPopMatrix().

The sphere/spaceship does rotate in the same direction when I rotate now but it rotates at a bigger angle then the one I’m rotating at. Then when I start flying it flies faster than me and separates from me until I point back in the positive Z direction and comes back to me and catches up. :slight_smile:

This is definitely an improvement and I thank you so much for having helped me out thus far. I really appreciate it. I don’t know if the “invert matrix” function I found on the internet works perfectly or not, or if there are discrepancies in the rotation calculations that are throwing off the inverted matrix. Here is the code I have now for the rendering function:

void display()
{
// clear (has to be done at the beginning)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glColor3ub(255, 255, 255);

// save the matrix before updating the position of the entire universe
glPushMatrix();

MultiplyTheMatrices();  // take my pitch, yaw, and roll angles and create a rotation matrix:  rot

glMultMatrixf(rot);  // take my rotation matrix and multiply it against the MODELVIEW matrix

// copy the current values located in the MODELVIEW_MATRIX which includes the rotations
glGetFloatv(GL_MODELVIEW_MATRIX, view_mat);

cam_right_vector_x = view_mat[0];
cam_right_vector_y = view_mat[4];
cam_right_vector_z = view_mat[8];
cam_up_vector_x = view_mat[1];
cam_up_vector_y = view_mat[5];
cam_up_vector_z = view_mat[9];
cam_look_vector_x = view_mat[2];
cam_look_vector_y = view_mat[6];
cam_look_vector_z = view_mat[10];

// view coordinate update
move_dist_x = user_speed * (-cam_look_vector_x);
move_dist_y = user_speed * (-cam_look_vector_y);
move_dist_z = user_speed * (-cam_look_vector_z);

spaceship_x = spaceship_x + move_dist_x;
spaceship_y = spaceship_y + move_dist_y;
spaceship_z = spaceship_z + move_dist_z;

glTranslatef(-spaceship_x, -spaceship_y, -spaceship_z);  // place the view at the coordinates I want by "moving the universe"

glGetFloatv(GL_MODELVIEW_MATRIX, m);  // get the current GL_MODELVIEW_MATRIX which has the translation of the view included in it

InvertTheMatrix();  // make an inverted matrix of the current MODELVIEW_MATRIX and store it in inv_mat.

// place the spaceship that I'm sitting in at the exact center of my view
glPushMatrix();
glLoadMatrixf(inv_mat);   //  load the inverted matrix that has the inverted version of the rotations and translation for the view
glColor3ub(220, 220, 220);
glutWireSphere(20.0f, 20, 20);
glPopMatrix();

// place some extra wire spheres around
glPushMatrix();
glTranslatef(0.0, 0.0, -7500.0);
glColor3ub(80, 150, 255);
glutWireSphere(500.0f, 20, 20);
glPopMatrix();

glPushMatrix();
glTranslatef(0.0, 0.0, 300.0);
glColor3ub(255, 0, 0);
glutWireSphere(200.0f, 20, 20);
glPopMatrix();

glPopMatrix();

glutSwapBuffers();

}

I’m assuming that I have to do the rotations first before implementing the translation for the view, is that correct? Either way, I have to figure out why the spaceship/sphere isn’t rotating and staying with me in the centre. At least it seems consistent with where I am in the world. I can fly back to the place I started and it will meet me there. I just wish it would stay with me all the time. :slight_smile: I’m guessing that since it is still able to meet me at the starting position, it suggests that the discrepancy is a consistent miscalculation between the rotation and translation rather than an eventual value decay that corrupts the consistency of the calculations.

bool InvertTheMatrix()
{
GLfloat det; int i;

inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];

det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];

if (det == 0)
    return false;

det = 1.0 / det;

for (i = 0; i < 16; i++)
    inv_mat[i] = inv[i] * det;

return true;

}

It sounds like you’re making this harder than it should be.
If you post a complete, simplified, version of your code, I’ll look at it and make some suggestions.
Make it as simple as possible, removing all routines, objects, that aren’t pertinent to the issue.
I have to be able to compile, link, and run it.
Include a statement saying what the code does wrong and/or what you want it to do.
Also, you’ll get more responses if you put your code in [ code] and [ /code] tags (without the spaces).

[QUOTE=Carmine;1280900]It sounds like you’re making this harder than it should be.
If you post a complete, simplified, version of your code, I’ll look at it and make some suggestions.
Make it as simple as possible, removing all routines, objects, that aren’t pertinent to the issue.
I have to be able to compile, link, and run it.
Include a statement saying what the code does wrong and/or what you want it to do.
Also, you’ll get more responses if you put your code in [ code] and [ /code] tags (without the spaces).[/QUOTE]

Fair enough. I simplified it as best as I could and I used a lot of commenting in my code so that it would be quicker to grasp what I’m trying to do. Other than the rotation and positioning of my sphere/spaceship not matching the world camera view despite using the inverted matrix for its position, the following are some caveats so that anyone looking at the code doesn’t misunderstand anything:

  1. I’m assuming that for multiplying the rotation matrices, I was supposed to go X * Y = XY, and then XY * Z = final rotation. If the order is wrong, I would appreciate a correction so that I can change it. They are “not perfect” axis-angle rotations that gimbal lock after flying around on all axes for a couple of minutes. I would suggest just yawing around on the XZ plane for now to test out the problem with the sphere/spaceship not matching the world camera view. I eventually want to make this bulletproof by using Quaternions which I’m in the process of learning more about. If there is a “gimbal-lock-proof” axis-angle rotation that I could use in place of what I used in my code, I would appreciate any help in this regard.

  2. I’m assuming that for setting up the world view of the camera, I had to do the rotations first for the world view and then the translation for the world view. If I did them backwards, then please let me know.

  3. I compiled this using Mac OS X and can be compiled from the console without setting up a project file in Xcode. The comments at the beginning include instructions for which header files to include for Mac OS X and for Linux as well as the console compiling instructions for each. They were not tested on Windows at all. I’m assuming that anyone reading this forum who may not be as savvy as you fine gentlemen may want to try out the code as well so that’s why I commented like crazy and included details for compiling instructions for Mac OS X and Linux. I figure that both you and GClements know what you’re doing. :slight_smile:

With all that out of the way, here is the code:


//
//  SpaceTrip.cpp
//

#include <OpenGL/gl.h>   // For Mac OS X.
#include <GLUT/glut.h>   // For Mac OS X.
//
// For Mac OS X, compile using:  g++ -o SpaceTrip SpaceTrip.cpp -framework OpenGL - framework GLUT
//
//
// For Linux:  #include <GL/gl.h>
// "           #include <GL/glu.h>
// "           #include <GL/glut.h>
//
// Compile using:  g++ -o SpaceTrip SpaceTrip.cpp -lglut -lGLU -lGL

#include <cmath>
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <iostream>
using namespace std;

// update rate (60 fps)
int interval = 1000 / 60;

GLfloat DegreesToRadians(GLfloat angle_in_degrees);

void MultiplyTheMatrices();

bool InvertTheMatrix();

GLfloat move_dist_x = 0.0;  GLfloat move_dist_y = 0.0;  GLfloat move_dist_z = 0.0;

// spaceship (user's view) coordinates
GLfloat spaceship_x = 0.0;  GLfloat spaceship_y = 0.0;  GLfloat spaceship_z = 0.0;

// rotation of user's view
GLfloat yaw_angle = 0.0;  GLfloat pitch_angle = 0.0;  GLfloat roll_angle = 0.0;

GLfloat user_speed = 0.0;

GLfloat cam_right_vector_x = 0.0;  GLfloat cam_right_vector_y = 0.0;  GLfloat cam_right_vector_z = 0.0;
GLfloat cam_up_vector_x = 0.0;  GLfloat cam_up_vector_y = 0.0;  GLfloat cam_up_vector_z = 0.0;
GLfloat cam_look_vector_x = 0.0;  GLfloat cam_look_vector_y = 0.0;  GLfloat cam_look_vector_z = 0.0;

GLfloat rot_x_mat[16];  // rotation x matrix with values set in MultiplyTheMatrices() function
GLfloat rot_y_mat[16];  // rotation y matrix with values set in MultiplyTheMatrices() function
GLfloat rot_z_mat[16];  // rotation z matrix with values set in MultiplyTheMatrices() function
GLfloat temp_mat[16];   // first step in rotation matrix calculation by multiplying (rot_x_mat * rot_y_mat)
GLfloat rot[16];        // final rotation matrix created by multiplying (temp_mat * rot_z_mat)

GLfloat view_mat[16];   // array used to grab matrix values from GL_MODELVIEW_MATRIX after rotations for the world view are performed but before the translation of the world view is performed

GLfloat m[16];   // array used to grab matrix values from GL_MODELVIEW_MATRIX after both the rotations for the world view and the translation of the world view are performed

GLfloat inv[16];  // array used by the InvertTheMatrix() function

GLfloat inv_mat[16];  // array used to store the inverted form of the world view matrix stored in m[16] so that the spaceship/wiresphere can be positioned at the world camera coordinate facing in the same direction as the camera view

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
}

void display()
{
    // clear (has to be done at the beginning)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3ub(255, 255, 255);

    // save the matrix before updating the position of the entire universe
    glPushMatrix();
    
    MultiplyTheMatrices();  // take my pitch, yaw, and roll angles and create a rotation matrix:  rot
    
    glMultMatrixf(rot);  // take my rotation matrix and multiply it against the MODELVIEW matrix
    
    // copy the current values located in the MODELVIEW_MATRIX which includes the rotations
    glGetFloatv(GL_MODELVIEW_MATRIX, view_mat);
    
    cam_right_vector_x = view_mat[0];
    cam_right_vector_y = view_mat[4];
    cam_right_vector_z = view_mat[8];
    cam_up_vector_x = view_mat[1];
    cam_up_vector_y = view_mat[5];
    cam_up_vector_z = view_mat[9];
    cam_look_vector_x = view_mat[2];
    cam_look_vector_y = view_mat[6];
    cam_look_vector_z = view_mat[10];
    
    // view coordinate update
    move_dist_x = user_speed * (-cam_look_vector_x);
    move_dist_y = user_speed * (-cam_look_vector_y);
    move_dist_z = user_speed * (-cam_look_vector_z);
    
    spaceship_x = spaceship_x + move_dist_x;
    spaceship_y = spaceship_y + move_dist_y;
    spaceship_z = spaceship_z + move_dist_z;
    
    glTranslatef(-spaceship_x, -spaceship_y, -spaceship_z);  // place the view at the coordinates I want by "moving the universe"
    
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    
    InvertTheMatrix();  // make an inverted matrix of the current MODELVIEW_MATRIX and store it in inv_mat.

    // place the spaceship that I'm sitting in at the exact center of my view
    glPushMatrix();
    glLoadMatrixf(inv_mat);  // apply the inverted matrix in order to position my spaceship/sphere at the correct view position and rotation as the world view - NOT WORKING PROPERLY, NEED HELP WITH THIS.
    glColor3ub(220, 220, 220);
    glutWireSphere(20.0f, 20, 20);
    glPopMatrix();
    
    // place some extra wire spheres around so that flying through space doesn't look completely empty
    glPushMatrix();
    glTranslatef(0.0, 0.0, -7500.0);
    glColor3ub(80, 150, 255);
    glutWireSphere(500.0f, 20, 20);  // big blue sphere positioned starting 7500 units in front of you
    glPopMatrix();
    
    glPushMatrix();
    glTranslatef(0.0, 0.0, 300.0);
    glColor3ub(255, 0, 0);
    glutWireSphere(200.0f, 20, 20);  // small red sphere positioned starting 300 units behind you
    glPopMatrix();
    
    glPopMatrix();

    glutSwapBuffers();
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 'l':
            // increase speed
            if(user_speed < 20.0)
                user_speed = user_speed + 1.0;
            break;
            
        case 'k':
            // decrease speed
            if(user_speed >= 1.0)
                user_speed = user_speed - 1.0;
            break;
            
        case '2':
            // pitch up
            pitch_angle = pitch_angle - 4.5;
            if (pitch_angle <= -360.0)
                pitch_angle = pitch_angle + 360.0;
            break;
            
        case '8':
            // pitch down
            pitch_angle = pitch_angle + 4.5;
            if (pitch_angle >= 360.0)
                pitch_angle = pitch_angle - 360.0;
            break;
            
        case '4':
            // yaw to the left
            yaw_angle = yaw_angle - 4.5;
            if (yaw_angle <= -360.0)
                yaw_angle = yaw_angle + 360.0;
            break;
            
        case '6':
            // yaw to the right
            yaw_angle = yaw_angle + 4.5;
            if (yaw_angle >= 360.0)
                yaw_angle = yaw_angle - 360.0;
            break;
            
        case '1':
            // pitch up and yaw to the left
            pitch_angle = pitch_angle - 4.5;
            if (pitch_angle <= -360.0)
                pitch_angle = pitch_angle + 360.0;
            yaw_angle = yaw_angle - 4.5;
            if (yaw_angle <= -360.0)
                yaw_angle = yaw_angle + 360.0;
            break;
            
        case '3':
            // pitch up and yaw to the right
            pitch_angle = pitch_angle - 4.5;
            if (pitch_angle <= -360.0)
                pitch_angle = pitch_angle + 360.0;
            yaw_angle = yaw_angle + 4.5;
            if (yaw_angle >= 360.0)
                yaw_angle = yaw_angle - 360.0;
            break;

        case '7':
            // pitch down and yaw to the left
            pitch_angle = pitch_angle + 4.5;
            if (pitch_angle >= 360.0)
                pitch_angle = pitch_angle - 360.0;
            yaw_angle = yaw_angle - 4.5;
            if (yaw_angle <= -360.0)
                yaw_angle = yaw_angle + 360.0;
            break;
            
        case '9':
            // pitch down and yaw to the right
            pitch_angle = pitch_angle + 4.5;
            if (pitch_angle >= 360.0)
                pitch_angle = pitch_angle - 360.0;
            yaw_angle = yaw_angle + 4.5;
            if (yaw_angle >= 360.0)
                yaw_angle = yaw_angle - 360.0;
            break;
            
        case ',':
            // roll to the left
            roll_angle = roll_angle - 4.5;
            if (roll_angle <= -360.0)
                roll_angle = roll_angle + 360.0;
            break;
            
        case '.':
            // roll to the right
            roll_angle = roll_angle + 4.5;
            if (roll_angle >= 360.0)
                roll_angle = roll_angle - 360.0;
            break;
            
        case 'b':
            exit(0);
            break;
            
        default:
            break;
    }
}

void update(int value)
{
    glutTimerFunc(interval, update, 0);
    
    glutPostRedisplay();
}

void reshape(int width, int height)
{
    glViewport(0, 0, (GLsizei) width, (GLsizei) height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0f, (GLfloat) width/(GLfloat) height, 1.0f, 1000000.0f);
    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity();
}

GLfloat DegreesToRadians(GLfloat angle_in_degrees)
{
    GLfloat radians = 0.0;
    
    radians = ((angle_in_degrees * 3.141592653589793238462643383279) / 180.0);
    
    return radians;
}

void MultiplyTheMatrices()
{
    rot_x_mat[0] = 1.0;
    rot_x_mat[1] = 0.0;
    rot_x_mat[2] = 0.0;
    rot_x_mat[3] = 0.0;
    rot_x_mat[4] = 0.0;
    rot_x_mat[5] = cosf(DegreesToRadians(pitch_angle));
    rot_x_mat[6] = sinf(DegreesToRadians(pitch_angle));
    rot_x_mat[7] = 0.0;
    rot_x_mat[8] = 0.0;
    rot_x_mat[9] = -(sinf(DegreesToRadians(pitch_angle)));
    rot_x_mat[10] = cosf(DegreesToRadians(pitch_angle));
    rot_x_mat[11] = 0.0;
    rot_x_mat[12] = 0.0;
    rot_x_mat[13] = 0.0;
    rot_x_mat[14] = 0.0;
    rot_x_mat[15] = 1.0;
    
    rot_y_mat[0] = cosf(DegreesToRadians(yaw_angle));
    rot_y_mat[1] = 0.0;
    rot_y_mat[2] = -(sinf(DegreesToRadians(yaw_angle)));
    rot_y_mat[3] = 0.0;
    rot_y_mat[4] = 0.0;
    rot_y_mat[5] = 1.0;
    rot_y_mat[6] = 0.0;
    rot_y_mat[7] = 0.0;
    rot_y_mat[8] = sinf(DegreesToRadians(yaw_angle));
    rot_y_mat[9] = 0.0;
    rot_y_mat[10] = cosf(DegreesToRadians(yaw_angle));
    rot_y_mat[11] = 0.0;
    rot_y_mat[12] = 0.0;
    rot_y_mat[13] = 0.0;
    rot_y_mat[14] = 0.0;
    rot_y_mat[15] = 1.0;
    
    rot_z_mat[0] = cosf(DegreesToRadians(roll_angle));
    rot_z_mat[1] = -(sinf(DegreesToRadians(roll_angle)));
    rot_z_mat[2] = 0.0;
    rot_z_mat[3] = 0.0;
    rot_z_mat[4] = sinf(DegreesToRadians(roll_angle));
    rot_z_mat[5] = cosf(DegreesToRadians(roll_angle));
    rot_z_mat[6] = 0.0;
    rot_z_mat[7] = 0.0;
    rot_z_mat[8] = 0.0;
    rot_z_mat[9] = 0.0;
    rot_z_mat[10] = 1.0;
    rot_z_mat[11] = 0.0;
    rot_z_mat[12] = 0.0;
    rot_z_mat[13] = 0.0;
    rot_z_mat[14] = 0.0;
    rot_z_mat[15] = 1.0;
    
    temp_mat[0] = (rot_x_mat[0] * rot_y_mat[0]) + (rot_x_mat[4] * rot_y_mat[1]) + (rot_x_mat[8] * rot_y_mat[2]) + (rot_x_mat[12] * rot_y_mat[3]);
    temp_mat[1] = (rot_x_mat[0] * rot_y_mat[4]) + (rot_x_mat[4] * rot_y_mat[5]) + (rot_x_mat[8] * rot_y_mat[6]) + (rot_x_mat[12] * rot_y_mat[7]);
    temp_mat[2] = (rot_x_mat[0] * rot_y_mat[8]) + (rot_x_mat[4] * rot_y_mat[9]) + (rot_x_mat[8] * rot_y_mat[10]) + (rot_x_mat[12] * rot_y_mat[11]);
    temp_mat[3] = (rot_x_mat[0] * rot_y_mat[12]) + (rot_x_mat[4] * rot_y_mat[13]) + (rot_x_mat[8] * rot_y_mat[14]) + (rot_x_mat[12] * rot_y_mat[15]);
    temp_mat[4] = (rot_x_mat[1] * rot_y_mat[0]) + (rot_x_mat[5] * rot_y_mat[1]) + (rot_x_mat[9] * rot_y_mat[2]) + (rot_x_mat[13] * rot_y_mat[3]);
    temp_mat[5] = (rot_x_mat[1] * rot_y_mat[4]) + (rot_x_mat[5] * rot_y_mat[5]) + (rot_x_mat[9] * rot_y_mat[6]) + (rot_x_mat[13] * rot_y_mat[7]);
    temp_mat[6] = (rot_x_mat[1] * rot_y_mat[8]) + (rot_x_mat[5] * rot_y_mat[9]) + (rot_x_mat[9] * rot_y_mat[10]) + (rot_x_mat[13] * rot_y_mat[11]);
    temp_mat[7] = (rot_x_mat[1] * rot_y_mat[12]) + (rot_x_mat[5] * rot_y_mat[13]) + (rot_x_mat[9] * rot_y_mat[14]) + (rot_x_mat[13] * rot_y_mat[15]);
    temp_mat[8] = (rot_x_mat[2] * rot_y_mat[0]) + (rot_x_mat[6] * rot_y_mat[1]) + (rot_x_mat[10] * rot_y_mat[2]) + (rot_x_mat[14] * rot_y_mat[3]);
    temp_mat[9] = (rot_x_mat[2] * rot_y_mat[4]) + (rot_x_mat[6] * rot_y_mat[5]) + (rot_x_mat[10] * rot_y_mat[6]) + (rot_x_mat[14] * rot_y_mat[7]);
    temp_mat[10] = (rot_x_mat[2] * rot_y_mat[8]) + (rot_x_mat[6] * rot_y_mat[9]) + (rot_x_mat[10] * rot_y_mat[10]) + (rot_x_mat[14] * rot_y_mat[11]);
    temp_mat[11] = (rot_x_mat[2] * rot_y_mat[12]) + (rot_x_mat[6] * rot_y_mat[13]) + (rot_x_mat[10] * rot_y_mat[14]) + (rot_x_mat[14] * rot_y_mat[15]);
    temp_mat[12] = (rot_x_mat[3] * rot_y_mat[0]) + (rot_x_mat[7] * rot_y_mat[1]) + (rot_x_mat[11] * rot_y_mat[2]) + (rot_x_mat[15] * rot_y_mat[3]);
    temp_mat[13] = (rot_x_mat[3] * rot_y_mat[4]) + (rot_x_mat[7] * rot_y_mat[5]) + (rot_x_mat[11] * rot_y_mat[6]) + (rot_x_mat[15] * rot_y_mat[7]);
    temp_mat[14] = (rot_x_mat[3] * rot_y_mat[8]) + (rot_x_mat[7] * rot_y_mat[9]) + (rot_x_mat[11] * rot_y_mat[10]) + (rot_x_mat[15] * rot_y_mat[11]);
    temp_mat[15] = (rot_x_mat[3] * rot_y_mat[12]) + (rot_x_mat[7] * rot_y_mat[13]) + (rot_x_mat[11] * rot_y_mat[14]) + (rot_x_mat[15] * rot_y_mat[15]);
    
    rot[0] = (temp_mat[0] * rot_z_mat[0]) + (temp_mat[4] * rot_z_mat[1]) + (temp_mat[8] * rot_z_mat[2]) + (temp_mat[12] * rot_z_mat[3]);
    rot[1] = (temp_mat[0] * rot_z_mat[4]) + (temp_mat[4] * rot_z_mat[5]) + (temp_mat[8] * rot_z_mat[6]) + (temp_mat[12] * rot_z_mat[7]);
    rot[2] = (temp_mat[0] * rot_z_mat[8]) + (temp_mat[4] * rot_z_mat[9]) + (temp_mat[8] * rot_z_mat[10]) + (temp_mat[12] * rot_z_mat[11]);
    rot[3] = (temp_mat[0] * rot_z_mat[12]) + (temp_mat[4] * rot_z_mat[13]) + (temp_mat[8] * rot_z_mat[14]) + (temp_mat[12] * rot_z_mat[15]);
    rot[4] = (temp_mat[1] * rot_z_mat[0]) + (temp_mat[5] * rot_z_mat[1]) + (temp_mat[9] * rot_z_mat[2]) + (temp_mat[13] * rot_z_mat[3]);
    rot[5] = (temp_mat[1] * rot_z_mat[4]) + (temp_mat[5] * rot_z_mat[5]) + (temp_mat[9] * rot_z_mat[6]) + (temp_mat[13] * rot_z_mat[7]);
    rot[6] = (temp_mat[1] * rot_z_mat[8]) + (temp_mat[5] * rot_z_mat[9]) + (temp_mat[9] * rot_z_mat[10]) + (temp_mat[13] * rot_z_mat[11]);
    rot[7] = (temp_mat[1] * rot_z_mat[12]) + (temp_mat[5] * rot_z_mat[13]) + (temp_mat[9] * rot_z_mat[14]) + (temp_mat[13] * rot_z_mat[15]);
    rot[8] = (temp_mat[2] * rot_z_mat[0]) + (temp_mat[6] * rot_z_mat[1]) + (temp_mat[10] * rot_z_mat[2]) + (temp_mat[14] * rot_z_mat[3]);
    rot[9] = (temp_mat[2] * rot_z_mat[4]) + (temp_mat[6] * rot_z_mat[5]) + (temp_mat[10] * rot_z_mat[6]) + (temp_mat[14] * rot_z_mat[7]);
    rot[10] = (temp_mat[2] * rot_z_mat[8]) + (temp_mat[6] * rot_z_mat[9]) + (temp_mat[10] * rot_z_mat[10]) + (temp_mat[14] * rot_z_mat[11]);
    rot[11] = (temp_mat[2] * rot_z_mat[12]) + (temp_mat[6] * rot_z_mat[13]) + (temp_mat[10] * rot_z_mat[14]) + (temp_mat[14] * rot_z_mat[15]);
    rot[12] = (temp_mat[3] * rot_z_mat[0]) + (temp_mat[7] * rot_z_mat[1]) + (temp_mat[11] * rot_z_mat[2]) + (temp_mat[15] * rot_z_mat[3]);
    rot[13] = (temp_mat[3] * rot_z_mat[4]) + (temp_mat[7] * rot_z_mat[5]) + (temp_mat[11] * rot_z_mat[6]) + (temp_mat[15] * rot_z_mat[7]);
    rot[14] = (temp_mat[3] * rot_z_mat[8]) + (temp_mat[7] * rot_z_mat[9]) + (temp_mat[11] * rot_z_mat[10]) + (temp_mat[15] * rot_z_mat[11]);
    rot[15] = (temp_mat[3] * rot_z_mat[12]) + (temp_mat[7] * rot_z_mat[13]) + (temp_mat[11] * rot_z_mat[14]) + (temp_mat[15] * rot_z_mat[15]);
}

bool InvertTheMatrix()
{
    GLfloat det;  int i;
    
    inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
    inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
    inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
    inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
    inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
    inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
    inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
    inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
    inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
    inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
    inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
    inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
    inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
    inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
    inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
    inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
    
    det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
    
    if (det == 0)
        return false;
    
    det = 1.0 / det;
    
    for (i = 0; i < 16; i++)
        inv_mat[i] = inv[i] * det;
    
    return true;
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(1024, 768);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Space Trip");
    
    init();
    
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutTimerFunc(interval, update, 0);
    
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    
    return 0;
}

[QUOTE=Carmine;1280900]It sounds like you’re making this harder than it should be.
If you post a complete, simplified, version of your code, I’ll look at it and make some suggestions.
Make it as simple as possible, removing all routines, objects, that aren’t pertinent to the issue.
I have to be able to compile, link, and run it.
Include a statement saying what the code does wrong and/or what you want it to do.
Also, you’ll get more responses if you put your code in [ code] and [ /code] tags (without the spaces).[/QUOTE]


//
//  SpaceTrip.cpp
//

#include <OpenGL/gl.h>   // For Mac OS X.
#include <GLUT/glut.h>   // For Mac OS X.
//
// For Mac OS X, compile using:  g++ -o SpaceTrip SpaceTrip.cpp -framework OpenGL - framework GLUT
//
//
// For Linux:  #include <GL/gl.h>
// "           #include <GL/glu.h>
// "           #include <GL/glut.h>
//
// Compile using:  g++ -o SpaceTrip SpaceTrip.cpp -lglut -lGLU -lGL

#include <cmath>
#include <cstring>
#include <cstdlib>
#include <sstream>
#include <iostream>
using namespace std;

// update rate (60 fps)
int interval = 1000 / 60;

GLfloat DegreesToRadians(GLfloat angle_in_degrees);

void MultiplyTheMatrices();

bool InvertTheMatrix();

GLfloat move_dist_x = 0.0;  GLfloat move_dist_y = 0.0;  GLfloat move_dist_z = 0.0;

// spaceship (user's view) coordinates
GLfloat spaceship_x = 0.0;  GLfloat spaceship_y = 0.0;  GLfloat spaceship_z = 0.0;

// rotation of user's view
GLfloat yaw_angle = 0.0;  GLfloat pitch_angle = 0.0;  GLfloat roll_angle = 0.0;

GLfloat user_speed = 0.0;

GLfloat cam_right_vector_x = 0.0;  GLfloat cam_right_vector_y = 0.0;  GLfloat cam_right_vector_z = 0.0;
GLfloat cam_up_vector_x = 0.0;  GLfloat cam_up_vector_y = 0.0;  GLfloat cam_up_vector_z = 0.0;
GLfloat cam_look_vector_x = 0.0;  GLfloat cam_look_vector_y = 0.0;  GLfloat cam_look_vector_z = 0.0;

GLfloat rot_x_mat[16];  // rotation x matrix with values set in MultiplyTheMatrices() function
GLfloat rot_y_mat[16];  // rotation y matrix with values set in MultiplyTheMatrices() function
GLfloat rot_z_mat[16];  // rotation z matrix with values set in MultiplyTheMatrices() function
GLfloat temp_mat[16];   // first step in rotation matrix calculation by multiplying (rot_x_mat * rot_y_mat)
GLfloat rot[16];        // final rotation matrix created by multiplying (temp_mat * rot_z_mat)

GLfloat view_mat[16];   // array used to grab matrix values from GL_MODELVIEW_MATRIX after rotations for the world view are performed but before the translation of the world view is performed

GLfloat m[16];   // array used to grab matrix values from GL_MODELVIEW_MATRIX after both the rotations for the world view and the translation of the world view are performed

GLfloat inv[16];  // array used by the InvertTheMatrix() function

GLfloat inv_mat[16];  // array used to store the inverted form of the world view matrix stored in m[16] so that the spaceship/wiresphere can be positioned at the world camera coordinate facing in the same direction as the camera view

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_FLAT);
}

void display()
{
    // clear (has to be done at the beginning)
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glColor3ub(255, 255, 255);

    // save the matrix before updating the position of the entire universe
    glPushMatrix();
    
    MultiplyTheMatrices();  // take my pitch, yaw, and roll angles and create a rotation matrix:  rot
    
    glMultMatrixf(rot);  // take my rotation matrix and multiply it against the MODELVIEW matrix
    
    // copy the current values located in the MODELVIEW_MATRIX which includes the rotations
    glGetFloatv(GL_MODELVIEW_MATRIX, view_mat);
    
    cam_right_vector_x = view_mat[0];
    cam_right_vector_y = view_mat[4];
    cam_right_vector_z = view_mat[8];
    cam_up_vector_x = view_mat[1];
    cam_up_vector_y = view_mat[5];
    cam_up_vector_z = view_mat[9];
    cam_look_vector_x = view_mat[2];
    cam_look_vector_y = view_mat[6];
    cam_look_vector_z = view_mat[10];
    
    // view coordinate update
    move_dist_x = user_speed * (-cam_look_vector_x);
    move_dist_y = user_speed * (-cam_look_vector_y);
    move_dist_z = user_speed * (-cam_look_vector_z);
    
    spaceship_x = spaceship_x + move_dist_x;
    spaceship_y = spaceship_y + move_dist_y;
    spaceship_z = spaceship_z + move_dist_z;
    
    glTranslatef(-spaceship_x, -spaceship_y, -spaceship_z);  // place the view at the coordinates I want by "moving the universe"
    
    glGetFloatv(GL_MODELVIEW_MATRIX, m);
    
    InvertTheMatrix();  // make an inverted matrix of the current MODELVIEW_MATRIX and store it in inv_mat.

    // place the spaceship that I'm sitting in at the exact center of my view
    glPushMatrix();
    glLoadMatrixf(inv_mat);  // apply the inverted matrix in order to position my spaceship/sphere at the correct view position and rotation as the world view - NOT WORKING PROPERLY, NEED HELP WITH THIS.
    glColor3ub(220, 220, 220);
    glutWireSphere(20.0f, 20, 20);
    glPopMatrix();
    
    // place some extra wire spheres around so that flying through space doesn't look completely empty
    glPushMatrix();
    glTranslatef(0.0, 0.0, -7500.0);
    glColor3ub(80, 150, 255);
    glutWireSphere(500.0f, 20, 20);  // big blue sphere positioned starting 7500 units in front of you
    glPopMatrix();
    
    glPushMatrix();
    glTranslatef(0.0, 0.0, 300.0);
    glColor3ub(255, 0, 0);
    glutWireSphere(200.0f, 20, 20);  // small red sphere positioned starting 300 units behind you
    glPopMatrix();
    
    glPopMatrix();

    glutSwapBuffers();
}

void keyboard(unsigned char key, int x, int y)
{
    switch (key)
    {
        case 'l':
            // increase speed
            if(user_speed < 20.0)
                user_speed = user_speed + 1.0;
            break;
            
        case 'k':
            // decrease speed
            if(user_speed >= 1.0)
                user_speed = user_speed - 1.0;
            break;
            
        case '2':
            // pitch up
            pitch_angle = pitch_angle - 4.5;
            if (pitch_angle <= -360.0)
                pitch_angle = pitch_angle + 360.0;
            break;
            
        case '8':
            // pitch down
            pitch_angle = pitch_angle + 4.5;
            if (pitch_angle >= 360.0)
                pitch_angle = pitch_angle - 360.0;
            break;
            
        case '4':
            // yaw to the left
            yaw_angle = yaw_angle - 4.5;
            if (yaw_angle <= -360.0)
                yaw_angle = yaw_angle + 360.0;
            break;
            
        case '6':
            // yaw to the right
            yaw_angle = yaw_angle + 4.5;
            if (yaw_angle >= 360.0)
                yaw_angle = yaw_angle - 360.0;
            break;
            
        case '1':
            // pitch up and yaw to the left
            pitch_angle = pitch_angle - 4.5;
            if (pitch_angle <= -360.0)
                pitch_angle = pitch_angle + 360.0;
            yaw_angle = yaw_angle - 4.5;
            if (yaw_angle <= -360.0)
                yaw_angle = yaw_angle + 360.0;
            break;
            
        case '3':
            // pitch up and yaw to the right
            pitch_angle = pitch_angle - 4.5;
            if (pitch_angle <= -360.0)
                pitch_angle = pitch_angle + 360.0;
            yaw_angle = yaw_angle + 4.5;
            if (yaw_angle >= 360.0)
                yaw_angle = yaw_angle - 360.0;
            break;

        case '7':
            // pitch down and yaw to the left
            pitch_angle = pitch_angle + 4.5;
            if (pitch_angle >= 360.0)
                pitch_angle = pitch_angle - 360.0;
            yaw_angle = yaw_angle - 4.5;
            if (yaw_angle <= -360.0)
                yaw_angle = yaw_angle + 360.0;
            break;
            
        case '9':
            // pitch down and yaw to the right
            pitch_angle = pitch_angle + 4.5;
            if (pitch_angle >= 360.0)
                pitch_angle = pitch_angle - 360.0;
            yaw_angle = yaw_angle + 4.5;
            if (yaw_angle >= 360.0)
                yaw_angle = yaw_angle - 360.0;
            break;
            
        case ',':
            // roll to the left
            roll_angle = roll_angle - 4.5;
            if (roll_angle <= -360.0)
                roll_angle = roll_angle + 360.0;
            break;
            
        case '.':
            // roll to the right
            roll_angle = roll_angle + 4.5;
            if (roll_angle >= 360.0)
                roll_angle = roll_angle - 360.0;
            break;
            
        case 'b':
            exit(0);
            break;
            
        default:
            break;
    }
}

void update(int value)
{
    glutTimerFunc(interval, update, 0);
    
    glutPostRedisplay();
}

void reshape(int width, int height)
{
    glViewport(0, 0, (GLsizei) width, (GLsizei) height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(60.0f, (GLfloat) width/(GLfloat) height, 1.0f, 1000000.0f);
    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity();
}

GLfloat DegreesToRadians(GLfloat angle_in_degrees)
{
    GLfloat radians = 0.0;
    
    radians = ((angle_in_degrees * 3.141592653589793238462643383279) / 180.0);
    
    return radians;
}

void MultiplyTheMatrices()
{
    rot_x_mat[0] = 1.0;
    rot_x_mat[1] = 0.0;
    rot_x_mat[2] = 0.0;
    rot_x_mat[3] = 0.0;
    rot_x_mat[4] = 0.0;
    rot_x_mat[5] = cosf(DegreesToRadians(pitch_angle));
    rot_x_mat[6] = sinf(DegreesToRadians(pitch_angle));
    rot_x_mat[7] = 0.0;
    rot_x_mat[8] = 0.0;
    rot_x_mat[9] = -(sinf(DegreesToRadians(pitch_angle)));
    rot_x_mat[10] = cosf(DegreesToRadians(pitch_angle));
    rot_x_mat[11] = 0.0;
    rot_x_mat[12] = 0.0;
    rot_x_mat[13] = 0.0;
    rot_x_mat[14] = 0.0;
    rot_x_mat[15] = 1.0;
    
    rot_y_mat[0] = cosf(DegreesToRadians(yaw_angle));
    rot_y_mat[1] = 0.0;
    rot_y_mat[2] = -(sinf(DegreesToRadians(yaw_angle)));
    rot_y_mat[3] = 0.0;
    rot_y_mat[4] = 0.0;
    rot_y_mat[5] = 1.0;
    rot_y_mat[6] = 0.0;
    rot_y_mat[7] = 0.0;
    rot_y_mat[8] = sinf(DegreesToRadians(yaw_angle));
    rot_y_mat[9] = 0.0;
    rot_y_mat[10] = cosf(DegreesToRadians(yaw_angle));
    rot_y_mat[11] = 0.0;
    rot_y_mat[12] = 0.0;
    rot_y_mat[13] = 0.0;
    rot_y_mat[14] = 0.0;
    rot_y_mat[15] = 1.0;
    
    rot_z_mat[0] = cosf(DegreesToRadians(roll_angle));
    rot_z_mat[1] = -(sinf(DegreesToRadians(roll_angle)));
    rot_z_mat[2] = 0.0;
    rot_z_mat[3] = 0.0;
    rot_z_mat[4] = sinf(DegreesToRadians(roll_angle));
    rot_z_mat[5] = cosf(DegreesToRadians(roll_angle));
    rot_z_mat[6] = 0.0;
    rot_z_mat[7] = 0.0;
    rot_z_mat[8] = 0.0;
    rot_z_mat[9] = 0.0;
    rot_z_mat[10] = 1.0;
    rot_z_mat[11] = 0.0;
    rot_z_mat[12] = 0.0;
    rot_z_mat[13] = 0.0;
    rot_z_mat[14] = 0.0;
    rot_z_mat[15] = 1.0;
    
    temp_mat[0] = (rot_x_mat[0] * rot_y_mat[0]) + (rot_x_mat[4] * rot_y_mat[1]) + (rot_x_mat[8] * rot_y_mat[2]) + (rot_x_mat[12] * rot_y_mat[3]);
    temp_mat[1] = (rot_x_mat[0] * rot_y_mat[4]) + (rot_x_mat[4] * rot_y_mat[5]) + (rot_x_mat[8] * rot_y_mat[6]) + (rot_x_mat[12] * rot_y_mat[7]);
    temp_mat[2] = (rot_x_mat[0] * rot_y_mat[8]) + (rot_x_mat[4] * rot_y_mat[9]) + (rot_x_mat[8] * rot_y_mat[10]) + (rot_x_mat[12] * rot_y_mat[11]);
    temp_mat[3] = (rot_x_mat[0] * rot_y_mat[12]) + (rot_x_mat[4] * rot_y_mat[13]) + (rot_x_mat[8] * rot_y_mat[14]) + (rot_x_mat[12] * rot_y_mat[15]);
    temp_mat[4] = (rot_x_mat[1] * rot_y_mat[0]) + (rot_x_mat[5] * rot_y_mat[1]) + (rot_x_mat[9] * rot_y_mat[2]) + (rot_x_mat[13] * rot_y_mat[3]);
    temp_mat[5] = (rot_x_mat[1] * rot_y_mat[4]) + (rot_x_mat[5] * rot_y_mat[5]) + (rot_x_mat[9] * rot_y_mat[6]) + (rot_x_mat[13] * rot_y_mat[7]);
    temp_mat[6] = (rot_x_mat[1] * rot_y_mat[8]) + (rot_x_mat[5] * rot_y_mat[9]) + (rot_x_mat[9] * rot_y_mat[10]) + (rot_x_mat[13] * rot_y_mat[11]);
    temp_mat[7] = (rot_x_mat[1] * rot_y_mat[12]) + (rot_x_mat[5] * rot_y_mat[13]) + (rot_x_mat[9] * rot_y_mat[14]) + (rot_x_mat[13] * rot_y_mat[15]);
    temp_mat[8] = (rot_x_mat[2] * rot_y_mat[0]) + (rot_x_mat[6] * rot_y_mat[1]) + (rot_x_mat[10] * rot_y_mat[2]) + (rot_x_mat[14] * rot_y_mat[3]);
    temp_mat[9] = (rot_x_mat[2] * rot_y_mat[4]) + (rot_x_mat[6] * rot_y_mat[5]) + (rot_x_mat[10] * rot_y_mat[6]) + (rot_x_mat[14] * rot_y_mat[7]);
    temp_mat[10] = (rot_x_mat[2] * rot_y_mat[8]) + (rot_x_mat[6] * rot_y_mat[9]) + (rot_x_mat[10] * rot_y_mat[10]) + (rot_x_mat[14] * rot_y_mat[11]);
    temp_mat[11] = (rot_x_mat[2] * rot_y_mat[12]) + (rot_x_mat[6] * rot_y_mat[13]) + (rot_x_mat[10] * rot_y_mat[14]) + (rot_x_mat[14] * rot_y_mat[15]);
    temp_mat[12] = (rot_x_mat[3] * rot_y_mat[0]) + (rot_x_mat[7] * rot_y_mat[1]) + (rot_x_mat[11] * rot_y_mat[2]) + (rot_x_mat[15] * rot_y_mat[3]);
    temp_mat[13] = (rot_x_mat[3] * rot_y_mat[4]) + (rot_x_mat[7] * rot_y_mat[5]) + (rot_x_mat[11] * rot_y_mat[6]) + (rot_x_mat[15] * rot_y_mat[7]);
    temp_mat[14] = (rot_x_mat[3] * rot_y_mat[8]) + (rot_x_mat[7] * rot_y_mat[9]) + (rot_x_mat[11] * rot_y_mat[10]) + (rot_x_mat[15] * rot_y_mat[11]);
    temp_mat[15] = (rot_x_mat[3] * rot_y_mat[12]) + (rot_x_mat[7] * rot_y_mat[13]) + (rot_x_mat[11] * rot_y_mat[14]) + (rot_x_mat[15] * rot_y_mat[15]);
    
    rot[0] = (temp_mat[0] * rot_z_mat[0]) + (temp_mat[4] * rot_z_mat[1]) + (temp_mat[8] * rot_z_mat[2]) + (temp_mat[12] * rot_z_mat[3]);
    rot[1] = (temp_mat[0] * rot_z_mat[4]) + (temp_mat[4] * rot_z_mat[5]) + (temp_mat[8] * rot_z_mat[6]) + (temp_mat[12] * rot_z_mat[7]);
    rot[2] = (temp_mat[0] * rot_z_mat[8]) + (temp_mat[4] * rot_z_mat[9]) + (temp_mat[8] * rot_z_mat[10]) + (temp_mat[12] * rot_z_mat[11]);
    rot[3] = (temp_mat[0] * rot_z_mat[12]) + (temp_mat[4] * rot_z_mat[13]) + (temp_mat[8] * rot_z_mat[14]) + (temp_mat[12] * rot_z_mat[15]);
    rot[4] = (temp_mat[1] * rot_z_mat[0]) + (temp_mat[5] * rot_z_mat[1]) + (temp_mat[9] * rot_z_mat[2]) + (temp_mat[13] * rot_z_mat[3]);
    rot[5] = (temp_mat[1] * rot_z_mat[4]) + (temp_mat[5] * rot_z_mat[5]) + (temp_mat[9] * rot_z_mat[6]) + (temp_mat[13] * rot_z_mat[7]);
    rot[6] = (temp_mat[1] * rot_z_mat[8]) + (temp_mat[5] * rot_z_mat[9]) + (temp_mat[9] * rot_z_mat[10]) + (temp_mat[13] * rot_z_mat[11]);
    rot[7] = (temp_mat[1] * rot_z_mat[12]) + (temp_mat[5] * rot_z_mat[13]) + (temp_mat[9] * rot_z_mat[14]) + (temp_mat[13] * rot_z_mat[15]);
    rot[8] = (temp_mat[2] * rot_z_mat[0]) + (temp_mat[6] * rot_z_mat[1]) + (temp_mat[10] * rot_z_mat[2]) + (temp_mat[14] * rot_z_mat[3]);
    rot[9] = (temp_mat[2] * rot_z_mat[4]) + (temp_mat[6] * rot_z_mat[5]) + (temp_mat[10] * rot_z_mat[6]) + (temp_mat[14] * rot_z_mat[7]);
    rot[10] = (temp_mat[2] * rot_z_mat[8]) + (temp_mat[6] * rot_z_mat[9]) + (temp_mat[10] * rot_z_mat[10]) + (temp_mat[14] * rot_z_mat[11]);
    rot[11] = (temp_mat[2] * rot_z_mat[12]) + (temp_mat[6] * rot_z_mat[13]) + (temp_mat[10] * rot_z_mat[14]) + (temp_mat[14] * rot_z_mat[15]);
    rot[12] = (temp_mat[3] * rot_z_mat[0]) + (temp_mat[7] * rot_z_mat[1]) + (temp_mat[11] * rot_z_mat[2]) + (temp_mat[15] * rot_z_mat[3]);
    rot[13] = (temp_mat[3] * rot_z_mat[4]) + (temp_mat[7] * rot_z_mat[5]) + (temp_mat[11] * rot_z_mat[6]) + (temp_mat[15] * rot_z_mat[7]);
    rot[14] = (temp_mat[3] * rot_z_mat[8]) + (temp_mat[7] * rot_z_mat[9]) + (temp_mat[11] * rot_z_mat[10]) + (temp_mat[15] * rot_z_mat[11]);
    rot[15] = (temp_mat[3] * rot_z_mat[12]) + (temp_mat[7] * rot_z_mat[13]) + (temp_mat[11] * rot_z_mat[14]) + (temp_mat[15] * rot_z_mat[15]);
}

bool InvertTheMatrix()
{
    GLfloat det;  int i;
    
    inv[0] = m[5] * m[10] * m[15] - m[5] * m[11] * m[14] - m[9] * m[6] * m[15] + m[9] * m[7] * m[14] + m[13] * m[6] * m[11] - m[13] * m[7] * m[10];
    inv[4] = -m[4] * m[10] * m[15] + m[4] * m[11] * m[14] + m[8] * m[6] * m[15] - m[8] * m[7] * m[14] - m[12] * m[6] * m[11] + m[12] * m[7] * m[10];
    inv[8] = m[4] * m[9] * m[15] - m[4] * m[11] * m[13] - m[8] * m[5] * m[15] + m[8] * m[7] * m[13] + m[12] * m[5] * m[11] - m[12] * m[7] * m[9];
    inv[12] = -m[4] * m[9] * m[14] + m[4] * m[10] * m[13] + m[8] * m[5] * m[14] - m[8] * m[6] * m[13] - m[12] * m[5] * m[10] + m[12] * m[6] * m[9];
    inv[1] = -m[1] * m[10] * m[15] + m[1] * m[11] * m[14] + m[9] * m[2] * m[15] - m[9] * m[3] * m[14] - m[13] * m[2] * m[11] + m[13] * m[3] * m[10];
    inv[5] = m[0] * m[10] * m[15] - m[0] * m[11] * m[14] - m[8] * m[2] * m[15] + m[8] * m[3] * m[14] + m[12] * m[2] * m[11] - m[12] * m[3] * m[10];
    inv[9] = -m[0] * m[9] * m[15] + m[0] * m[11] * m[13] + m[8] * m[1] * m[15] - m[8] * m[3] * m[13] - m[12] * m[1] * m[11] + m[12] * m[3] * m[9];
    inv[13] = m[0] * m[9] * m[14] - m[0] * m[10] * m[13] - m[8] * m[1] * m[14] + m[8] * m[2] * m[13] + m[12] * m[1] * m[10] - m[12] * m[2] * m[9];
    inv[2] = m[1] * m[6] * m[15] - m[1] * m[7] * m[14] - m[5] * m[2] * m[15] + m[5] * m[3] * m[14] + m[13] * m[2] * m[7] - m[13] * m[3] * m[6];
    inv[6] = -m[0] * m[6] * m[15] + m[0] * m[7] * m[14] + m[4] * m[2] * m[15] - m[4] * m[3] * m[14] - m[12] * m[2] * m[7] + m[12] * m[3] * m[6];
    inv[10] = m[0] * m[5] * m[15] - m[0] * m[7] * m[13] - m[4] * m[1] * m[15] + m[4] * m[3] * m[13] + m[12] * m[1] * m[7] - m[12] * m[3] * m[5];
    inv[14] = -m[0] * m[5] * m[14] + m[0] * m[6] * m[13] + m[4] * m[1] * m[14] - m[4] * m[2] * m[13] - m[12] * m[1] * m[6] + m[12] * m[2] * m[5];
    inv[3] = -m[1] * m[6] * m[11] + m[1] * m[7] * m[10] + m[5] * m[2] * m[11] - m[5] * m[3] * m[10] - m[9] * m[2] * m[7] + m[9] * m[3] * m[6];
    inv[7] = m[0] * m[6] * m[11] - m[0] * m[7] * m[10] - m[4] * m[2] * m[11] + m[4] * m[3] * m[10] + m[8] * m[2] * m[7] - m[8] * m[3] * m[6];
    inv[11] = -m[0] * m[5] * m[11] + m[0] * m[7] * m[9] + m[4] * m[1] * m[11] - m[4] * m[3] * m[9] - m[8] * m[1] * m[7] + m[8] * m[3] * m[5];
    inv[15] = m[0] * m[5] * m[10] - m[0] * m[6] * m[9] - m[4] * m[1] * m[10] + m[4] * m[2] * m[9] + m[8] * m[1] * m[6] - m[8] * m[2] * m[5];
    
    det = m[0] * inv[0] + m[1] * inv[4] + m[2] * inv[8] + m[3] * inv[12];
    
    if (det == 0)
        return false;
    
    det = 1.0 / det;
    
    for (i = 0; i < 16; i++)
        inv_mat[i] = inv[i] * det;
    
    return true;
}

int main(int argc, char** argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
    glutInitWindowSize(1024, 768);
    glutInitWindowPosition(0, 0);
    glutCreateWindow("Space Trip");
    
    init();
    
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutTimerFunc(interval, update, 0);
    
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    
    return 0;
}

Multiply by a translation matrix:


[1 0 0 x]
[0 1 0 y]
[0 0 1 z]
[0 0 0 1]

Or you could use GLM for the matrix stuff.

There are three common ways to implement a generalised inverse: Cramer’s rule, Gaussian elimination, or blockwise inversion. Cramer’s rule is probably the simplest; it’s not particularly efficient, but that doesn’t really matter for a 4x4 matrix.

There are also some simpler techniques for inverting matrices having a specific form.

If a matrix is constructed solely from rotations and translations, the upper-left 3x3 submatrix (the rotation component) will be orthonormal (all three axes are mutually perpendicular and of unit length), and can be inverted simply by transposing it. The translation component is then transformed by the transposed 3x3 submatrix and negated (i.e. -RT.T where R is the 3x3 rotation submatrix and T is the original translation).

Also, if a matrix is constructed by multiplying together matrices which individually have simple inverses, you can use the identity
(A.B)-1 = B-1.A-1
I.e. you invert the individual matrices and multiply them in the reverse order (this holds for any number of matrices). This is how the inverse of the camera matrix is typically constructed using OpenGL operations; the inverse of glTranslate(x,y,z) is glTranslate(-x,-y,-z) and the inverse of glRotate(a,x,y,z) is glRotate(-a,x,y,z).

In any case, you can check that whichever inverse function you use is correct by multiplying the calculated inverse by the original matrix (the order doesn’t matter here); if the result is the identity matrix (to within the limits of floating-point accuracy), the inverse is correct.

It depends. You want to start by generating the inverse of the transformation for the object to which the camera is attached. You can do that by applying the inverse rotation followed by the inverse translation, or by applying the (non-inverted) translation followed by the rotation then inverting the result.

[QUOTE=GClements;1280903]Multiply by a translation matrix:


[1 0 0 x]
[0 1 0 y]
[0 0 1 z]
[0 0 0 1]

[/QUOTE]

Thank you. I’m sorry for the late reply. I was experimenting like crazy on all this stuff. :slight_smile:

I.e. you invert the individual matrices and multiply them in the reverse order (this holds for any number of matrices). This is how the inverse of the camera matrix is typically constructed using OpenGL operations; the inverse of glTranslate(x,y,z) is glTranslate(-x,-y,-z) and the inverse of glRotate(a,x,y,z) is glRotate(-a,x,y,z).

In any case, you can check that whichever inverse function you use is correct by multiplying the calculated inverse by the original matrix (the order doesn’t matter here); if the result is the identity matrix (to within the limits of floating-point accuracy), the inverse is correct.

Thank you. I was able to test it and get it working by using glRotatef(pitch_angle, 1.0, 0.0, 0.0), glRotatef(yaw_angle, 0.0, 1.0, 0.0), glRotatef(roll_angle, 0.0, 0.0, 1.0) and glTranslatef(-spaceship_x, -spaceship_y, -spaceship_z) for setting up the view and then using glTranslatef(spaceship_x, spaceship_y, spaceship_z), and the negated angles versions of the three glRotatef commands and the spaceship stays consistent with the view now. I have to go back to my original experimental rotation matrices and get more comfortable with them to make them work as well. Once I accomplish that, I’m going to move on to trying an axis-angle rotation along an arbitrary axis (next best thing to Quaternions), and then if that doesn’t suit the simulation, I will be learning about Quaternions to perfect things.

Thank you for all your help. You were more than kind to help me out. :slight_smile: