An Introduction to Real-time Rendering Using OpenGL

Nick Lowe (nickl'at'csse.uwa.edu.au)

Displaying a Triangle

Next we'll draw a triangle on the plane z = 0. This triangle can be specified by the three points as shown in figure 1.

Drawing a triangle with OpenGL

In code this looks like:

  /* draw a triangle */
  glBegin(GL_TRIANGLES);
  glVertex3f(-2.0f, -1.0f, 0.0f);
  glVertex3f(0.0f, 2.0f, 0.0f);
  glVertex3f(2.0f, -1.0f, 0.0f);
  glEnd();

Add this to the the display callback function (_Draw). Compile and run the program. Oh no! No triangle! What's wrong? (read on)

Setting the camera viewport and perspective transformations

The correct OpenGL commands have now been sent to draw a triangle on the plane z = 0. However, nothing is visible. This is because the camera perspective and viewport transformations have not been set. Clearly, these transformations will change whenever the window is resized because the viewport should match the new window width and height and the perspective transformation should represent the new window aspect ratio. Modify the reshape callback to update these transformations:

static void _Reshape(int width, int height)
{
  /* set the viewport to the window width and height */
  glViewport(0, 0, width, height);
  
  /* load a projection matrix that matches the window aspect ratio */
  glMatrixMode(GL_PROJECTION);
  glLoadIdentity();
  gluPerspective(45.0, (double)width/(double)height, 1.0, 100.0);

  /* reset the modelview matrix */
  glMatrixMode(GL_MODELVIEW);
}

The important functions here are glViewport() and gluPerspective(). The gluPerspective() functions is part of GLU, the OpenGL Utility Library. See their man pages for more details (ie. type man glViewport in a terminal window). Still no triangle? Hmmmm...

Making the triangle come into view

The triangle is on the plane z = 0, but the default modelview matrix is the identity matrix. This represents a camera placed on the origin facing in the direction of -z. Since the near plane (set by the gluPerspective() function) is one unit in front of the camera, everything closer than the plane z = -1 is clipped away. This includes our triangle! So we can either move the triangle or move the camera. Choose a method to make the triangle visible, update your code where appropriate, and enjoy the view of your triangle.

If you choose to move the triangle, you can do so by changing the triangle's z coordinates. You can do this by modifing the input when defining the triangle:

  /* draw a triangle */
  glBegin(GL_TRIANGLES);
  glVertex3f(-2.0f, -1.0f, -10.0f);
  glVertex3f(0.0f, 2.0f, -10.0f);
  glVertex3f(2.0f, -1.0f, -10.0f);
  glEnd();

You can also do this by modifying the modelview matrix so that the triangle is rendered relative to a different coordinate space:

  glTranslatef(0.0f, 0.0f, -10.0f);

The complementary operation to moving the triangle away from the camera is to move the camera away from the triangle. To move the camera we can modify the modelview matrix using the gluLookAt function. Here is the code to place the camera at the point (0, 0, 10), looking at the origin (0, 0, 0), oriented such that the +y is up:

  gluLookAt(0.0, 0.0, 10.0, /* eye point */
            0.0, 0.0, 0.0,  /* reference point */
            0.0, 1.0, 0.0); /* up vector */
           

If you choose to modify the modelview matrix rather than modify the calls to glVertex you need to decide where to do so. If the modelview matrix needs to be updated each time the triangle is rendered you should do so in the _Draw function. If it needs to be updated on window resize, do so in the _Reshape function. Otherwise, if it does not change and only needs to be set once, set it in the _Init function.

Changing the colour of the triangle

If all has gone well, you should now have a white triangle in the middle of a window with a background colour of your choosing. You can change the colour of the triangle by using a call to the glColor() function:

  /* set vertex colour to blue */
  glColor3f(0.0f, 0.0f, 1.0f);

  /* draw a triangle */
  glBegin(GL_TRIANGLES);
  glVertex3f(-2.0f, -1.0f, -10.0f);
  glVertex3f(0.0f, 2.0f, -10.0f);
  glVertex3f(2.0f, -1.0f, -10.0f);
  glEnd();

In this example code, the vertex colour is set to blue and then the triangle is rendered. With each glVertex call the current vertex colour (blue) is used. You can also change the vertex colour between glVertex cals. This results in each vertex having a seperate colour. These colours are blended over the triangle. Try:

  /* draw a triangle */
  glBegin(GL_TRIANGLES);

  /* red vertex */
  glColor3f(1.0f, 0.0f, 0.0f);
  glVertex3f(-2.0f, -1.0f, 0.0f);

  /* green vertex */
  glColor3f(0.0f, 1.0f, 0.0f);
  glVertex3f(0.0f, 2.0f, 0.0f);

  /* blue vertex */
  glColor3f(0.0f, 0.0f, 1.0f);
  glVertex3f(2.0f, -1.0f, 0.0f);

  glEnd();

Set the vertex colours of your triangle to something that suits you. The end result should look something like this (without the jpeg compression artefacts):

Make sure that your program displays a triangle with different vertex colours before continuing. If it does not please ask for assistance from a demonstrator. If you still can't get your program to work, you can download a copy with all changes up to this point here.

Next: Animating a Teapot