TinyURL widget - shorten your URL's for free!

Enter a long URL to make tiny:

Friday, February 27, 2015

How to make a floating camera in OpenGL using C functions & GL_MODELVIEW matrix.

Here is a program you can compile to teach you how to make a camera float in an OpenGL scene. I won't claim I'm an expert in all things OpenGL, my first attempt didn't work so well.  But I stumbled on some code bits and cobbled them together.

If you want to use projective perspective and GL_MODELVIEW you can simply transform the camera.

Because the model view matrix has x and y along the 2D screen and negative z out from the viewpoint, two rotations have to be backward and all z-values must be negative and then it works as expected. The files have been changed to reflect this.

The GL_MODELVIEW matrix is already in the fixed coordinate frame of the camera. Simple apply a roll pitch and yaw.  I added xyz translations as well.

Oh, and I increase the Field of View (FOV) using Page UP Page DOWN to zoom in and zoom out.

Key Legend

 * Pitch - tilts camera up/down along current viewing port
 * Roll - rolls side to side like you were in a fighter jet
 * Yaw - turns "left" and "right" although technically it's rotation about an axis not turning
 
 * lz - into and out of the screen
 * lx - slide left and right frictionlessly
 * ly - hover or descend without gravity



Yaw   = Left/ Right Arrow
Pitch = Up / Down Arrow
Roll  =  Home / End Key

Z motion =  7 / 1 keys
Y motion = 8 / 2 keys
X motion = 4 / 6 keys

This is Lighthouse3D's original snow man example modified to use free camera rotations. Except his example forces the camera to the same plane.  You can find it here:

http://www.lighthouse3d.com/tutorials/glut-tutorial/keyboard-example-moving-around-the-world/



Here is a link to my C file:  https://www.dropbox.com/s/k7itn9qc45qvkez/opengl-floatingcamera.c?dl=0


/***\file opengl-floatingcamera.c   *********************************************************
                          
 H.File   $Header:  $
    
 Date Started: -2015

 Date:     $Date:  $
 *
 Author:  $Name:   $

 Purpose: Example OpenGL program showing how floating camera in MODELVIEW mode works.
 * It makes a floating camera using the C library and uses keys to change the relative
 * local frame motion of the camera.

 Version:  $Id: opengl-floatingcamera.c,v 1.2 2007/08/24 14:27:29 cvsuser Exp $

 Revision: $Revision:  $
 *
 *
 Log:   $Log:   $
 *
 * \brief
 * This file modifies the original file to demonstrate how to make a floating camera.
***************************************************************************/
// global library includes
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <GL/gl.h>
#include <GL/freeglut.h>
#include <GL/freeglut_ext.h>
#include <GL/freeglut_std.h>



// angle of rotation for the camera direction
float angle=0.0;
// actual vector representing the camera's direction
float lx = 0.0;
float ly = 0.0;
float lz = 10.0f;

// camera angles
float yaw = 0.0f;
float pitch = 0.0f;
float roll = 0.0f;


// Field of View
float FOV = 45.0;

// window dimensions
float w_height;
float w_width;


// new camera rotation system
void NewCameraTransformation( void );


/*
   Deal with plain key strokes
*/
void processNormalKeys(unsigned char key, int x, int y)
{
   switch (key)
   {
    case 27: /* ESC */
    case 'Q':
    case 'q': exit(0); break;
    case 's':
    case 'S': ; break;
    case 'b':
    case 'B': ; break;
    // translation keys  - pure location displacements
    case '8': ly -= 1; break;
    case '2': ly += 1; break;  
    case '4': lx += 1; break;   
    case '6': lx -= 1; break;
    case '7': lz += 1; break;   
    case '1': lz -= 1; break;   
   
   }
}


/*!  \fn ChangeWindowSize
 *
 * Updated Change size that takes into account modified window size
 *
 * */
void ChangeWindowSize(int w, int h)
{
    float ratio; // aspect ratio

    // Prevent a divide by zero, when window is too short
    // (you cant make a window of zero width)
    if(h == 0)
        h = 1;
    // get current window sizes    - not sent values
    w_width = glutGet(GLUT_WINDOW_WIDTH);
    w_height = glutGet(GLUT_WINDOW_HEIGHT);
    // compute aspect ration at scale 1.0 * width / height
    ratio = 1.0* w_width / w_height;
    // Use the Projection Matrix
    glMatrixMode(GL_PROJECTION);
    // Reset Matrix
    glLoadIdentity();
    // Set the viewport to be the entire window
    glViewport(0, 0, w_width, w_height);
    // Set the correct perspective.
    gluPerspective(FOV,ratio,1,1000);
    // Get Back to the Modelview
    glMatrixMode(GL_MODELVIEW);
}


void drawSnowMan()
{

    glColor3f(1.0f, 1.0f, 1.0f);

// Draw Body
    glTranslatef(0.0f ,0.75f, 0.0f);
    glutSolidSphere(0.75f,20,20);

// Draw Head
    glTranslatef(0.0f, 1.0f, 0.0f);
    glutSolidSphere(0.25f,20,20);

// Draw Eyes
    glPushMatrix();
    glColor3f(0.0f,0.0f,0.0f);
    glTranslatef(0.05f, 0.10f, 0.18f);
    glutSolidSphere(0.05f,10,10);
    glTranslatef(-0.1f, 0.0f, 0.0f);
    glutSolidSphere(0.05f,10,10);
    glPopMatrix();

// Draw Nose
    glColor3f(1.0f, 0.5f , 0.5f);
    glutSolidCone(0.08f,0.5f,10,2);
}

/*! \fn DrawAxes
 * \brief this function draws three multi-coloured lines on the coord origin
 * to mark the location under transformation
 *
 * */
void DrawAxes(void)
{
    // draw white for X
    glColor3f(0.99f, 0.99f, 0.99f);
    glBegin(GL_LINES);
    glVertex3f(-0.0f, 0.0f, 00.0f);
    glVertex3f(1.0f, 0.0f, 00.0f);   
    glEnd();
    // draw red for Y
    glColor3f(0.99f, 0.0f, 0.0f);
    glBegin(GL_LINES);
    glVertex3f(-0.0f, 0.0f, 00.0f);
    glVertex3f( 0.0f, 1.0f, 00.0f);   
    glEnd();
    // draw Blue for Z       
    glColor3f(0.0f, 0.0f, 1.0f);
    glBegin(GL_LINES);
    glVertex3f(-0.0f, 0.0f, 00.0f);
    glVertex3f( 0.0f, 0.0f, 1.0f);   
    glEnd();       
   
}


// new camera rotation system
/*!
 * Camera Rotation based on +- xyz translation and roll pitch yaw rotation
 *
 * The GL_MODELVIEW matrix is already set up to do the transformations for local - camera
 * transformations.  One only needs to load a new identity matrix, conduct the
 * roll pitch and yaw rotations and then the translation.
 *
 * All variables are fixed coordinates relative to the current pose.
 *
 * Pitch - tilts camera up/down along current viewing port
 * Roll - rolls side to side like you were in a fighter jet
 * Yaw - turns "left" and "right" although technically it's rotation about an axis not turning
 *
 * lz - into and out of the screen
 * lx - slide left and right frictionlessly
 * ly - hover or descend without gravity
 *
 * */
// new camera rotation system
/*!
 * Camera Rotation based on +- xyz translation and roll pitch yaw rotation
 *
 * The GL_MODELVIEW matrix is already set up to do the transformations for local - camera
 * transformations.  One only needs to load a new identity matrix, conduct the
 * roll pitch and yaw rotations and then the translation.
 *
 * Details from http://www.songho.ca/opengl/gl_transform.html#example2
 *
 * Note that there is no separate camera (view) matrix in OpenGL.
 * Therefore, in order to simulate transforming the camera or view, the scene
 * (3D objects and lights) must be transformed with the inverse of the view transformation.
 * In other words, OpenGL defines that the camera is always located at (0, 0, 0) and facing to -Z axis
 * in the eye space coordinates, and cannot be transformed.
 *
 * All variables are fixed coordinates relative to the current pose.
 *
 * Pitch - tilts camera up/down along current viewing port
 * Roll - rolls side to side like you were in a fighter jet
 * Yaw - turns "left" and "right" although technically it's rotation about an axis not turning
 *
 * lz - into and out of the screen
 * lx - slide left and right frictionlessly
 * ly - hover or descend without gravity
 *
 * */
void NewCameraTransformation( float  pitch, float  roll, float  yaw,  float  lx, float  ly, float  lz )
{
       
   
    // Position lights, and camera location
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();   
    /*
     * void glRotatef(GLfloat  angle,  GLfloat  x,  GLfloat  y,  GLfloat  z);
     * Parameters angle
     *                  Specifies the angle of rotation, in degrees.
                x, y, z
                    Specify the x, y, and z coordinates of a vector, respectively.
        
               
     *
     * */
    // Euler XYZ RPY notation
    // roll about z
    glRotatef((GLfloat)((roll)), 0.0f, 0.0f, 1.0f);
    // pitch up down around new x
    glRotatef((GLfloat)((-1*pitch)), 1.0f, 0.0f, 0.0f);
    // rotate around new y
    glRotatef((GLfloat)((-1*yaw)), 0.0f, 1.0f, 0.0f);
    // translate
    glTranslatef((GLfloat)(lx), (GLfloat)(ly),(GLfloat)((lz)));
   
}

// Optional draw ground
void DrawGround()
{
    glColor3f(0.9f, 0.9f, 0.9f);
    glBegin(GL_QUADS);
        glVertex3f(-100.0f, 0.0f, -100.0f);
        glVertex3f(-100.0f, 0.0f,  100.0f);
        glVertex3f( 100.0f, 0.0f,  100.0f);
        glVertex3f( 100.0f, 0.0f, -100.0f);
    glEnd();
}
// Optional Draw Snow Men
void DrawSnowMen()
{
    int i;
    int j;
    //Draw 36 SnowMen
    for( i = -3; i < 3; i++)
        for( j=-3; j < 3; j++)
        {
            glPushMatrix();
            glTranslatef(i*10.0,0,j * 10.0);
            drawSnowMan();
            glPopMatrix();
        }   
}

void renderScene(void)
{
    float camera_viewx;
    float camera_viewy;   
    float camera_viewz;
   
    float camera_view_normalx;
    float camera_view_normaly;
    float camera_view_normalz;
   
    // Clear Color and Depth Buffers
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   
    // new free floating camera
    NewCameraTransformation( pitch, roll, yaw, lx, ly, lz    )    ;

    // Draw ground
    //DrawGround();   
    // Draw Snow Men
    DrawSnowMen();
    // draw axes example
    DrawAxes();
   
   
    // final step
    glutSwapBuffers();
}


// modified to control angles as well as translation
void processSpecialKeys(int key, int xx, int yy)
{

    float fraction = 0.1f;

    switch (key)
    {
        /*  Control Camera Roll */
        case GLUT_KEY_HOME :
            roll += 0.1;
            break;
        case GLUT_KEY_END :
            roll -= 0.1;
            break;           
        /*  Control Camera Yaw */
        case GLUT_KEY_LEFT :
            yaw += 0.1;
            break;
        case GLUT_KEY_RIGHT :
            yaw -= 0.1;
            break;
        /* Control camera pitch  */
        case GLUT_KEY_UP :
            pitch -= 0.1;
            break;
        case GLUT_KEY_DOWN :
            pitch += 0.1;
            break;
        /* change the field of view on next resize  */
        case  GLUT_KEY_PAGE_UP:
            FOV +=5.0;
            // hard limit to 90 degrees
            if (FOV >91.0) FOV=90.0;
            ChangeWindowSize(320,320);
            break;
        /* change the field of view on next resize  */           
        case  GLUT_KEY_PAGE_DOWN:
            FOV -=5.0;
            // hard limit to 2 degree
            if (FOV < 4.0) FOV = 2.0;
            ChangeWindowSize(320,320);           
            break;                   
       
    }
}


int main(int argc, char **argv)
{

    // init GLUT and create window

    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA);
    glutInitWindowPosition(100,100);
    glutInitWindowSize(320,320);
    glutCreateWindow("Lighthouse3D - GLUT Tutorial");

    // register callbacks
    glutDisplayFunc(renderScene);
    glutReshapeFunc(ChangeWindowSize);
    glutIdleFunc(renderScene);
    glutKeyboardFunc(processNormalKeys);
    glutSpecialFunc(processSpecialKeys);

    // OpenGL init
    glEnable(GL_DEPTH_TEST);

    // enter GLUT event processing cycle
    glutMainLoop();

    return 1;
}

No comments:

Post a Comment