Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / desktop / Win32

OpenGL 3D Navigation with Tao and C#

4.03/5 (12 votes)
19 Feb 2008CPOL2 min read 2   5.2K  
OpenGL 3D navigation with Tao and C#, using glRotatef, glTranslatef, and gluLookAt.

Image 1

Introduction

I think one of the most important steps for beginners is to learn how to create a 3D space and navigate in this space. Especially, how to navigate in 3D space is important. It can be very confusing for beginners. This program shows how to navigate in 3D space.

Background

I have the same project with a C++ Windows console application. If you are interested, check my other articles.

Using the code

The base code is from the red book "OpenGL Programming Guide (Third Edition)". This is a beginner level program to show how to navigate in 3D space. It uses glRotatef(), glTranslatef(), and gluLookAt() functions. I divided the 3D space with lines. The intersection of the x, y, z axes is the location (0,0,0). The doted parts of the lines are the negative sides of the axes. The z axis is not viewable, because we look at the space from the (0,0,15) coordinates. The above picture was rotated so the z axis can be seen.

  • Green for x axis
  • Red for y axis
  • Blue for z axis
  • x,X - rotates on x axis; uses the glRotatef() function
  • y,Y - rotates on y axis; uses the glRotatef() function
  • z,Z - rotates on z axis; uses the glRotatef() function
  • left_key - translates to left (x axis); uses the glTranslatef() function
  • right_key - translates to right (x axis); uses the glTranslatef() function
  • up_key - translates up (y axis); uses the glTranslatef() function
  • down_key - translates down (y axis); uses the glTranslatef() function
  • page_up - translates on z axis (zoom in); uses the glTranslatef() function
  • page_down - translates on z axis (zoom out); uses the glTranslatef() function
  • j,J translates on x axis; uses the glLookAt() function
  • k,K translates on y axis; uses the glLookAt() function
  • l,L translates on z axis; uses the glLookAt() function
  • b,B rotates (+/-)90 degrees on x axis
  • n,N rotates (+/-)90 degrees on y axis
  • m,M rotates (+/-)90 degrees on z axis
  • o,O brings everything to default (starting coordinates)

Notice that glTranslatef and gluLookAt() behaves the same. However, they are not exactly the same. You can figure this out by using this program.

C#
using System;
using System.Collections.Generic;
using System.Text;
using Tao.OpenGl;
using Tao.FreeGlut;

namespace OpenGLNavigationWithTaoCSharp
{

    sealed class Program
    {
        static float X = 0.0f;       // Translate screen to x direction (left or right)
        static float Y = 0.0f;       // Translate screen to y direction (up or down)
        static float Z = 0.0f;       // Translate screen to z direction (zoom in or out)
        static float rotX = 0.0f;    // Rotate screen on x axis 
        static float rotY = 0.0f;    // Rotate screen on y axis
        static float rotZ = 0.0f;    // Rotate screen on z axis

        static float rotLx = 0.0f;   // Translate screen by using  the glulookAt
                                     // function (left or right)
        static float rotLy = 0.0f;   // Translate screen by using  the glulookAt
                                     // function (up or down)
        static float rotLz = 0.0f;   // Translate screen by using  the glulookAt
                                     // function (zoom in or out)

        // Initiliaze the OpenGL window
       static void init()
        {           
            Gl.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);          // Clear the color 
            Gl.glShadeModel (Gl.GL_FLAT);                     // Set the shading model
                                                              // to GL_FLAT
            Gl.glEnable (Gl.GL_LINE_SMOOTH);
            Gl.glHint(Gl.GL_LINE_SMOOTH_HINT, Gl.GL_NICEST);  // Set Line Antialiasing
        }

        // Draw the lines (x,y,z)
        static void display()
        {    
            Gl.glClear(Gl.GL_COLOR_BUFFER_BIT);             // Clear the Color Buffer 
            Gl.glPushMatrix();                              // It is important to push
                                                            // the Matrix before calling
                                                            // glRotatef and glTranslatef
            Gl.glRotatef(rotX, 1.0f, 0.0f, 0.0f);           // Rotate on x
            Gl.glRotatef(rotY, 0.0f, 1.0f, 0.0f);           // Rotate on y
            Gl.glRotatef(rotZ, 0.0f, 0.0f, 1.0f);           // Rotate on z
            Gl.glTranslatef(X, Y, Z);                       // Translates the screen
                                                            // left or right, up or down
                                                            // or zoom in zoom out

            // Draw the positive side of the lines x,y,z
            Gl.glBegin(Gl.GL_LINES);
                Gl.glColor3f(0.0f, 1.0f, 0.0f);                // Green for x axis
                Gl.glVertex3f(0f, 0f, 0f);
                Gl.glVertex3f(10f, 0f, 0f);
                Gl.glColor3f(1.0f, 0.0f, 0.0f);                // Red for y axis
                Gl.glVertex3f(0f, 0f, 0f);
                Gl.glVertex3f(0f, 10f, 0f);
                Gl.glColor3f(0.0f, 0.0f, 1.0f);                // Blue for z axis
                Gl.glVertex3f(0f, 0f, 0f);
                Gl.glVertex3f(0f, 0f, 10f);
            Gl.glEnd();
            
            // Dotted lines for the negative sides of x,y,z
            Gl.glEnable(Gl.GL_LINE_STIPPLE);            // Enable line stipple to
                                                        // use a dotted pattern for
                                                        // the lines
            Gl.glLineStipple(1, 0x0101);                // Dotted stipple pattern for
                                                        // the lines
            Gl.glBegin(Gl.GL_LINES);
                Gl.glColor3f(0.0f, 1.0f, 0.0f);         // Green for x axis
                Gl.glVertex3f(-10f, 0f, 0f);
                Gl.glVertex3f(0f, 0f, 0f);
                Gl.glColor3f(1.0f, 0.0f, 0.0f);         // Red for y axis
                Gl.glVertex3f(0f, 0f, 0f);
                Gl.glVertex3f(0f, -10f, 0f);
                Gl.glColor3f(0.0f, 0.0f, 1.0f);         // Blue for z axis
                Gl.glVertex3f(0f, 0f, 0f);
                Gl.glVertex3f(0f, 0f, -10f);
            Gl.glEnd();

            Gl.glDisable(Gl.GL_LINE_STIPPLE);           // Disable the line stipple
            Gl.glPopMatrix();                           // Don't forget to pop the Matrix
            Glut.glutSwapBuffers();
        }

        // This function is called whenever the window size is changed
       static void reshape (int w, int h)
        {
     
            Gl.glViewport (0, 0, w,  h);                // Set the viewport
            Gl.glMatrixMode (Gl.GL_PROJECTION);         // Set the Matrix mode
            Gl.glLoadIdentity ();                                            
            Glu.gluPerspective(75f, (float) w /(float)h , 0.10f, 100.0f);
            Gl.glMatrixMode(Gl.GL_MODELVIEW);
            Gl.glLoadIdentity(); 
            Glu.gluLookAt (rotLx, rotLy, 15.0f + rotLz, 0.0f, 0.0f, 0.0f, 0.0f,
                1.0f, 0.0f); 
        }

        // This function is used for the navigation keys
      public static void keyboard(byte key, int x, int y)
        {
            switch (key) {    
            
                // x,X,y,Y,z,Z uses the glRotatef() function
                case 120:    // x           // Rotates screen on x axis 
                    rotX -= 0.5f;
                break;
                case 88:    // X            // Opposite way 
                    rotX += 0.5f;
                break;
                case 121:    // y           // Rotates screen on y axis
                    rotY -= 0.5f;
                break;
                case 89:    // Y            // Opposite way
                    rotY += 0.5f;    
                break;    
                case 122:    // z           // Rotates screen on z axis
                    rotZ -= 0.5f;
                break;
                case 90:    // Z            // Opposite way
                    rotZ += 0.5f;
                break;

                // j,J,k,K,l,L uses the gluLookAt function for navigation
                case 106:   // j
                    rotLx -= 0.2f;  
                    Gl.glMatrixMode(Gl.GL_MODELVIEW);
                    Gl.glLoadIdentity();
                    Glu.gluLookAt (rotLx, rotLy, 15.0 + rotLz, 0.0, 0.0, 0.0, 0.0, 1.0,
                        0.0);
                break;
                case 74:    // J
                    rotLx += 0.2f;
                    Gl.glMatrixMode(Gl.GL_MODELVIEW);
                    Gl.glLoadIdentity();
                    Glu.gluLookAt (rotLx, rotLy, 15.0 + rotLz, 0.0, 0.0, 0.0, 0.0, 1.0,
                        0.0);
                break;    
                case 107:   // k
                    rotLy -= 0.2f;
                    Gl.glMatrixMode(Gl.GL_MODELVIEW);
                    Gl.glLoadIdentity();
                    Glu.gluLookAt (rotLx, rotLy, 15.0 + rotLz, 0.0, 0.0, 0.0, 0.0, 1.0,
                        0.0);
                break;
                case 75:    // K
                    rotLy += 0.2f;
                    Gl.glMatrixMode(Gl.GL_MODELVIEW);
                    Gl.glLoadIdentity();
                    Glu.gluLookAt (rotLx, rotLy, 15.0 + rotLz, 0.0, 0.0, 0.0, 0.0, 1.0,
                        0.0);
                break;
                case 108: // (l) It has a special case when the rotLZ becames less
                          // than -15 the screen is viewed from the opposite side
                          // therefore this if statement below does not allow rotLz
                          // be less than -15
                        if(rotLz + 14 >= 0)
                            rotLz -= 0.2f;
                    Gl.glMatrixMode(Gl.GL_MODELVIEW);
                    Gl.glLoadIdentity();
                    Glu.gluLookAt (rotLx, rotLy, 15.0 + rotLz, 0.0, 0.0, 0.0, 0.0, 1.0,
                        0.0);
                break;
                case 76:    // L
                    rotLz += 0.2f;
                    Gl.glMatrixMode(Gl.GL_MODELVIEW);
                    Gl.glLoadIdentity();
                    Glu.gluLookAt (rotLx, rotLy, 15.0 + rotLz, 0.0, 0.0, 0.0, 0.0,
                        1.0, 0.0);
                break;
                case 98:    // b        // Rotates on x axis by -90 degree
                    rotX -= 90.0f;
                break;
                case 66:    // B        // Rotates on y axis by 90 degree
                    rotX += 90.0f;        
                break;
                case 110:    // n       // Rotates on y axis by -90 degree
                    rotY -= 90.0f;
                break;
                case 78:    // N        // Rotates on y axis by 90 degree
                    rotY += 90.0f;
                break;
                case 109:    // m       // Rotates on z axis by -90 degree
                    rotZ -= 90.0f;            
                break;
                case 77:    // M        // Rotates on z axis by 90 degree
                    rotZ += 90.0f;
                break;
                case 111:    // o       // Default, resets the translations vies from
                                        // starting view
                case 80:    // O        
                    X = Y = 0.0f;
                    Z = 0.0f;
                    rotX = 0.0f;
                    rotY = 0.0f;
                    rotZ = 0.0f;
                    rotLx = 0.0f;
                    rotLy = 0.0f;
                    rotLz = 0.0f;
                    Gl.glMatrixMode(Gl.GL_MODELVIEW);
                    Gl.glLoadIdentity();
                   Glu.gluLookAt(rotLx, rotLy, 15.0f + rotLz, 0.0f, 0.0f, 0.0f, 0.0f,
                       1.0f, 0.0f);
                    
                break;
            }
            Glut.glutPostRedisplay();    // Redraw the scene
        }

        // called on special key pressed
       private static void specialKey(int key, int x, int y) { 
          
            // The keys below are using the gluLookAt() function for navigation
            // Check which key is pressed
            switch(key) {
                case Glut.GLUT_KEY_LEFT :  // Rotate on x axis
                    X -= 0.1f;
                  break;
              case Glut.GLUT_KEY_RIGHT:    // Rotate on x axis (opposite)
                    X +=  0.1f;
                  break;
              case Glut.GLUT_KEY_UP:       // Rotate on y axis 
                    Y += 0.1f;
                  break;
              case Glut.GLUT_KEY_DOWN:     // Rotate on y axis (opposite)
                    Y -= 0.1f;
                  break;
              case Glut.GLUT_KEY_PAGE_UP:  // Roatae on z axis
                    Z -= 0.1f;
                  break;
              case Glut.GLUT_KEY_PAGE_DOWN:// Roatae on z axis (opposite)
                    Z += 0.1f;
                  break;
            }
            Glut.glutPostRedisplay();      // Redraw the scene
        }
        static void Main(string[] args)
        {
           
            Glut.glutInit();
            // Setup display mode to double buffer and RGB color
            Glut.glutInitDisplayMode(Glut.GLUT_DOUBLE | Glut.GLUT_RGB); 
            // Set the screen size
            Glut.glutInitWindowSize(600, 600);
            Glut.glutCreateWindow("OpenGL 3D Navigation Program With Tao");
            init();
            Glut.glutReshapeFunc(reshape);
            Glut.glutDisplayFunc(display);
            // set window's key callback     
            Glut.glutKeyboardFunc(new Glut.KeyboardCallback(keyboard));
            // set window's to specialKey callback
            Glut.glutSpecialFunc(new Glut.SpecialCallback(
                                 specialKey));         
            Glut.glutMainLoop();
        }
    }
}

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)