Perspective projection is a technique that is used to "paint" a scene in your 3D world onto a 2D surface such as a computer screen. It is responsible for making objects closer to you appear bigger than objects far away in the distance.
With OpenGL we are in the lucky position that a group of very smart computer scientists already took the time to work through all the complex mathematics used for perspective projection. All we need to do, is to set up the projection settings and OpenGL will automatically do the hard work for us.
The diagram above illustrates the idea behind perspective projection. As you can see, the virtual 3D models are mapped to a 2D surface such as your computer screen. Humans have an almost 180-degree forward-facing horizontal field of view. Some birds have a near-complete 360-degree field of view.
OpenGL.glPushMatrix ' save matrix ' clear the background OpenGL.glClearColor(0, 0, 0, 1) OpenGL.glClear(OpenGL.GL_COLOR_BUFFER_BIT) ' move back a bit so that we can see the object OpenGL.glTranslatef 0.0, 0.0, -5.0 ' draw a polygon close to us OpenGL.glBegin OpenGL.GL_POLYGON OpenGL.glVertex3d -1, 1, 1 OpenGL.glVertex3d -2, 0, 1 OpenGL.glVertex3d 0, 0, 1 OpenGL.glEnd ' draw a polygon far from us OpenGL.glBegin OpenGL.GL_POLYGON OpenGL.glVertex3d 1.5, 1, -3 OpenGL.glVertex3d 0.5, 0, -3 OpenGL.glVertex3d 2.5, 0, -3 OpenGL.glEnd OpenGL.glPopMatrix ' restore matrix7. Add the following code to the Resized event of OpenGLSurface1 (You can access the Resized event by double clicking on OpenGLSurface1 and then selecting the event from the list):
' set the viewport rectangle OpenGL.glViewport 0, 0, OpenGLSurface1.Width, OpenGLSurface1.Height ' set up the perspective projection settings OpenGL.glMatrixMode OpenGL.GL_PROJECTION OpenGL.glLoadIdentity OpenGL.gluPerspective 60.0, OpenGLSurface1.Width / OpenGLSurface1.Height, 1, 100.0 ' select and reset the modelview matrix OpenGL.glMatrixMode OpenGL.GL_MODELVIEW OpenGL.glLoadIdentity8. Add the following code to the Paint event of Window1 (You can access the Paint event by double clicking on the titlebar of Window1 and then selecting the event from the list):
' refresh the OpenGL surface OpenGLSurface1.Render9. Save and run the project.
In the Render event we start by saving the current OpenGL matrix using glPushMatrix. For now you don't have to worry about what the matrix is. Just take note that we save it at the start of our drawing routine and restore it again with a call to glPopMatrix, at the end of our drawing routine.
The rest of the code in the Render event is similar to the code in Tutorial 1, with the only difference being that two polygons are drawn instead of just one. The interesting thing about these two polygons are that they have exactly the same area size.
You might be asking at this point, why then do the one polygon appear to be larger than the other polygon? The answer to this question is straight forward. The secret is in how we configure the perspective projection settings in the Resized event. The perspective settings will make polygons closer to you appear larger than objects in the distance. If you look closely at the z-values of the first polygon you will notice they are all set to 1. All the z-values of the second polygon is set to -3. The deeper you go into the screen, the smaller the z-values become. This explains why the second polygon appears to be smaller, because of its z-values.
So how is the perspective projection settings configured in the Resized event?
First we set up a viewport into our virtual 3D world by calling the glViewport function. Think of the viewport as a window through which you look into your world. The values x, y, width and height are passed to glViewport. x and y specifies the lower left corner of the viewport rectangle (window). width and height specifies the width and the height of the viewport rectangle (window).
OpenGL uses different modes to work with different aspects of the 3D mathematics. The two modes that is most commonly used is the GL_PROJECTION mode and the GL_MODELVIEW mode.
We switch the GL_PROJECTION mode by calling the glMatrixMode function with the GL_PROJECTION parameter. The GL_PROJECTION mode is used to set up our camera (perspective projection). With a call to glLoadIdentity we first "reset" the current perspective projection settings so that we can set up our own settings. Now we call gluPerspective to set up our perspective projection settings (camera). The parameters passed to gluPerspective is the fovy in degrees that specifies the field of view in the y direction, the aspect that determines the field of view in the x direction, zNear that specifies the distance from the viewer to the near clipping plane (always positive), and zFar that specifies the distance from the viewer to the far clipping plane (always positive).
Finally we switch to the GL_MODELVIEW mode, which is the mode we need to be in when we draw our polygons and objects. As with the GL_PROJECTION mode we "reset" the GL_MODELVIEW mode with a call to glLoadIdentity.
Whenever we now instruct OpenGL to draw polygons, the polygons will be drawn with the perspective projection settings that we configured. The perspective projection settings only need to be configured once when the size of our OpenGL surface changes, therefore the reason why we do so in the OpenGLSurface1.Resized event.
Experiment with the z-values. What happens when you set the z-values of the second polygon to -1?