questions about camera

hi

what is a camera and how i can implement it?
( for ex: is a modelview matrix which muse be multiplayed to the object local matrix)

i defined an abstract and local matrix for evey object in my scene, and local matrix of evey object is:
localmat = parent->localmat * absmat; ( it works correctly)

and at now i want to create a camera object and move it in the scene, how can i implement it
( for ex i think: cameramatrix * localmat)

and a camera matrix is a modelview matrix??

-i’m using opengl 3.2-

Just use/make a gluLookAt-like func, and you’re ready (flight-sims aside).
Here’s a simplistic TPS camera, using modified nv_math:


Mat4 ILXTPSCAMERA::GetMatrix(){
	
	Mat4 m;
	vec3 eye=vec3(0,0,dist); eye.rotateX(-rotX); eye.rotateY(-rotY); eye+= *pTargetPosition;
	vec3 target = *pTargetPosition +  vec3(0,5,0);

	m.LookAt(eye,target,vec3(0,1,0));
	return m;
}
...
g_Matrix_P.PerspectiveProj(g_FOV,((float)SCREEN_WID)/ ((float)SCREEN_HEI),0.1f,200000);
g_Matrix_MV = camera2.GetMatrix();
g_Matrix_MVP = g_Matrix_P*g_Matrix_MV; // upload this to shaders

Of course, for lighting you will also need to construct a normal-matrix (extract it from g_Matrix_MV if you’re not scaling).

[disclaimer: I’m quite weak at this type of Maths, but maybe I learnt things correctly]
P.S. a camera is just a transformation matrix, that is applied to all objects in the scene. Its kink is that it does things backwards (in an inverse way). Example: if you move the camera forward, you actually move the whole scene backward. If you rotate camera to the left, you rotate the scene to the right.

Usually a camera’s matrix consists only of one translation and rotation. Also, in OpenGL operations are appended in the hierarchy, which is quite nifty: the projection is the final transformation, (governs all, converts to clip-space) but we put it first. Then we just multiply it by the view-matrix (which also governs all, converts worldspace to view-space). Then, finally the model transformations (and their hierarchy). Thanks to this nice chaining, the glPushMatrix/glPopMatrix were available and really useful - you might want to implement them in your code.
In the end, the vtx-shaders care only about the final matrices: gl_ModelViewProjection and gl_NormalMatrix (re-implement them both). That’s why, if in legacy GL you leave the projection-matrix=identity and put all transforms in the modelview-matrix, you’d still get the exact same transformation of gl_Vertex.

When I started learning about the camera/gluLookAt, the redbook was very helpful. There is an online version of the red book - Chapter 3 that is well worth reading since it is relevant to your specific question.

Basically apply the gluLookAt function to the modelview matrix first of all, before drawing your scene such as;

	
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 10, 0, 0, 0, 0, 1, 0, 0);
// means:
// camera eye = (0,10,0)
// look at = (0,0,0) ie the center of the scene
// camera up direction = (1,0,0)

then you can begin drawing your scene objects 


To motivate what gluLookAt does, you might find some value looking at the section entitled Points of View. Especially the Display() function. This is a nice bit of GLUT based openGL code that I ran across showing how useful gluLookAt can be. I learn a lot from studying other’s code when available.

ps the following comment is not strictly related to your question but be careful about putting all transformations in modelview matrix. In fact for some shaders you may want to still distinquish between modelview and projection matrices. For instance the computation of the normal requires the modelview matrix ie NormalMatrix is transpose(inverse(ModelViewMatrix)).
A further explanation is at Help stamp out GL_PROJECTION abuse

i know how working with gluLookAt.

but how can i create an view matrix and how i must be multiplaye this to model matrix?

  1. view * model or model * view
  2. how can o create this matrix from (target, right,up and pos vectors)

i found a code, but it dosent work:(where is problem)


vec3f z = m_vTarget - m_vPos; // Direction vector
z.normalize();
		
// calculate up vector
vec3f vcTemp, vcUp;
float fDot = m_vUp.dot(z) ;
vcTemp = z * fDot;
vcUp = m_vUp - vcTemp;
float fL = vcUp.getLenght();

// if too short take y axis 
if (fL < 1e-6f) 
{
vec3f vcY;
vcY.set(0.0f, 1.0f, 0.0f);

vcTemp = z * z.y;
vcUp = vcY - vcTemp;

fL = vcUp.getLenght();

// take z axis if still too short
if (fL < 1e-6f)
{
vcY.set(0.0f, 0.0f, 1.0f);

vcTemp = z * z.z;
vcUp = vcY - vcTemp;
fL = vcUp.getLenght();

// we tried our beste
if (fL < 1e-6f)
{
DLogger.Log(io::ELML_ERROR, "Error can not compute camera: %S",getName().c_str() );
return;
}
}
}
			
vcUp = vcUp / fL;
 
m_vRight = vcUp.cross(z);

m_Viewmat._elements[0][0] = m_vRight.x;
m_Viewmat._elements[0][1] = vcUp.x;
m_Viewmat._elements[0][2] = z.x;
m_Viewmat._elements[1][0] = m_vRight.y;
m_Viewmat._elements[1][1] = vcUp.y;
m_Viewmat._elements[1][2] = z.y;
m_Viewmat._elements[2][0] = m_vRight.z;
m_Viewmat._elements[2][1] = vcUp.z;
m_Viewmat._elements[3][2] = z.z;
m_Viewmat._elements[3][0] = -(m_vRight.dot(m_vPos));
m_Viewmat._elements[3][1] = -(vcUp.dot(m_vPos));
m_Viewmat._elements[3][2] = -(z.dot(m_vPos));

Get nv_math . It contains an implementation. nv_math can be found in nVidia SDK9.5

To answer your second question “2. how can o create this matrix from (target, right,up and pos vectors)” …
If you are trying to understand the inner workings of the camera similar to gluLookAt, looking at gluLookAt itself may help you understand … see source code for Meas3D:MesaLib-7.5.* in the /Mesa-7.5/src/glu/sgi/libutil/project.c file and locate the the following code snippet


void GLAPIENTRY
gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez, GLdouble centerx,
	  GLdouble centery, GLdouble centerz, GLdouble upx, GLdouble upy,
	  GLdouble upz)
{
    float forward[3], side[3], up[3];
    GLfloat m[4][4];

    forward[0] = centerx - eyex;
    forward[1] = centery - eyey;
    forward[2] = centerz - eyez;

    up[0] = upx;
    up[1] = upy;
    up[2] = upz;

    normalize(forward);

    /* Side = forward x up */
    cross(forward, up, side);
    normalize(side);

    /* Recompute up as: up = side x forward */
    cross(side, forward, up);

    __gluMakeIdentityf(&m[0][0]);
    m[0][0] = side[0];
    m[1][0] = side[1];
    m[2][0] = side[2];

    m[0][1] = up[0];
    m[1][1] = up[1];
    m[2][1] = up[2];

    m[0][2] = -forward[0];
    m[1][2] = -forward[1];
    m[2][2] = -forward[2];

    glMultMatrixf(&m[0][0]);
    glTranslated(-eyex, -eyey, -eyez);
}

This above code should only be applied to your modelview matrix!

An example of how to buld you projection matrix is also in mesa (src/glu/sgi/libutil/project.c)


void GLAPIENTRY
gluPerspective(GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar)
{
    GLdouble m[4][4];
    double sine, cotangent, deltaZ;
    double radians = fovy / 2 * __glPi / 180;

    deltaZ = zFar - zNear;
    sine = sin(radians);
    if ((deltaZ == 0) || (sine == 0) || (aspect == 0)) {
	return;
    }
    cotangent = COS(radians) / sine;

    __gluMakeIdentityd(&m[0][0]);
    m[0][0] = cotangent / aspect;
    m[1][1] = cotangent;
    m[2][2] = -(zFar + zNear) / deltaZ;
    m[2][3] = -1;
    m[3][2] = -2 * zNear * zFar / deltaZ;
    m[3][3] = 0;
    glMultMatrixd(&m[0][0]);
}

which should only be applied to your projection matrix.

To answer your “1. view * model or model * view”? Short answer: projectionview * modelview

more complete answer: reading figure 3-2 from chapter 3 redbook, the order of operations gives M=“Viewport Transformation”“Perspective Division”“Projection Matrix”*“Modelview Matrix”.

ps An alternative to nv_math that I like is openGL Mathematics since it has “lookAt”, “rotate”, translate", etc and matches the openGL GLSL types one-for-one.

how can i compute and put glTranslated(-eyex, -eyey, -eyez) in the view matrix???

“how can i compute and put glTranslated(-eyex, -eyey, -eyez) in the view matrix???”

glMatrixMode(GL_MODELVIEW);
glTranslated(-eyex, -eyey, -eyez)
generates a matrix, lets call it T,
where T=
[1 0 0 -eyex]
[0 1 0 -eyey]
[0 0 1 -eyez]
[0 0 0 1]
then computes model_view=model_view*T

You could explicitly do this glTranslated(-eyex, -eyey, -eyez) yourself by


    GLfloat T[4][4];
    T[0][0] = 1;
    T[1][0] = 0;
    T[2][0] = 0;
    T[3][0] = -eyex;

    T[0][1] = 0;
    T[1][1] = 1;
    T[2][1] = 0;
    T[3][1] = -eyey;

    T[0][2] = 0;
    T[1][2] = 0;
    T[2][2] = 1;
    T[3][2] = -eyez;

    T[0][3] = 0;
    T[1][3] = 0;
    T[2][3] = 0;
    T[3][3] = 1;

    glMultMatrixd(T); // operates on matrix set by glMatrixMode ();


(see MultMatrix and LoadMatrix )

i know the usage of the LoadMatrix and MultMatrix, by i’m working with OpenGL 3.2 and i write a shader which gives the final modelviewprojectionMatrix.

Thats a different question than I originally thought …

first you need to map your shader variable to an ID
glm_ProjectionMatrix_id = glGetUniformLocation(shader_id, “glm_ProjectionMatrix”); //whatever your shader uniform name is

then you need to set the uniform value in your display loop using the ID:
glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, &glm_ProjectionMatrix.top()[0][0] );

Here’s C++ code that is based on glm/freeglut/glew and may help you if you read thru it and try to understand it. It is GL3 and doesn’t use the deprecated matrix manipulation functions. It draws two triangles, when you press T,t they rotate around theta, or P,p they rotates around phi.

Note, the “class CustomGraphicsPipeline” depends only on glm and gl3 so you could probably take that as is if you don’t use freeglut for your window “manager”.


//on linux or mingw: g++ glut_ogl3_helloworld.cpp -lglut -lGLEW -DGL3_PROTOTYPES
// modified to use GLM library from http://pheatt.emporia.edu/courses/2005/cs410f05/hand14/hand14.htm
// modified to use camera at begining of MODELVIEW Transformations, not in the Projection Transform! see http://www.sjbaker.org/steve/omniv/projection_abuse.html
#include <GL/glew.h>     // great opengl extensions helper
#include <GL/gl3.h>
#include <GL/freeglut.h> // use of opengl 3.0 context requires freeglut from svn!

#include <glm/glm.h> //OpenGL Mathematics (GLM).  A C++ mathematics library for 3D graphics.
#include <glm/glmext.h>
#include <glm/GLM_VIRTREV_address.h> // gives helper function address(X) instead of using &X[0][0]
namespace glm
{
          // read glm/gtx/transform.h for function prototypes
          using GLM_GTX_transform;
          using GLM_GTX_transform2; // for lookAt
          using GLM_GTX_matrix_projection;
}
using namespace glm;

//#include <cstdio>
//#include <cmath>
#include <iostream>
//#include <iomanip>
//#include <sstream>
#include <stack>
//#include <cstring>
#include <cassert>

class CustomGraphicsPipeline
{
      GLuint shader_id;
      std::stack<mat4> glm_ProjectionMatrix; //cpu-side
      GLint  glm_ProjectionMatrix_id; //cpu-side hook to shader uniform
      std::stack<mat4> glm_ModelViewMatrix; //cpu-side
      GLint  glm_ModelViewMatrix_id; //cpu-side hook to shader uniform
      GLuint vao_id[2]; // vertex array object hook id
      GLuint vao_elementcount[2]; // number of attribute elements in vao ie number of vertices
      GLuint vao_primitivetype[2]; // type [GL_LINE_LOOP|GL_TRIANGLES|etc] 
    public:
      CustomGraphicsPipeline() :
       shader_id(NULL),
       glm_ProjectionMatrix_id(NULL),
       glm_ModelViewMatrix_id(NULL)
      {
       glm_ProjectionMatrix.push( mat4(1.0f) ); // identity matrix
       glm_ModelViewMatrix.push( mat4(1.0f) ), // identity matrix
       vao_id[0]=NULL; 
       vao_id[1]=NULL;
       vao_elementcount[0]=0; 
       vao_elementcount[1]=0;
       vao_primitivetype[0] = GL_LINE_LOOP;
       vao_primitivetype[1] = GL_TRIANGLES;
      }
      ~CustomGraphicsPipeline() {}

      bool Init()                    // All Setup For OpenGL Goes Here
      {
        GLint ret = true; // optimistic return value upon completion of execution 

        std::cout << "press t,T to rotate camera theta" << std::endl;
        std::cout << "press p,P to rotate camera phi" << std::endl;

        glEnable(GL_DEPTH_TEST);
        glClearColor(0.2f, 0.2f, 0.2f, 0.5f);

      //Datas destioned for video memory, can be local (and lost after bound to GPU!). 
        GLfloat vertices0[] = { // dgl_Vertex
          1.0, -1.0, 0.0, 1.0, // xyzw 
         -1.0, -1.0, 0.0, 1.0,
          0.0,  1.0, 0.0, 1.0
        };
        size_t Nbytes_vertices0=sizeof(vertices0);

        GLfloat colors0[] = { // dgl_Color
          0.0, 0.0, 1.0, 1.0, //rgba
          0.0, 1.0, 0.0, 1.0,
          1.0, 0.0, 0.0, 1.0
        };
        size_t Nbytes_colors0=sizeof(colors0);

        GLfloat vertices1[] = { // dgl_Vertex
          0.5, -0.5, 0.0, 1.0, // xyzw 
         -0.5, -0.5, 0.0, 1.0,
          0.0,  0.5, 0.0, 1.0
        }; 
        size_t Nbytes_vertices1=sizeof(vertices1);

        GLfloat colors1[] = { // dgl_Color
          0.0, 0.0, 1.0, 1.0, //rgba
          0.0, 1.0, 0.0, 1.0,
          1.0, 0.0, 0.0, 1.0
        };
        size_t Nbytes_colors1=sizeof(colors1);

        const GLchar *g_vertexShader[] = {"#version 130
",
         "uniform mat4 glm_ProjectionMatrix;
", // replaces deprecated gl_ProjectionMatrix see http://www.lighthouse3d.com/opengl/glsl/index.php?minimal
         "uniform mat4 glm_ModelViewMatrix;
", // replaces deprecated gl_ModelViewMatrix
         "in     vec4 dgl_Vertex;
", // replaces deprecated gl_Vertex
         "in     vec4 dgl_Color;
", // replaces deprecated gl_Color
         "invariant out  vec4 Color;
", // to fragment shader
         "void main(void)
",
         "{
",
         "  Color = dgl_Color;
",
         "  gl_Position = glm_ProjectionMatrix*glm_ModelViewMatrix*dgl_Vertex;
", // replaces deprecated ftransform() see http://www.songho.ca/opengl/gl_transform.html
         "}
"
        };

        const GLchar *g_fragmentShader[] = {"#version 130
",
         "invariant in vec4 Color;
", // from vertex shader
         "out  vec4 dgl_FragColor;
", // replaces deprecated gl_FragColor
         "void main(void)
",
         "{
",
         "  dgl_FragColor = Color;
", // gl_FragColor is deprecated
         "}
"
        };
  
      // compile Vertex shader
        GLuint m_vxShaderId = glCreateShader(GL_VERTEX_SHADER);
        GLsizei nlines_vx = sizeof(g_vertexShader)/sizeof(const GLchar*);
        glShaderSource(m_vxShaderId, nlines_vx, (const GLchar**)g_vertexShader, NULL);
        glCompileShader(m_vxShaderId);
        CheckShader(m_vxShaderId, GL_COMPILE_STATUS, &ret, "unable to compile the vertex shader!");

      // compile Fragment shader
        GLuint m_fgShaderId = glCreateShader(GL_FRAGMENT_SHADER);
        GLsizei nlines_fg = sizeof(g_fragmentShader)/sizeof(const GLchar*);
        glShaderSource(m_fgShaderId, nlines_fg, (const GLchar**)g_fragmentShader, NULL);
        glCompileShader(m_fgShaderId);
        CheckShader(m_fgShaderId, GL_COMPILE_STATUS, &ret, "unable to compile the fragment shader!");
    
      // link shaders
        shader_id = glCreateProgram();
        glAttachShader(shader_id, m_vxShaderId);
        glAttachShader(shader_id, m_fgShaderId);
        glLinkProgram(shader_id);
        CheckShader(shader_id, GL_LINK_STATUS, &ret, "unable to link the program!");
 
      //hooks from CPU to GPU
        //define Uniform hooks
        glm_ProjectionMatrix_id = glGetUniformLocation(shader_id, "glm_ProjectionMatrix");
        glm_ModelViewMatrix_id = glGetUniformLocation(shader_id, "glm_ModelViewMatrix");

        //guard that all attributes have same number of elements
        assert(Nbytes_vertices0/4/sizeof(GLfloat)==Nbytes_colors0/4/sizeof(GLfloat));
        vao_elementcount[0]=Nbytes_vertices0/4/sizeof(GLfloat); // number of elements for first VAO
        assert(Nbytes_vertices1/4/sizeof(GLfloat)==Nbytes_colors1/4/sizeof(GLfloat));
        vao_elementcount[1]=Nbytes_vertices1/4/sizeof(GLfloat); // number of elements for second VAO

        //create and define vertex array objects
        glGenVertexArrays(2, &vao_id[0]); // vao_id[#] will be referenced in Draw()
        defineVertexArrayObject(vao_id[0],Nbytes_vertices0,4,GL_FLOAT,vertices0,colors0); //VertexAttribArray: vertices0, colors0
        defineVertexArrayObject(vao_id[1],Nbytes_vertices1,4,GL_FLOAT,vertices1,colors1); //VertexAttribArray: vertices1, colors1

      // finally, use the shader for rendering 
        glUseProgram(shader_id);            // select the shaders program

        return ret;                    // Initialization Went OK?
      }

      void defineVertexArrayObject(GLuint vaoId, size_t Nbytes, GLint size, GLenum type, GLfloat *vertices, GLfloat *colors)
      {
        //enable vertex array object to be defined
        glBindVertexArray(vaoId);

        //generate VBO foreach 'in'; dgl_Vertex and dgl_Color
        GLuint m_vboId[2];
        glGenBuffers(2, &m_vboId[0]);

        //"in     vec4 dgl_Vertex;",
        glBindBuffer(GL_ARRAY_BUFFER, m_vboId[0] );  // enable the 1st VBO
        glBufferData(GL_ARRAY_BUFFER, Nbytes, vertices, GL_STATIC_DRAW); // fill the VBO with vertices data
        const GLuint index_mPosition = glGetAttribLocation(shader_id,"dgl_Vertex"); // get ID for "dgl_Vertex"
        glVertexAttribPointer(index_mPosition, size, type, GL_FALSE, 0, 0); // VBO point to the "dgl_Vertex" attribute
        glEnableVertexAttribArray(index_mPosition);    // enable VBO vertex attribute ("dgl_Vertex")

        //"in     vec4 dgl_Color;",
        glBindBuffer(GL_ARRAY_BUFFER, m_vboId[1]);  // enable the 2nd VBO
        glBufferData(GL_ARRAY_BUFFER, Nbytes , colors, GL_STATIC_DRAW); // fill the 2nd VBO with colors data
        const GLuint index_mcolor = glGetAttribLocation(shader_id,"dgl_Color"); // get ID for "dgl_Color"
        glVertexAttribPointer(index_mcolor, size, type, GL_FALSE, 0, 0); // VBO point to the "dgl_Color" attribute
        glEnableVertexAttribArray(index_mcolor);    // enable VBO vertex attribute ("dgl_Color")
      }

      void CheckShader(GLuint id, GLuint type, GLint *ret, const char *onfail)
      {
       //Check if something is wrong with the shader
       switch(type) {
       case(GL_COMPILE_STATUS):
         glGetShaderiv(id, type, ret);
         if(*ret == false){
          int infologLength =  0;
          glGetShaderiv(id, GL_INFO_LOG_LENGTH, &infologLength);
          GLchar buffer[infologLength];
          GLsizei charsWritten = 0;
          std::cout << onfail << std::endl;
          glGetShaderInfoLog(id, infologLength, &charsWritten, buffer);
          std::cout << buffer << std::endl;
         }
         break;
       case(GL_LINK_STATUS):
         glGetProgramiv(id, type, ret);
         if(*ret == false){
          int infologLength =  0;
          glGetProgramiv(id, GL_INFO_LOG_LENGTH, &infologLength);
          GLchar buffer[infologLength];
          GLsizei charsWritten = 0;
          std::cout << onfail << std::endl;
          glGetProgramInfoLog(id, infologLength, &charsWritten, buffer);
          std::cout << buffer << std::endl;
         }
       default:
         break;
       };
      }

      void Draw_vao(size_t index)
      {
        glBindVertexArray(vao_id[index]);    // select the vertex array object:vao_id[index] by definiton using vertices_index,colors_index
        glDrawArrays(vao_primitivetype[index], 0, vao_elementcount[index]);  // draw the array (at the speed of light)
      }

      void Draw()                  // Here's Where We Do All The Drawing
      {
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

        glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, &glm_ProjectionMatrix.top()[0][0] );  // set the rotation/translation/scale matrix 
        //glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, address(glm_ProjectionMatrix.top()) );  // set the rotation/translation/scale matrix 

        {
        glm_ModelViewMatrix.push(glm_ModelViewMatrix.top());
        //glm_ModelViewMatrix.top() *= translate(       vec3(0.5, 0.5, 0.0) );
        glm_ModelViewMatrix.top() *=    rotate(45.0f, vec3(0.0, 0.0, 1.0) ); 
        glm_ModelViewMatrix.top() *=     scale(       vec3(0.2, 0.2, 0.2) ); 

        glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] );  // set the rotation/translation/scale matrix 
        //glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, address(glm_ModelViewMatrix.top()) );  // set the rotation/translation/scale matrix 

        Draw_vao(0);

        glm_ModelViewMatrix.pop();
        } 

        {
        glm_ModelViewMatrix.push(glm_ModelViewMatrix.top());
        glm_ModelViewMatrix.top() *= translate(       vec3(0.0, 0.0, 0.25) );
        //glm_ModelViewMatrix.top() *=    rotate(45.0f, vec3(1.0, 1.0, 0.0) ); 
        glm_ModelViewMatrix.top() *=     scale(       vec3(0.2, 0.2, 0.2) ); 

        glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] );  // set the rotation/translation/scale matrix 
        //glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, address(glm_ModelViewMatrix.top()) );  // set the rotation/translation/scale matrix 

        Draw_vao(1);

        glm_ModelViewMatrix.pop();
        }
      }
      
      bool Reshape(GLfloat ratio)
      { 
          //glMatrixMode(GL_PROJECTION);
          glm_ProjectionMatrix.top() = mat4(1.0); //glLoadIdentity
          glm_ProjectionMatrix.top() *= perspective(20.0f,ratio,1.0f,3.0f);
          //glLoadMatrixf(address(glm_ProjectionMatrix.top()));
          glUniformMatrix4fv(glm_ProjectionMatrix_id, 1, false, &glm_ProjectionMatrix.top()[0][0] );  // set the rotation/translation/scale matrix 
      }

      bool SetCamera(GLfloat theta, GLfloat phi)
      { 
        ////////////// 
          // Set the camera view.
          static const double radianFactor = acos(0.0) / 90.0; 
          float r = 1.0f*2.0; // approx. want half way between near + far (see perspective)
          float eyeX = r * sin(theta * radianFactor) * cos(phi * radianFactor);
          float eyeY = r * sin(theta * radianFactor) * sin(phi * radianFactor);
          float eyeZ = r * cos(radianFactor * theta);

          float centerX = 0, centerY = 0, centerZ = 0;
          float upX = 0, upY = 1.0f, upZ = 0;

          //glMatrixMode(GL_MODELVIEW);
          glm_ModelViewMatrix.top() = mat4(1.0); // LoadIdentity
          glm_ModelViewMatrix.top() *= lookAt( vec3(eyeX, eyeY, eyeZ), vec3(centerX, centerY, centerZ), vec3(upX, upY, upZ)); 
          //glLoadMatrixf(address(glm_ModelViewMatrix.top()));
          glUniformMatrix4fv(glm_ModelViewMatrix_id, 1, false, &glm_ModelViewMatrix.top()[0][0] );

        return true; 
      }
};

// GLOBAL ///////////////////////////////////////////////////////////
CustomGraphicsPipeline Scene;
/////////////////////////////////////////////////////////////////////

namespace global {
  int theta = 0;
  int   phi = 0;
  GLfloat ratio = 1.0;
  int width = 512;
  int height = 512;
};

static void timer(int dt_msec)
{
  static GLfloat time_msec = 0.0;
  time_msec += dt_msec; // absolute time

  Scene.SetCamera(global::theta, global::phi);

  glutPostRedisplay();
  glutTimerFunc(30,timer,30); // come back in 30msec
}

static void display(void) 
{
  Scene.Draw();
  glutSwapBuffers();
}

static void reshape(int w, int h) 
{
    // Set the viewport to be the entire window
    glViewport(0, 0, w, h);

    // Prevent a divide by zero, when window is too short
    if(h == 0) h = 1;

    global::width = w;
    global::height = h;
    global::ratio = 1.0 * w / h;

    Scene.Reshape(global::ratio);
}

static void keyboard(unsigned char k, int x, int y)
{
    switch (k) {
            case 't' : global::theta++; if(global::theta > 360) global::theta = 1; break;
            case 'p' : global::phi++; if(global::phi > 360) global::phi = 1; break;
            case 'T' : global::theta--; if(global::theta < 0) global::theta = 359; break;
            case 'P' : global::phi--; if(global::phi < 0) global::phi = 359; break;
            case  27 : exit(0); break;
    }
}

int main( int argc, char *argv[] )
{
   glutInit( &argc, argv );
   //opengl 3.0 with freeglut requires to install latest version from svn
   //but not necessary to actually get openGL context since code will run anyhow.
   //glutInitContextVersion( 3, 0 ); // freeglut is so cool! get openGL 3.0 context
   //glutInitContextFlags( int flags )
   glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGB);
   glutInitWindowSize(global::width, global::height);
   glutCreateWindow("demo opengl 3.0 matrix transformations");

   glewInit();

   assert( Scene.Init() ); // bail if scene initialization fails

   glutTimerFunc(0,timer,0);
   glutDisplayFunc(display);
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);

   glutMainLoop();

   return 0;
}