Search code examples
c++openglglutcoordinate-transformation

Isolating "Compass" from camera rotations openGL


I'm close to finishing a prototype of a solar system animation. (It's still not as efficient as it could be). Currently I have a solar system with Saturn/Uranus/Neptune plus Triton/Proteus (moons of neptune). This program allows a user to animate these planets while awsd to rotate the camera about the Axis. ( 0,1,0 / 1, 0, 0 etc)

I put in a prototype compass (literally 3 lines) to indicate the current camera orientation. Y = White. X = Red. Z = blue. However whenever the camera is rotated, the compass appears to move (although it isnt really moving), thus confusing the user. Is there a way I can lock the compass position while allowing it to mimic the user's camera rotations in place?

I understand that the compass is a set of 3D lines in 3D space and visually locking it in a 2D field doesn't make sense but I'm hoping that there's a solution regardless. Thanks!

In addition I'm also trying to animate the compass so that it mimics the camera rotations in place to help the user understand his/her current camera orientation.

Compass drawn/initialized in display()

Camera Rotations declared in Cases "wasd"

float triton = 0;
float proteus = 0;
float neptune = 0;
float saturn = 0;
float uranus = 0;
int sun = 0;
int angle = 0;
GLint buf, sbuf;

void init(void)
{
    glClearColor(0.0, 0.0, 0.0, 0.0);
    glShadeModel(GL_SMOOTH);

    // Stars 
    glNewList(1, GL_COMPILE);
    glBegin(GL_POINTS);
    glColor3f(1.0, 1.0, 1.0);
    for (int i = 0; i < 200; i++){
        for (int j = 0; j < 300; j++){
            if (((i + j) % 2) == 0){
                glVertex3f(100 * i, 100 * j, 0.0);
            }
        }
    }
    glEnd();
    glEndList();

    // Material Specs
    GLfloat mat_specular[] = { 0.8, 0.8, 0.9, 0.1 };
    GLfloat mat_shininess[] = { 128.0 };
    GLfloat lightDiffuse[] = { 1.0, 1.0, 1.0, 0.0 };
    GLfloat lmodel_ambient[] = { 0.1, 0.2, 0.7, 0.0 };

    // Light 0 Initialized.
    GLfloat light0[] = { 1.0, 1.0, 1.0, 0.1 };
    GLfloat light_position[] = { 1.0, 0.5, 0.0, -100.0 };

    // Light 0
    glLightfv(GL_LIGHT0, GL_SPECULAR, light0);
    glLightfv(GL_LIGHT0, GL_POSITION, light_position);

    // Mat Specs Implmentations.
    glMaterialfv(GL_FRONT, GL_DIFFUSE, lightDiffuse);
    glMaterialfv(GL_FRONT, GL_SPECULAR, mat_specular);
    glMaterialfv(GL_FRONT, GL_SHININESS, mat_shininess);

    //Ambient surrounding light on object.
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);

    // Enable Lighting and Depth
    glEnable(GL_LIGHTING);
    glEnable(GL_LIGHT0);
    glEnable(GL_DEPTH_TEST);
    // Enable AntiAliased Lines

    glEnable(GL_LINE_SMOOTH);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
    glLineWidth(1.5);

}
// Orbit values are arbitrary
void orbit(void)
{
    triton = triton - 0.11;
    proteus = proteus - 0.08;
    neptune = neptune - 0.04;
    saturn = saturn - 0.02;
    uranus = uranus - 0.037;
    glutPostRedisplay();
}

void backorbit(void)
{
    triton = triton + 0.11;
    proteus = proteus + 0.08;
    neptune = neptune + 0.04;
    saturn = saturn + 0.02;
    uranus = uranus + 0.037;
    glutPostRedisplay();
}

void display(void)
{
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glEnable(GL_COLOR_MATERIAL);
    glDisable(GL_LIGHTING);
    // Compass
    glPushMatrix();
        glBegin(GL_LINES);
            glColor3f(1.0, 1.0, 1.0);
            // Y axis
            glVertex3f(-15.0, 12.0, 0.0);
            glVertex3f(-15.0, 17.0, 0.0);
            glColor3f(1.0, 0.0, 0.0);
            // X axis
            glVertex3f(-12.5, 14.5, 0.0);
            glVertex3f(-17.5, 14.5, 0.0);
            glColor3f(0.0, 0.0, 1.0);
            // Z axis
            glVertex3f(-15.0, 14.5, 1.0);
            glVertex3f(-15.0, 14.5, -1.5);
        glEnd();
    glPopMatrix();

    glEnable(GL_LIGHTING);
    // Sun 
    glPushMatrix();
        glColor3f(1.0, 0.35, 0.1);
        glutSolidSphere(2.0, 100, 100);

        // Saturn
        glPushMatrix();
            glRotatef((GLfloat)saturn, 0.5, 0.6, 1.0);
            glColor3f(0.7, 0.5, 0.3);
            glTranslatef(5.0, 0.0, 0.0);
            glutSolidSphere(0.38, 100, 100);
            glRotatef(20.0, 1.0, 0.0, 0.0);
            glutSolidTorus(.11, .60, 2, 50);
        glPopMatrix();

        // Uranus
        glPushMatrix();
            glRotatef((GLfloat)uranus, 0.0, 1.0, 0.0);
            glColor3f(0.5, 0.85, 0.9);
            glTranslatef(6.5, 0.0, 0.0);
            glutSolidSphere(0.37, 100, 100);
        glPopMatrix();
        // End Uranus

        // Neptune 
        glPushMatrix();
            glRotatef((GLfloat)neptune, 0.3, 1.0, 0.8);
            glTranslatef(8.0, 0.0, 0.0);
            glColor3f(0.1, 0.1, 0.3);
            glutSolidSphere(0.3, 100, 100);

            // Neptune(Triton)
            glPushMatrix();
                glColor3f(0.85, 0.7, 0.8);
                glRotatef((GLfloat)triton, 1.0, 1.0, 1.0);
                glTranslatef(1.0, 0.0, 0.0);
                glutSolidSphere(0.07, 100, 100);
            glPopMatrix(); // Ends Triton

            // Neptune(Proteus)
            glPushMatrix();
                glColor3f(1.0, 1.0, 1.0);
                glRotatef((GLfloat)proteus, 0.0, 1.0, 0.0);
                glTranslatef(1.0, 0.0, 0.0);
                glutSolidSphere(0.04, 100, 100);
            glPopMatrix(); // Ends Proteus

        glPopMatrix(); // Ends Neptune

    glPopMatrix(); // Ends Sun

    glEnable(GL_MULTISAMPLE);

    glDisable(GL_LIGHTING);
    // Stars
    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
        glLoadIdentity();
        glPushMatrix();
            glMatrixMode(GL_PROJECTION);
            glPushMatrix();
                glLoadIdentity();
                // Arbitrary ortho
                glOrtho(0, 1000, 0, 1000, 0, 1000);
                glCallList(1);
            glPopMatrix();
            glMatrixMode(GL_MODELVIEW);
        glPopMatrix();
    glPopMatrix(); 

    glDisable(GL_COLOR_MATERIAL);
    glEnable(GL_LIGHTING);
    glFlush();
    glutSwapBuffers();
}

void reshape(int w, int h)
{
    glViewport(0, 0, (GLsizei)w, (GLsizei)h);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(120.0, (GLfloat)w / (GLfloat)h, 1.0, 20.0); 
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
    glTranslatef(0.0, 0.0, -11.0); // Find location. 

}
void keyboard(unsigned char key, int x, int y)
{
    switch (key) {
        // Triton + Proteus Orbit. 
    case 'o':
        glutIdleFunc(orbit);
        break;
    case 'p':
        glutIdleFunc(backorbit);
        break;
        // Camera Rotations. 
    case 'd':
        glRotatef(4, 1.0, 0.0, 0.0);
        glutPostRedisplay();
        break;
    case 'a':
        glRotatef(-4, 1.0, 0.0, 0.0);
        glutPostRedisplay();
        break;
    case 'w':
        angle -= 4.0;
        glRotatef(-4.0, 0.0, 1.0, 0.0);
        glutPostRedisplay();
        break;
    case 's':
        glRotatef(4.0, 0.0, 1.0, 0.0);
        glutPostRedisplay();
        break;
        // Stop Orbit.
    case 't':
        glutIdleFunc(NULL);
        break;
        // Reset to Origin (IP)
    case '1':
        angle = 0;
        glutPostRedisplay();
        break;
    case ',':
        glTranslatef(-0.3, 0.0, 0.0);
        glutPostRedisplay();
        break;
    case '.':
        glTranslatef(0.3, 0.0, 0.0);
        glutPostRedisplay();
        break;
        // Exit
    case 27:
        exit(0);
        break;
    default:
        break;
    }
}
int main(int argc, char **argv)
{
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_DEPTH | GLUT_RGB | GLUT_MULTISAMPLE);
    glutInitWindowSize(1000, 1000);
    glutInitWindowPosition(100, 100);
    glutCreateWindow("Solar System");
    init();
    glutDisplayFunc(display);
    glutReshapeFunc(reshape);
    glutKeyboardFunc(keyboard);
    glutMainLoop();
    return 0;
}

Solution

  • You have to draw the "compass " to the center of the view (0, 0, 0), then you have to apply the view matrix and finally you have to translate the "compass" to its final position.
    The current model view matrix can be get by glGetFloatv( GL_MODELVIEW_MATRIX, view_mat ):

    glPushMatrix();
    GLfloat view_mat[16];
    glGetFloatv( GL_MODELVIEW_MATRIX, view_mat );
    glLoadIdentity();
    glTranslatef( -15.0, 14.5, 0.0 );
    glMultMatrixf( view_mat );
    
        glBegin(GL_LINES);
            glColor3f(1.0, 1.0, 1.0);
            // Y axis
            glVertex3f(0.0, -2.5, 0.0);
            glVertex3f(0.0,  2.5, 0.0);
            glColor3f(1.0, 0.0, 0.0);
            // X axis
            glVertex3f(-2.5, 0.0, 0.0);
            glVertex3f(2.5, 0.0, 0.0);
            glColor3f(0.0, 0.0, 1.0);
            // Z axis
            glVertex3f(-0.0, 0.0, 1.0);
            glVertex3f(-0.0, 0.0, -1.5);
        glEnd();
    
    glPopMatrix();
    

    But note, drawing by glBegin/glEnd sequences and using the fixed function pipeline matrix stack is deprecated since several years. Read about Fixed Function Pipeline and see Vertex Specification and Shader for a state of the art way of rendering.