Home   Donators   Contact Us       

<< Previous Tutorial     Next Tutorial >>

Tutorial 2 - Adding perspective


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.

Tutorial Steps
Tutorial created with Real Studio 2011 Release 4.3.
1. Open Real Studio.
2. Choose the "Desktop" project template.
3. Add an OpenGLSurface control to Window1.
4. Resize and position OpenGLSurface1 to fill the whole form.
5. Tick the LockRight and LockBottom properties of OpenGLSurface1. This is required to raise the Resized event and set up the perspective projection settings.
6. Add the following code to the Render event of OpenGLSurface1 (You can access the Render event by double clicking on OpenGLSurface1 and then selecting the event from the list):
OpenGL.glPushMatrix ' save matrix

' clear the background

OpenGL.glClearColor(0, 0, 0, 1)

' 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


' 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.glPopMatrix ' restore matrix
7. 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.gluPerspective 60.0, OpenGLSurface1.Width / OpenGLSurface1.Height, 1, 100.0

' select and reset the modelview matrix

OpenGL.glMatrixMode OpenGL.GL_MODELVIEW					
8. 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

9. Save and run the project.

Code Analysis

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?

Project Downloads

<< Previous Tutorial     Next Tutorial >>

All the content on Real 3D Tutorials, with the exception of the SyntaxHighlighter which is licensed under the MIT License, is provided to the public domain and everyone is free to use, modify, republish, sell or give away this work without prior consent from anybody. Content is provided without warranty of any kind. Under no circumstances shall the author(s) or contributor(s) be liable for damages resulting directly or indirectly from the use or non-use of the content.
Should you find the content useful and would like to make a contribution, you can show your support by making a donation.