At this point, most of you already have working code of your own, and I suggest you make any necessary change based on your own code. The entire source code, though, is still downloadable here
I will only cover those open GL topics which are necessary to help you make interesting interactive graphics applications. The source code from the red book, is available here. You can download and try it.
In our Canvas class, the eye (camera) defaults to (0, 0, hReso / 2), looking along negative z-direction, with up-direction (0,1,0). OpenGL has a similar default setting as ours, except the eye is at (0, 0, 0).
In our Canvas class, the viewing volume is an infinite pyramid, specified by the eye (0, 0, eye_at), and four corners of the canvas, which are (-hReso/2, -vReso/2, 0), (hReso)/2, -vReso/2, 0), (hReso/2, vReso/2, 0), (-hReso/2, vReso/2, 0).
In OpenGL, this infinite viewing volume is clipped by two planes, called near plane and far plane. One of the most commonly used way to specify an OpenGL viewing, is by a glu function call,
/* This specify a viewing volume of a truncated symmetrical pyramid with, the near plane: at z = -near of size tan(fov_y/2) * near * wh_ratio * 2 by tan(fov_y/2) * near * 2. the far plane: at z = -far, of size tan(fov_y/2) * far * wh_ratio * 2 by tan(fov_y/2) * far * 2. */ gluPerspective(fov_y, wh_ratio, near, far);
The answer is that there is not such a canvas at all. But you can image the canvas is the near plane, or the far plane, or any other plane parallel to them-- the point is that the exact position of the canvas does not matter. This is because OpenGL has one thing we do not have in our Canvas class, which is Viewport, and Viewport transformation.
To make an interactive graphics application, we need create a window using a GLUT function call.
... main_window = glutCreateWindow(argv[0]); // main_window assigned the integer value, which is the id of the created window.
We call this GLUT window.
The scene inside the 3D viewing volume is first projected onto the canvas (or the near plane, or the far plane, whichever you would like) and then mapped onto some (usually the entire) rectangle area inside the GLUT window. This rectangle area is called viewport.
glViewport(), shown below, creates a viewport inside the GLUT window, and defines consequently the viewport transformation.
/* This specify a rectangle area in the GLUT window opened in your computer screen, the rectangle is of size width by height, and its lowerleft corner is lowleft_x to the right of the lowerleft corner of the GLUT window, and is lowleft_y to the above of it. The viewport transformation will map the whole (projected) viewing volume onto this rectangle area. */ glViewport(int lowleft_x, int lowleft_y, (GLsizei) width, (GLsizei) height);
Although we can map the whole viewing volume to any portion of the GLUT window, we usually let the viewport to be the same as the entire GLUT window, which is typically done as in the following code,
void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); ... }
where reshape() is a callback function, which is called every time the shape of the GLUT window is changed, and is automatically given the current width and height of the GLUT window as its two arguments.
Also note, since the viewport transformation maps the entire projected viewing volume to the entire viewport, the mapping is usually not conformal, meaning the two rectangles are not similar, which in turn means the final image is squeezed or stretched. Again, the common practice is to make sure the viewport transformation is conformal, which is typically done as follow,
void reshape(int w, int h) { glViewport(0, 0, (GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fov_y, (GLfloat) w/(GLfloat) h, near, far); }
In the above code, the near plane (or far plane, or any canvas in some position) is specified as having the same ratio of width to height( also known as aspect ratio) as the current GLUT window, and consequently the image is not squeezed or stretched.
void display(void); // called whenever the window system finds the display in the GLUT window need to be updated.
void reshape(int w, int h); // called whenever the window system finds the shape of the GLUT window has been changed.
You are responsible to write the actual function bodies of these callback functions, and of course you have to tell the window system about the functions you have written, so that it can call back when necessary. This is done by a process called callback function registration, as follow,
glutDisplayFunc(display); glutReshapeFunc(reshape);
Here are some other possible callback functions which can be registered with window system.
glutKeyboardFunc(keyboard); // the registered function is called if (ascii)key pressed. glutMotionFunc(motion); // the registered function is called if mouse moved. glutMouseFunc(mouse); // the registered function is called if mouse pressed or released. glutSpecialFunc(specialKey); // like glutKeyboardFunc(keyboard), deals some with non-ascii keys.
The signatures of these callback functions are as follow,
void mouse(int button, int state, int x, int y) void keyboard(unsigned char key, int x, int y) void motion(int x, int y) void specialKey(int key, int x, int y)
We only have to know and use one of them, i.e., triangles.
glBegin(GL_TRIANGLES); { /* vertex data of the first triangle */ glVertex3f( x1, y1, z1 ); glVertex3f( x2, y2, z2 ); glVertex3f( x3, y3, z3 ); /* vertex data of the second triangle */ glVertex3f( x4, y4, z4 ); glVertex3f( x5, y5, z5 ); glVertex3f( x6, y6, z6 ); /* vertex data of the third triangle */ glVertex3f( x7, y7, z7 ); glVertex3f( x8, y8, z8 ); glVertex3f( x9, y9, z9 ); ... } glEnd();
The simplest way to assign color to each pixel is
The other common ways to get the color is by lighting computation and texture mapping, which we are going to talk later.Directly specify the color of each vertex. The pixels of the projected vertexes get the specified colors, and all other pixels get the color from interpolation.
The current color is one of the many states OpenGL has.
void glDraw() const; // simply draw all triangles with white color; to be changed later to support lighting and/or texture mapping.
1.3.6