Working with 3D Environment – Opengl tutorial 3 by Osama Hosam


Introduction

Most of current games in market are built in the 3D environment, so it is clear that we find the look and feel of the real world environment. We will build a simple application that helps us to understand how to use OpenGL to build a real world 3D game. We are going to draw shapes in 3D, rotate and move them. First we will show the difference between the previous tutorials and this tutorial. Then we will explain in detail how to translate rotate and scale objects.

Transforming and rotating the objects

The combination of rotation and translation is always done in OpenGL. With combining the two operations, you should take care of the order, since if you do the translation first and then do the rotation it will lead to another results than doing the opposite. Fig.1 shows an example of a cube, in the left part it is Rotated and then translated (the cub’s initial position is at origin and the final position is on x-axis), in the right part it is translated and then rotated (the cub’s final position is different and not on x-axis as the previous case)

Fig.1 Rotate-Translate combination

Transformation Modeling

The transformations are models in OpenGL with the following three modules

  • glTranslate()
  • glRotate()
  • glScale()

glTranslate() is used to move the object from place to another, in other words you can say that we move the coordinate system by the amount of translation. Fig.2 shows the translation of a sample cube, it is done also by moving the coordinate system. The feel of translation can be seen as “You are moving” state this can occur if you are inside an object and you move the object so you feel you are moving, while the second state is “The object is moving” state in which the object is small and you see it moving and rotating. “You are moving state” can be done by using the gluLookAt() function in OpenGL which changes the camera position or “Your” position.

In OpenGL if you are implementing a game in which you driving a car, If you move the car in the street and you see the car is becoming smaller when it goes into the screen, this reflects the “Object is moving” state while if the car is fixed and the platform and the road is moving, this is the “You are moving” state. The first state is done by translating the car object while the second state is done by translating the whole scene except the car.

Fig.2 translating in 3D space

glRotate() is used to rotate an object counterclockwise around an axis. It is very important to notice that is the angle of rotation is zero; this means the object will not be rotated. Also if the object is near the rotating axis, it will move by small amount rather than an object which is positioned away from the rotating axis. glRotate is shown in Fig.3

Fig.3 rotating in 3D space.

glScale() is used to shrink or stretch the object. glScale() is used also in zooming in or out the whole scene.

The program structure

The program from previous tutorials can be used but with some changes. In the previous tutorials we have used the orthogonal projection, while in this tutorial we are going to use the perspective projection. The orthogonal projection is suitable to design simple 2D games while the perspective projection can be used to implement real world 3D games. The OpenGL program structure should be as follow

 
#include "stdafx.h" 
#include <GL/glut.h> 
#pragma comment (lib,"opengl32.lib") 
#pragma comment (lib,"glu32.lib") 
#pragma comment (lib,"glut32.lib") 
void render() 
{ 
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); 
 glLoadIdentity(); 
 glTranslatef(0,0,-3.0); 
 //Draw your objects here 
 glutSwapBuffers(); 
} 
void reshape(int w,int h) 
{ 
 glViewport(0,0,w,h); 
 glMatrixMode(GL_PROJECTION); 
 glLoadIdentity(); 
 gluPerspective(45.0f,(float)w/(float)h,1,1000); 
 glMatrixMode(GL_MODELVIEW); 
 glLoadIdentity(); 
} 
int main(int argc, char* argv[]) 
{ 
 glutInit(&argc,argv); 
 glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); 
 //window settings
 glutInitWindowPosition(100,100);
 glutInitWindowSize(320,230);
 glutCreateWindow("Tutorial 3: Working with 3D environment");
 glutDisplayFunc(render);
 glutIdleFunc(render);
 glutReshapeFunc(reshape);
 glutMainLoop();
 return 0;
}

gluPerspective() take the following form: void gluPerspective(GLdouble fovy, GLdouble aspect,GLdouble near, GLdouble far); fovy Is the field of view angle, aspect is the aspect ratio of the viewed scene. Near and far are the distances between the view point and the clipping window and they must be both positive. gluPerspective() is described in Fig.4

Fig.4 the perspective volume in OpenGL

glutIdleFunc(render), is very important, without it the scene will not be changed. It is telling OpenGL to execute the function render even in the Idle state. An example of using gluPerspective, we will show how to render a cube in OpenGL and translate scale and rotate it. The code of the render function will be changed as follow:

 
void render() 
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glLoadIdentity();
 glTranslatef(-1.5f,0.0f,-10.0f);
 glRotatef(45,0,1,0);
 //Draw your objects here
 glBegin(GL_QUADS);
 glColor3f(0.0f,1.0f,0.0f);
 glVertex3f( 1.0f, 1.0f,-1.0f);
 glVertex3f(-1.0f, 1.0f,-1.0f);
 glVertex3f(-1.0f, 1.0f, 1.0f);
 glVertex3f( 1.0f, 1.0f, 1.0f);
 glColor3f(1.0f,0.5f,0.0f);
 glVertex3f( 1.0f,-1.0f, 1.0f);
 glVertex3f(-1.0f,-1.0f, 1.0f);
 glVertex3f(-1.0f,-1.0f,-1.0f);
 glVertex3f( 1.0f,-1.0f,-1.0f);
 glColor3f(1.0f,0.0f,0.0f);
 glVertex3f( 1.0f, 1.0f, 1.0f);
 glVertex3f(-1.0f, 1.0f, 1.0f);
 glVertex3f(-1.0f,-1.0f, 1.0f);
 glVertex3f( 1.0f,-1.0f, 1.0f);
 glColor3f(1.0f,1.0f,0.0f);
 glVertex3f( 1.0f,-1.0f,-1.0f);
 glVertex3f(-1.0f,-1.0f,-1.0f);
 glVertex3f(-1.0f, 1.0f,-1.0f);
 glVertex3f( 1.0f, 1.0f,-1.0f);
 glColor3f(0.0f,0.0f,1.0f);
 glVertex3f(-1.0f, 1.0f, 1.0f);
 glVertex3f(-1.0f, 1.0f,-1.0f);
 glVertex3f(-1.0f,-1.0f,-1.0f);
 glVertex3f(-1.0f,-1.0f, 1.0f);
 glColor3f(1.0f,0.0f,1.0f);
 glVertex3f( 1.0f, 1.0f,-1.0f);
 glVertex3f( 1.0f, 1.0f, 1.0f);
 glVertex3f( 1.0f,-1.0f, 1.0f);
 glVertex3f( 1.0f,-1.0f,-1.0f);
 glEnd();
 glutSwapBuffers();
 }

We have changed the view point to be 1.5 units to the left and 10 units deep into the screen by using the glTranslate() function, then the cube is rotated 45 degrees around the y axis ( notice the order of glRotate and glTranslate, if you changed the order the result will be completely different, you are free to play with the code to see the difference). glBegin(GL_QUADS) draws the cube with its six faces by specifying its vertex coordinates. The output of the above code should be as shown in the Fig.5

If we need to make the cube rotating around a specified axis, we need to define a global variable for holding the angle of rotation and then changing the value of the angle every time you render the scene. To do that we have changed the render function to be as follow:

float rot=0.01; void render() 
{
 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 glLoadIdentity();
 glTranslatef(-1.5f,0.0f,-10.0f);
 glRotatef(rot++,0,1,0);
 rot=rot>=360?0:rot;
 //Draw your objects here
 glBegin(GL_QUADS);
 glColor3f(0.0f,1.0f,0.0f);
 glVertex3f( 1.0f, 1.0f,-1.0f);
 glVertex3f(-1.0f, 1.0f,-1.0f);
 glVertex3f(-1.0f, 1.0f, 1.0f);
 glVertex3f( 1.0f, 1.0f, 1.0f);
 glColor3f(1.0f,0.5f,0.0f);
 glVertex3f( 1.0f,-1.0f, 1.0f);
 glVertex3f(-1.0f,-1.0f, 1.0f);
 glVertex3f(-1.0f,-1.0f,-1.0f);
 glVertex3f( 1.0f,-1.0f,-1.0f);
 glColor3f(1.0f,0.0f,0.0f);
 glVertex3f( 1.0f, 1.0f, 1.0f);
 glVertex3f(-1.0f, 1.0f, 1.0f);
 glVertex3f(-1.0f,-1.0f, 1.0f);
 glVertex3f( 1.0f,-1.0f, 1.0f);
 glColor3f(1.0f,1.0f,0.0f);
 glVertex3f( 1.0f,-1.0f,-1.0f);
 glVertex3f(-1.0f,-1.0f,-1.0f);
 glVertex3f(-1.0f, 1.0f,-1.0f);
 glVertex3f( 1.0f, 1.0f,-1.0f);
 glColor3f(0.0f,0.0f,1.0f);
 glVertex3f(-1.0f, 1.0f, 1.0f);
 glVertex3f(-1.0f, 1.0f,-1.0f);
 glVertex3f(-1.0f,-1.0f,-1.0f);
 glVertex3f(-1.0f,-1.0f, 1.0f);
 glColor3f(1.0f,0.0f,1.0f);
 glVertex3f( 1.0f, 1.0f,-1.0f);
 glVertex3f( 1.0f, 1.0f, 1.0f);
 glVertex3f( 1.0f,-1.0f, 1.0f);
 glVertex3f( 1.0f,-1.0f,-1.0f);
 glEnd();
 glutSwapBuffers(); 
}

We have defined a variable called rot and we initialize its value to be 0.01 degrees. rot value will be changed in glRotatef(rot++,0,1,0); by increasing its value with 1, and then we check if rot reached the value 360 we reset it to 0 by the statement rot=rot>=360?0:rot; which literally means if (rot >= 360) rot=0; . The output of the above code will be the same cube but rotating around the y axis.

Fig. 5 drawing and rotating 3D cube

The source code:

To download the source code of this tutorial click here. If you have any comments or suggestions you are welcome to contact me mohandesosama(at thre rate of)yahoo.com