3-D classroom: understanding OpenGL basics
So I got a chance to take up a course at my univeristy on computer graphics and I was exposed to OpenGL library. I decided to explore a bit about it and come up with a basic model of a classroom.
OpenGL is a software interface to graphics hardware. This interface consists of about 150 distinct commands that you use to specify the objects and operations needed to produce interactive three−dimensional applications. Basically OpenGL is nothing more than a set of functions you call from your program (think of it as a collection of .h files). It hides the details of the display adapter, operating system, etc. The API comprises of several libraries with varying levels of abstraction: GL, GLU and GLUT
Levels of abstraction:
GL: lowest level that includes vertex, matrix manipulations. Example: glVertex3f(point.x, point.y, point.z)
GLU: It consists of helper functions for shapes, transformations like gluPerspective(fovy, aspect, near, far)
GLUT: the highest level that deals with window and interface management.
OpenGL is an API, hence we include the header files of it in our program:
The explanation of the code and implementation goes something like this:
The entire classroom is implemented using simple cubes and simple scaling to turn them into cuboids. The cuboids were used to construct tabels and chairs. Perspective projection was used to construct the classroom. The world rotates while the camera is fixed.
GLUT Setup - main()
The program contains a myinit(), drawcube(), drawchair(), drawclassroom(), keyfunc(), display() functions.
The main() program:
glutInit(&argc, argv);Initializes the GLUT.
glutInitWindowSize(900, 700);glutCreateWindow("3D classroom");Creates a window with a title, initial width and height positioned at initial top-left corner.
glutDisplayFunc(display);Registers display() as the re-paint event handler. That is, the graphics sub-system calls back display() when the window first appears and whenever there is a re-paint request.
glutKeyboardFunc(keyfunc);glutKeyboardFunc sets the keyboard callback for the current window. When a user types into the window, each key press generating an ASCII character will generate a keyboard callback. The key callback parameter is the generated ASCII character. The state of modifier keys such as Shift cannot be determined directly; their only effect will be on the returned ASCII data.
myinit();Invokes the myinit() once to perform all one-time initialization tasks.
glutMainLoop();Finally, enters the event-processing loop.
One-Time Initialization Operations - myinit()
The myinit() function performs the one-time initialization tasks. It is invoked from main() once (and only once).
glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // Set background color to black and opaque
glEnable(GL_COLOR_MATERIAL); // If enabled, have one or more material parameters track the current color
glEnable(GL_NORMALIZE); //If enabled and no vertex shader is active, normal vectors are normalized to unit length after transformation and before lighting.
glEnable(GL_DEPTH_TEST); // Enable depth testing for z-culling
glDepthFunc(GL_LESS); // Set the type of depth-test
We need to enable depth-test to remove the hidden surface, and set the function used for the depth test.
Defining the chairs, classroom, board, door etc.
OpenGL's object is made up of primitives (such as triangle, quad, polygon, point and line). A primitive is defined via one or more vertices. The color-cube is made up of 6 quads. Each quad is made up of 4 vertices, defined in counter-clockwise (CCW) order, such as the normal vector is pointing out, indicating the front face. All the 4 vertices have the same color.
The objects are defined in their local spaces (model spaces). We need to transform them to the common world space, known as model transform.
To perform model transform, we need to operate on the so-called model-view matrix (OpenGL has a few transformation matrices), by setting the current matrix mode to model-view matrix:
glMatrixMode(GL_MODELVIEW); // To operate on model-view matrix
glLoadIdentity(); // Reset model-view matrixFor example:
glTranslatef(1.5f, 0.0f, -7.0f); // Move right and into the screen
The default camera position is:
gluLookAt(0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, 1.0, 0.0)
That is, EYE=(0,0,0) at the origin, AT=(0,0,-1) pointing at negative-z axis (into the screen), and UP=(0,1,0) corresponds to y-axis.
OpenGL graphics rendering pipeline performs so-called view transform to bring the world space to camera's view space.
glMatrixMode(GL_PROJECTION); // To operate on the Projection matrix
glLoadIdentity(); // Reset
gluPerspective(70.0f,1,0.1,2000); // Perspective projection: fovy, aspect, near, far A camera has limited field of view. The projection models the view captured by the camera. There are two types of projection: perspective projection and orthographic projection. In perspective projection, object further to the camera appears smaller compared with object of the same size nearer to the camera. In orthographic projection, the objects appear the same regardless of the z-value. Orthographic projection is a special case of perspective projection where the camera is placed very far away.
To set the projection, we need to operate on the projection matrix. (Recall that we operated on the model-view matrix in model transform.)
We set the matrix mode to projection matrix and reset the matrix. We use the gluPerspective() to enable perspective projection, and set the fovy (view angle from the bottom-plane to the top-plane), aspect ratio (width/height), zNear and zFar.
Enough of the theorey part now, you might want to check out the implementation now: