Help end child hunger

Keyboard Example: Moving the Camera

 
Prev: Keyboard Next: Advanced Keyboard
 

OK, so lets see a more exciting use for the keyboard using GLUT. In this section we’re going to go through the code of an application that will draw a small world populated with snowmen, and we’re going to use the direction keys to move the camera in this world. The left and right keys will rotate the camera around the Y axis, i.e. in the XZ plane, whereas the up and down keys will move the camera forward and backwards in the current direction.

The code for this sample application is now presented with comments where appropriate. First we need some global variables to store the camera parameters. The variables will store both the camera position and the vector that gives us the aiming direction. We will also store the angle. There is no need to store the y component since it is constant.

Hence, we need:

  • angle: the angle of rotation in the y axis. this variable will allow us to rotate the camera
  • x,z: The camera position in the XZ plane
  • lx,lz: A vector defining our line of sight

Lets deal with the variable declarations:

// angle of rotation for the camera direction
float angle=0.0;
// actual vector representing the camera's direction
float lx=0.0f,lz=-1.0f;
// XZ position of the camera
float x=0.0f,z=5.0f;

The code to draw a snowman is now presented. The result looks like this

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);
}

Next we have the new render function. It contains all the commands to draw our little world. Another change is in the gluLookAt function. The parameters of the gluLookAt function are now variables instead of fixed values. Just in case you aren’t familiar with this function, here goes a brief explanation. The gluLookAt function provides an easy and intuitive way to set the camera position and orientation. Basically it has three groups of parameters, each one is composed of 3 floating point values. The first three values indicate the camera position. The second set of values defines the point we’re looking at. Actually it can be any point in our line of sight.The last group indicates the up vector, this is usually set to (0.0, 1.0, 0.0), meaning that the camera’s is not tilted. If you want to tilt the camera just play with these values. For example, to see everything upside down try (0.0, -1.0, 0.0).

As mentioned before x, y, and z represent the camera position so these values correspond to the first vector in gluLookAt. The second set of parameters, the look at point, is computed by adding the vector which defines our line of sight to the camera position.

  • Look At Point = Line Of Sight + Camera Position

Here is the code for the render function:

void renderScene(void) {

	// Clear Color and Depth Buffers

	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

	// Reset transformations
	glLoadIdentity();
	// Set the camera
	gluLookAt(	x, 1.0f, z,
			x+lx, 1.0f,  z+lz,
			0.0f, 1.0f,  0.0f);

        // Draw ground
	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();

        // Draw 36 SnowMen
	for(int i = -3; i < 3; i++)
		for(int j=-3; j < 3; j++) {
			glPushMatrix();
			glTranslatef(i*10.0,0,j * 10.0);
			drawSnowMan();
			glPopMatrix();
		}

	glutSwapBuffers();
}

Now where ready for the function that will process the arrow keys events. We’re using the left and right arrow keys to rotate the camera, i.e. to change the vector that defines the line of sight. The up and down keys are used to move along the current line of sight.

When the user presses the left or right keys the variable angle is changed accordingly. Based on the angle value it computes the appropriate values for the new lx and lz components of the line of sight vector. Note that we’re only moving in the XZ plane, therefore we don’t need to change the ly coordinate of the line of sight vector. The new lx and lz are mapped onto a unitary circle on the XZ plane. Therefore, given a angle ang, the new values for lx and lz are:

  • lx = sin(ang)
  • lz = -cos(ang)

Just like if we wanted to convert from Polar coordinates to Euclidean coordinates. The lz is negative because the initial value is -1.

Note that the camera doesn’t move when updating lx and lz, the camera position remains the same, only the look at point is altered.

We also want to move the camera along the line of sight, i.e. the next camera position must be along the line of sight vector. In order to achieve this we’re going to add or subtract a fraction of the line of sight vector to our current position when the up or down arrows are pressed, respectively. For instance, to move the camera forward the new values for x and z are:

  • x = x + lx * fraction
  • z = z + lz * fraction

The fraction is a possible speed implementation. We know that (lx,lz) is a unitary vector (as mentioned before, its a point in the unit circle), therefore if the fraction is kept constant then the speed will be kept constant as well. By increasing the fraction we’re moving faster, i.e. we’re moving farther in each frame.

void processSpecialKeys(int key, int xx, int yy) {

	float fraction = 0.1f;

	switch (key) {
		case GLUT_KEY_LEFT :
			angle -= 0.01f;
			lx = sin(angle);
			lz = -cos(angle);
			break;
		case GLUT_KEY_RIGHT :
			angle += 0.01f;
			lx = sin(angle);
			lz = -cos(angle);
			break;
		case GLUT_KEY_UP :
			x += lx * fraction;
			z += lz * fraction;
			break;
		case GLUT_KEY_DOWN :
			x -= lx * fraction;
			z -= lz * fraction;
			break;
	}
}

Next follows the code for the main function using GLUT. The only news in here is the depth test enabling.

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(changeSize);
	glutIdleFunc(renderScene);
	glutKeyboardFunc(processNormalKeys);
	glutSpecialFunc(processSpecialKeys);

	// OpenGL init
	glEnable(GL_DEPTH_TEST);

	// enter GLUT event processing cycle
	glutMainLoop();

	return 1;
}

 

Prev: Keyboard Next: Advanced Keyboard
 

  40 Responses to “Keyboard Example: Moving the Camera”

  1. Can you please tell me how to strafe the camera in all four directions?…I have been trying but couldn’t find much success.

    • Hi, straffin is the same as moving forward/backward, but using the right and up vectors instead of the view direction.

      Consider the gluLookAt function with the three vectors/points: position, look at point and “up” vector. To determine the right vector just perform a cross product between the view direction (look at point – position) and the “up” vector. To compute the real up vector another cross product between the right and view direction is enough.

      Hope this helps

  2. What if i want move the camera 1.0 at time ? i.e. i have a world 10 x 10 , the camera is at 0,0,0 when i hit the key_up i want to move the camera to 0, 0 , 1 and not by a float value

    • Just set the fraction to whatever value yuo require. As real numbers include natural numbers this works for ints as well.

  3. I don’t understand this:
    “The lz is negative because the initial value is -1”.
    Could anyone explain it for me?

    • Hi Peter,

      I’m assuming that the camera initial angle is zero, and the initial looking direction is the negative Z, it is just a convention, you could do it in many different ways.

      Hope this helps,

      António

  4. Hello,

    My snowmen don’t look like the snowmen in your picture – they don’t look 3D. I presume you’re using shaders to produce that effect. Is this covered in another tutorial? Thanks.

  5. i want urgent code for moving snow man nd fallin snow immediately plzzzzz

  6. While drawing snowman’s nose, there is a rotation line:

    glRotatef(0.0f,1.0f, 0.0f, 0.0f);

    This line is useless, right? Secondly, could anyone explain me what is the magnitude of x, y or z represents? In other words, what would be the difference between:

    glRotatef(1.0f,1.0f, 0.0f, 0.0f); AND glRotatef(1.0f,20.0f, 0.0f, 0.0f);

    Thanks in advance!

    • The first rotation you mention is useless. I took it off. Thanks for letting me know.

      As for the magnitude, it is irrelevant. Only the direction is meaningful.

  7. This tutorial is awsome!

    I have one question:
    We are changing angle variable, and I don’t see the code, that use it as argument or sth. When I comment angle changing in processSpecialKeys, then camera doesn’t change. Could You explain (maybe I miss sth in previous chapters) where angle is used?

  8. Great tutorial… I grasp the material very quickly..Thanks a lot

  9. #include
    #include
    #include
    GLfloat bi;
    GLint s,cr;
    void myinit()
    {
    glClearColor(1.0,1.0,1.0,1.0);
    glColor3f(0.0,1.0,0.0);
    glPointSize(6.0);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluOrtho2D(0.0,900.0,0.0,640.0);
    glMatrixMode(GL_MODELVIEW);
    }
    void box()
    {
    {
    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(50+cr+bi,270);
    glVertex2i(50+cr+bi,250);
    glVertex2i(70+cr+bi,250);
    glVertex2i(70+cr+bi,270);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(150+cr+bi,360);
    glVertex2i(150+cr+bi,340);
    glVertex2i(170+cr+bi,340);
    glVertex2i(170+cr+bi,360);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(270+cr+bi,270);
    glVertex2i(270+cr+bi,250);
    glVertex2i(290+cr+bi,250);
    glVertex2i(290+cr+bi,270);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(300+cr+bi,270);
    glVertex2i(300+cr+bi,250);
    glVertex2i(320+cr+bi,250);
    glVertex2i(320+cr+bi,270);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(400+cr+bi,270);
    glVertex2i(400+cr+bi,250);
    glVertex2i(420+cr+bi,250);
    glVertex2i(420+cr+bi,270);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(440+cr+bi,270);
    glVertex2i(440+cr+bi,250);
    glVertex2i(460+cr+bi,250);
    glVertex2i(460+cr+bi,270);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(550+cr+bi,350);
    glVertex2i(550+cr+bi,330);
    glVertex2i(570+cr+bi,330);
    glVertex2i(570+cr+bi,350);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(600+cr+bi,350);
    glVertex2i(600+cr+bi,330);
    glVertex2i(620+cr+bi,330);
    glVertex2i(620+cr+bi,350);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(700+cr+bi,270);
    glVertex2i(700+cr+bi,250);
    glVertex2i(720+cr+bi,250);
    glVertex2i(720+cr+bi,270);
    glEnd();

    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(830+cr+bi,270);
    glVertex2i(830+cr+bi,250);
    glVertex2i(850+cr+bi,250);
    glVertex2i(850+cr+bi,270);
    glEnd();
    //box1();

    glEnd();
    glutPostRedisplay();
    }

    }

    void redraw()
    { if(s==0)
    {
    if(bi<40)
    {

    bi+=-0.1;
    glutPostRedisplay();
    }
    else
    { bi=bi-1000;
    glutPostRedisplay();
    }
    }
    }

    GLint i;
    void display()
    {
    glClear(GL_COLOR_BUFFER_BIT);
    glBegin(GL_POLYGON);
    glColor3f(0.0,0.0,0.0);
    glVertex2i(1,250);
    glVertex2i(1,230);
    glVertex2i(900,230);
    glVertex2i(900,250);
    glEnd();

    redraw();
    box();

    glutSwapBuffers();

    glFlush();
    glutPostRedisplay();
    }
    //GLint cr=0;

    void main(int argc,char** argv)
    {
    glutInit(&argc,argv);
    glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB);
    glutInitWindowSize(900,500);
    glutCreateWindow("hgfh");

    glutDisplayFunc(display);

    myinit();

    glutMainLoop();
    }

    this a bit of prog….and i need to design a game where a man is standing at one end that is at the starting of the screen and on the background the blocks will be moving as u can see here i want to give it a keyboard use…plz help me……to do so by pressing "a" in the keyboard the man should go up…like this…plz help me….

  10. In case somebody wants a version that’s easy to copy/paste and implement:

    Seems like it will be useful since there was actually quite a lot changed since the last version.


    #include
    #include

    #ifdef __APPLE__
    #include
    #else
    #include
    #endif

    // actual vector representing the camera's direction
    float lx=0.0f,lz=-1.0f;
    // XZ position of the camera
    float x=0.0f,z=5.0f;

    // all variables initialized to 1.0, meaning
    // the triangle will initially be white
    float red=1.0f, blue=1.0f, green=1.0f;

    // angle for rotating triangle
    float angle = 0.0f;

    //int dummy = 5;

    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);
    glRotatef(0.0f,1.0f, 0.0f, 0.0f);
    glutSolidCone(0.08f,0.5f,10,2);
    }

    void changeSize(int w, int h)
    {

    // Prevent a divide by zero, when window is too short
    // (you cant make a window of zero width).
    if (h == 0)
    h = 1;
    float ratio = w * 1.0 / h;

    // Use the Projection Matrix
    glMatrixMode(GL_PROJECTION);

    // Reset Matrix
    glLoadIdentity();

    // Set the viewport to be the entire window
    glViewport(0, 0, w, h);

    // Set the correct perspective.
    gluPerspective(45.0f, ratio, 0.1f, 100.0f);

    // Get Back to the Modelview
    glMatrixMode(GL_MODELVIEW);
    }

    void renderScene(void)
    {

    // Clear Color and Depth Buffers

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Reset transformations
    glLoadIdentity();
    // Set the camera
    gluLookAt( x, 1.0f, z,
    x+lx, 1.0f, z+lz,
    0.0f, 1.0f, 0.0f);

    // Draw ground
    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();

    // Draw 36 SnowMen
    for(int i = -3; i < 3; i++)
    for(int j=-3; j < 3; j++) {
    glPushMatrix();
    glTranslatef(i*10.0,0,j * 10.0);
    drawSnowMan();
    glPopMatrix();
    }

    glutSwapBuffers();
    }

    void processNormalKeys(unsigned char key, int x, int y)
    {

    if (key == 27)
    exit(0);
    }

    void processSpecialKeys(int key, int xx, int yy)
    {

    float fraction = 0.1f;

    switch (key) {
    case GLUT_KEY_LEFT :
    angle -= 0.01f;
    lx = sin(angle);
    lz = -cos(angle);
    break;
    case GLUT_KEY_RIGHT :
    angle += 0.01f;
    lx = sin(angle);
    lz = -cos(angle);
    break;
    case GLUT_KEY_UP :
    x += lx * fraction;
    z += lz * fraction;
    break;
    case GLUT_KEY_DOWN :
    x -= lx * fraction;
    z -= lz * fraction;
    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(changeSize);
    glutIdleFunc(renderScene);
    glutKeyboardFunc(processNormalKeys);
    glutSpecialFunc(processSpecialKeys);

    // OpenGL init
    glEnable(GL_DEPTH_TEST);

    // enter GLUT event processing cycle
    glutMainLoop();

    return 1;
    }

  11. #include “stdafx.h”
    #include
    #include
    // angle of rotation for the camera direction
    float angle=0.0;
    // actual vector representing the camera’s direction
    float lx=0.0f,lz=-1.0f;
    // XZ position of the camera
    float x=0.0f,z=5.0f;

    void drawTriangle()
    {
    glBegin(GL_TRIANGLES);
    glColor3f(1.0,0,0);
    glVertex3f(-0.5f,-0.5f, 0.0f);
    glVertex3f( -0.5f, 0.0f, 0.0);
    glVertex3f( 0.0f, -0.5f, 0.0);
    glEnd();
    }

    void processSpecialKeys(int key, int xx, int yy) {

    float fraction = 0.01f;
    switch (key) {
    case GLUT_KEY_LEFT :
    angle -= 0.001f;
    lx = sin(angle);
    lz = -cos(angle);
    break;

    case GLUT_KEY_RIGHT :
    angle += 0.001f;
    lx = sin(angle);
    lz = -cos(angle);
    break;
    case GLUT_KEY_UP :
    lx += lx * fraction;
    lz += lz * fraction;
    break;
    case GLUT_KEY_DOWN :
    lx -= lx * fraction;
    lz -= lz * fraction;
    break;
    }
    }

    void renderScene(void) {

    gluLookAt( x, 1.0f, z,
    x+lx, 1.0f, z+lz,
    0.0f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity();

    glColor3f(0.2f, 0.1f, 0.4f);
    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();
    for(int i = -3; i < 3; i++)
    for(int j=-3; j < 3; j++) {
    glPushMatrix();
    glTranslatef(i*10,0,j * 10);
    drawTriangle();
    glPopMatrix();
    }
    glutSwapBuffers();
    }
    void reshape (int width, int height) {
    glViewport(0, 0, (GLsizei)width, (GLsizei)height);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    gluPerspective(0, (GLfloat)width / (GLfloat)height, 1.0, 100.0);
    glMatrixMode(GL_MODELVIEW);
    }

    int main(int argc, char **argv) {
    #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" );
    glutInit(&argc, argv);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA |GLUT_DEPTH);
    glutInitWindowPosition(50,50);
    glutInitWindowSize(500,500);
    glutCreateWindow(argv[0]);
    glutDisplayFunc(renderScene);
    glutReshapeFunc(reshape);
    glutIdleFunc(renderScene);
    glutSpecialFunc(processSpecialKeys);
    glEnable(GL_DEPTH_TEST);
    glutMainLoop();
    return 1;
    }

    this code is not working sir plz help me .

  12. %$&# yeah… This is best tutorial I have ever got… THANKS MAAAAN!!!!

  13. And now I see this site doesn’t show the includes properly because of the greater then and less then brackets having a conflict. That I see is part of the problem here on this website. Hard for anyone else to learn to know what libraries are needed. Good thing I knew what you needed. For your code to work, make sure the following is ADDED to the top, but change what I spelled out with the actual symbol. Greater then and less then signs.

    #ifdef __APPLE__
    #include ( LESS THEN BRACKET ) GLUT/glut.h ( GREATER THEN BRACKET )
    #else
    #include ( LESS THEN BRACKET ) GL/glut.h ( GREATER THEN BRACKET )
    #endif

    #include ( LESS THEN BRACKET ) stdlib.h ( GREATER THEN BRACKET )
    #include “math.h”

  14. @ Zoe, Here you go, your code has been fixed. Turns out, you had more then one problem with this code. First off, your screen position was set way out to 8000+ for both X and Y. So I fixed that with 1024×768 as a screen resolution and set the window position to 1,1. The 1,1 is where on your screen it will show up, which in this case will be the top left.

    The other problem is, you didn’t supply the Math.H file or any includes. You just show # Include, and that’s all you had. So that’s been fixed.

    Enjoy,
    John


    #ifdef __APPLE__
    #include
    #else
    #include
    #endif

    #include
    #include "math.h"

    GLuint listID;
    GLuint list2ID;
    GLUquadric *sun, *mercury, *venus, *earth, *mars, *jupiter, *saturn, *uranus, *neptune;
    GLfloat zoomx=128000;
    GLfloat zoomy=80000;
    // angle of rotation for the camera direction
    GLfloat angle=0.0;
    // actual vector representing the camera's direction
    GLfloat lx=0.0f,lz=-1.0f;
    // XZ position of the camera
    GLfloat x=0.0f,z=5.0f;
    GLfloat fraction;

    void init()
    {
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    //store view matrix

    glMatrixMode (GL_MODELVIEW);
    glLoadIdentity();

    angle=0;
    glutInitWindowPosition(1,1);
    glutInitWindowSize(1024,768);
    glutCreateWindow("Solar System");

    glClearColor(0,0,0,0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-128000,128000,-80000,80000,1,5000);

    glClearColor(0,0,0,1);

    //glEnable(GL_DEPTH_TEST);

    sun=gluNewQuadric();
    mercury=gluNewQuadric();
    venus=gluNewQuadric();
    earth=gluNewQuadric();
    mars=gluNewQuadric();
    jupiter=gluNewQuadric();
    saturn=gluNewQuadric();
    uranus=gluNewQuadric();
    neptune=gluNewQuadric();
    }

    void display()
    {
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);

    //glLoadIdentity();
    //gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);

    //draw sun
    glLoadIdentity();
    glColor3f(1,0,0);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    //glutPostRedisplay();
    gluQuadricDrawStyle(sun, GLU_LINE);
    gluSphere(sun,1400,400,400);

    //draw mercury
    angle=(angle+0.01);
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-397+1930*cos(angle/0.24)*cos(0.51)-1887*sin(angle/0.24)*sin(0.51),1930*cos(angle/0.24)*sin(0.51)+1887*sin(angle/0.24)*cos(0.51),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(mercury, GLU_LINE);
    gluSphere(mercury,25,20,20);

    //draw venus
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-24.4+3607*cos(angle/0.62)*cos(0.5)-3606*sin(angle/0.62)*sin(0.5),3607*cos(angle/0.62)*sin(0.5)+3606*sin(angle/0.62)*cos(0.5),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(venus, GLU_LINE);
    gluSphere(venus,61,20,20);

    //draw earth
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-83+4986*cos(angle)*cos(2)-4985*sin(angle)*sin(2),4986*cos(angle)*sin(2)+4985*sin(angle)*cos(2),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(earth, GLU_LINE);
    gluSphere(earth,64,10,10);

    //draw mars
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-709+7598*cos(angle/1.9)*cos(5)-7560*sin(angle/1.9)*sin(5),7598*cos(angle/1.9)*sin(5)+7560*sin(angle/1.9)*cos(5),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(mars, GLU_LINE);
    gluSphere(mars,34,10,10);

    //draw jupiter
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-1266+25951*cos(angle/11.9)*cos(4.8)-25919*sin(angle/11.9)*sin(4.8),25951*cos(angle/11.9)*sin(4.8)+25919*sin(angle/11.9)*cos(4.8),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(jupiter, GLU_LINE);
    gluSphere(jupiter,714,100,100);

    //draw saturn
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-2664+47783*cos(angle/29.5)*cos(15)-47697*sin(angle/29.5)*sin(15),47783*cos(angle/29.5)*sin(15)+47697*sin(angle/29.5)*cos(15),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(saturn, GLU_LINE);
    gluSphere(saturn,602,100,100);

    //draw uranus
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-4258+95889*cos(angle/84.32)*cos(6)-95769*sin(angle/84.32)*sin(6),95889*cos(angle/84.32)*sin(6)+95769*sin(angle/84.32)*cos(6),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(uranus, GLU_LINE);
    gluSphere(uranus,255,100,100);

    //draw neptune
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-1683.4+150114*cos(angle/164.8)*cos(4.6)-150107*sin(angle/164.8)*sin(4.6),150114*cos(angle/164.8)*sin(4.6)+150107*sin(angle/164.8)*cos(4.6),0);
    glutPostRedisplay();
    gluQuadricDrawStyle(neptune, GLU_LINE);
    gluSphere(neptune,247,100,100);
    //glLoadIdentity();
    glutSwapBuffers();

    }

    void keysnormal(unsigned char nkey, int x2, int y2)
    {
    fraction = 0.1f;
    switch (nkey) {
    case 27 : //Esc key
    exit(0);
    case 65 : //A key
    angle -= 0.01f;
    lx = sin(angle);
    lz = -cos(angle);
    //glLoadIdentity();
    //gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    //glutPostRedisplay();
    break;
    case 68 : //D key
    angle += 0.01f;
    lx = sin(angle);
    lz = -cos(angle);
    //glLoadIdentity();
    //gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    //glutPostRedisplay();
    break;
    case 87 : //W key
    x += lx * fraction;
    z += lz * fraction;
    //glLoadIdentity();
    //gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    //glutPostRedisplay();
    break;
    case 83 : //S key
    x -= lx * fraction;
    z -= lz * fraction;
    //glLoadIdentity();
    //gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    //glutPostRedisplay();
    break;
    }

    }

    void keyspecial( int key, int x1, int y1 )
    {
    if (key==GLUT_KEY_UP)
    {
    zoomx=zoomx/2;
    zoomy=zoomy/2;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1*zoomx,zoomx,-1*zoomy,zoomy,1,5000);
    glutPostRedisplay();
    }
    if (key==GLUT_KEY_DOWN)
    {
    zoomx=zoomx*2;
    zoomy=zoomy*2;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1*zoomx,zoomx,-1*zoomy,zoomy,1,5000);
    glutPostRedisplay();
    }
    }

    int main(int argc, char **argv)
    {
    glutInit(&argc,argv);

    //Initializations
    init();

    glutDisplayFunc(display);
    glutKeyboardFunc(keysnormal);
    glutSpecialFunc(keyspecial);
    glEnable(GL_DEPTH_TEST);
    glutMainLoop();
    return 0;
    }

  15. If anyone feel like debugging please help! I am trying to make camera moves like this tutorial in a simple solar system model but it doesn’t work. I’ve tried to put glulookat at different positions in my code but still nothing.
    Here is my code (sorry for the wall of text, I couldn’t find any way to hide it):


    #include // Header file for standard file i/o.
    #include // Header file for malloc/free.
    #include
    #include //include the gl header file
    #include //include the glut header file /* this includes the necessary X headers */

    GLuint listID;
    GLuint list2ID;
    GLUquadric *sun, *mercury, *venus, *earth, *mars, *jupiter, *saturn, *uranus, *neptune;
    GLfloat zoomx=128000;
    GLfloat zoomy=80000;
    // angle of rotation for the camera direction
    GLfloat angle=0.0;
    // actual vector representing the camera's direction
    GLfloat lx=0.0f,lz=-1.0f;
    // XZ position of the camera
    GLfloat x=0.0f,z=5.0f;
    GLfloat fraction;

    void init()
    { glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH);
    angle=0;
    glutInitWindowPosition(128000,80000);
    glutInitWindowSize(1280,800);
    glutCreateWindow("Solar System");

    glClearColor(0,0,0,0);

    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-128000,128000,-80000,80000,1,5000);

    glClearColor(0,0,0,1);

    //glEnable(GL_DEPTH_TEST);

    sun=gluNewQuadric();
    mercury=gluNewQuadric();
    venus=gluNewQuadric();
    earth=gluNewQuadric();
    mars=gluNewQuadric();
    jupiter=gluNewQuadric();
    saturn=gluNewQuadric();
    uranus=gluNewQuadric();
    neptune=gluNewQuadric();
    }

    void display()
    { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

    glMatrixMode(GL_MODELVIEW);

    //glLoadIdentity();
    //gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);

    //draw sun
    glLoadIdentity();
    glColor3f(1,0,0);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    //glutPostRedisplay();
    gluQuadricDrawStyle(sun, GLU_LINE);
    gluSphere(sun,1400,400,400);

    //draw mercury
    angle=(angle+0.01);
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-397+1930*cos(angle/0.24)*cos(0.51)-1887*sin(angle/0.24)*sin(0.51),1930*cos(angle/0.24)*sin(0.51)+1887*sin(angle/0.24)*cos(0.51),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(mercury, GLU_LINE);
    gluSphere(mercury,25,20,20);

    //draw venus
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-24.4+3607*cos(angle/0.62)*cos(0.5)-3606*sin(angle/0.62)*sin(0.5),3607*cos(angle/0.62)*sin(0.5)+3606*sin(angle/0.62)*cos(0.5),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(venus, GLU_LINE);
    gluSphere(venus,61,20,20);

    //draw earth
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-83+4986*cos(angle)*cos(2)-4985*sin(angle)*sin(2),4986*cos(angle)*sin(2)+4985*sin(angle)*cos(2),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(earth, GLU_LINE);
    gluSphere(earth,64,10,10);

    //draw mars
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-709+7598*cos(angle/1.9)*cos(5)-7560*sin(angle/1.9)*sin(5),7598*cos(angle/1.9)*sin(5)+7560*sin(angle/1.9)*cos(5),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(mars, GLU_LINE);
    gluSphere(mars,34,10,10);

    //draw jupiter
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-1266+25951*cos(angle/11.9)*cos(4.8)-25919*sin(angle/11.9)*sin(4.8),25951*cos(angle/11.9)*sin(4.8)+25919*sin(angle/11.9)*cos(4.8),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(jupiter, GLU_LINE);
    gluSphere(jupiter,714,100,100);

    //draw saturn
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-2664+47783*cos(angle/29.5)*cos(15)-47697*sin(angle/29.5)*sin(15),47783*cos(angle/29.5)*sin(15)+47697*sin(angle/29.5)*cos(15),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(saturn, GLU_LINE);
    gluSphere(saturn,602,100,100);

    //draw uranus
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-4258+95889*cos(angle/84.32)*cos(6)-95769*sin(angle/84.32)*sin(6),95889*cos(angle/84.32)*sin(6)+95769*sin(angle/84.32)*cos(6),0);
    //glutPostRedisplay();
    gluQuadricDrawStyle(uranus, GLU_LINE);
    gluSphere(uranus,255,100,100);

    //draw neptune
    glLoadIdentity();
    glColor3f(0,0,1);
    gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    glTranslatef(-1683.4+150114*cos(angle/164.8)*cos(4.6)-150107*sin(angle/164.8)*sin(4.6),150114*cos(angle/164.8)*sin(4.6)+150107*sin(angle/164.8)*cos(4.6),0);
    glutPostRedisplay();
    gluQuadricDrawStyle(neptune, GLU_LINE);
    gluSphere(neptune,247,100,100);

    glutSwapBuffers();

    }

    void keysnormal(unsigned char nkey, int x2, int y2)
    {
    fraction = 0.1f;
    switch (nkey) {
    case 27 : //Esc key
    exit(0);
    case 65 : //A key
    angle -= 0.01f;
    lx = sin(angle);
    lz = -cos(angle);
    //glLoadIdentity();
    //gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    //glutPostRedisplay();
    break;
    case 68 : //D key
    angle += 0.01f;
    lx = sin(angle);
    lz = -cos(angle);
    //glLoadIdentity();
    //gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    //glutPostRedisplay();
    break;
    case 87 : //W key
    x += lx * fraction;
    z += lz * fraction;
    //glLoadIdentity();
    //gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    //glutPostRedisplay();
    break;
    case 83 : //S key
    x -= lx * fraction;
    z -= lz * fraction;
    //glLoadIdentity();
    //gluLookAt( x, 1.0f, z,x+lx, 1.0f, z+lz,0.0f, 1.0f, 0.0f);
    //glutPostRedisplay();
    break;
    }

    }

    void keyspecial( int key, int x1, int y1 )
    {

    if (key==GLUT_KEY_UP)
    {
    zoomx=zoomx/2;
    zoomy=zoomy/2;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1*zoomx,zoomx,-1*zoomy,zoomy,1,5000);
    glutPostRedisplay();
    }
    if (key==GLUT_KEY_DOWN)
    {
    zoomx=zoomx*2;
    zoomy=zoomy*2;
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1*zoomx,zoomx,-1*zoomy,zoomy,1,5000);
    glutPostRedisplay();

    }
    }

    int main(int argc, char **argv)
    {
    glutInit(&argc,argv);

    //Initializations
    init();

    glutDisplayFunc(display);
    glutKeyboardFunc(keysnormal);
    glutSpecialFunc(keyspecial);
    glEnable(GL_DEPTH_TEST);
    glutMainLoop();
    return 0;

    }

  16. Extremely helpful tutorials mate. Thanks a lot.

  17. hi, can you please explain about the calculations in processSpecialKeys function in more depth?

    what if I want to change the starting direction of the camera? what should be the angle and the corresponding vector?

  18. Thank you for the tutorial, very nicely explained.

    But my math is quite weak when it comes to vectors and angles. 🙁

  19. I got the code to work and am having a lot of fun with this. But the snow man does not have any lighting effects on it like your picture. My snow man is only a flat color. Am I missing something?

    • No, you’re not missing anything. I kept the source code as simple as possible, hence no lighting.

    • Oh boy did he trick you. You get a flatted sample code. The initRendering() function is completely missing.
      glEnable(GL_LIGHTING) enables shades & glEnable(GL_LIGHT0) enables colors and more that I am still discovering.

  20. Sorry for posting comments to quickly 😛 it just that I`m discovering new things to comment. Hope it helps… This is my final code for this page

    #include
    #include

    // angle of rotation for the camera direction
    float angle=0.0;
    // actual vector representing the camera’s direction
    float lx=0.0f,lz=-1.0f;
    // XZ position of the camera
    float x=0.0f,z=5.0f;

    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);
    glRotatef(0.0f,1.0f, 0.0f, 0.0f);
    glutSolidCone(0.08f,0.5f,10,2);
    }

    void renderScene(void) {

    // Clear Color and Depth Buffers

    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    // Reset transformations
    glLoadIdentity();
    // Set the camera
    gluLookAt( x, 1.0f, z,
    x+lx, 1.0f, z+lz,
    0.0f, 1.0f, 0.0f);

    // Draw ground
    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();

    // Draw 36 SnowMen
    for(int i = -3; i < 3; i++)
    for(int j=-3; j < 3; j++) {
    glPushMatrix();
    glTranslatef(i*10.0,0,j * 10.0);
    drawSnowMan();
    //glCallList(snowman_display_list);
    glPopMatrix();
    }

    glutSwapBuffers();
    }

    void changeSize(int w, int h) {

    // Prevent a divide by zero, when window is too short
    // (you cant make a window of zero width).
    if (h == 0)
    h = 1;
    float ratio = w * 1.0 / h;

    // Use the Projection Matrix
    glMatrixMode(GL_PROJECTION);

    // Reset Matrix
    glLoadIdentity();

    // Set the viewport to be the entire window
    glViewport(0, 0, w, h);

    // Set the correct perspective.
    gluPerspective(45.0f, ratio, 0.1f, 100.0f);

    // Get Back to the Modelview
    glMatrixMode(GL_MODELVIEW);
    }

    void processNormalKeys(unsigned char key, int x, int y) {

    if (key == 27)
    exit(0);
    }

    void processSpecialKeys(int key, int xx, int yy) {

    float fraction = 0.1f;

    switch (key) {
    case GLUT_KEY_LEFT :
    angle -= 0.01f;
    lx = sin(angle);
    lz = -cos(angle);
    break;
    case GLUT_KEY_RIGHT :
    angle += 0.01f;
    lx = sin(angle);
    lz = -cos(angle);
    break;
    case GLUT_KEY_UP :
    x += lx * fraction;
    z += lz * fraction;
    break;
    case GLUT_KEY_DOWN :
    x -= lx * fraction;
    z -= lz * fraction;
    break;
    }
    }

    void main(int argc, char **argv) {
    //to hide console
    #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" )
    // 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(changeSize);
    glutIdleFunc(renderScene);
    glutKeyboardFunc(processNormalKeys);
    glutSpecialFunc(processSpecialKeys);

    // OpenGL init
    glEnable(GL_DEPTH_TEST);

    // enter GLUT event processing cycle
    glutMainLoop();

    }

    • thats include math.h and GL/glut.h I think at greater than and less than sign removed it

    • Hi Glen,

      Which version of VS are you using? I can’t get the pragma to work in VS2010 🙁

    • I once tried that “pragma thing” to hide the console, I never got it to work either though. The solution I’m currently using is basically the same but instead of placing that within the code, go to:

      Project Properties » Linker » Command Line

      and add:

      /SUBSYSTEM:WINDOWS /ENTRY:mainCRTStartup

      to Additional Options.

  21. I got it working but i think this part here is wrong

    case GLUT_KEY_LEFT :
    angle -= 0.01f;
    lx = sin(angle);
    lz = -cos(angle);
    break;
    case GLUT_KEY_RIGHT :
    angle -= 0.01f;
    lx = sin(angle);
    lz = -cos(angle);
    break;

    RIGHT and LEFT keys, does same funtion. both goes left

    • case GLUT_KEY_LEFT :
      angle -= 0.01f;
      lx = sin(angle);
      lz = -cos(angle);
      break;
      case GLUT_KEY_RIGHT :
      angle += 0.01f;
      lx = sin(angle);
      lz = -cos(angle);
      break;

      I think this is the correct code

  22. change size and processnormalkeys are undeclared

    • I’m not providing the full source code in here, just the modifications from the previous example.

  23. some functions cant be called… what are the libraries which needs to be included?

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: