Graphics Programming with OpenGL

Course Notes #2 - "Simple Geometric Modeling"

Notes for 1/16/96

These notes are copyright (C) 1996, John D. DeCuir.

A Note about program structure

Please look on the back of the Assignment 1 handout - you'll find a page called "How to compile OpenGL apps under Visual C++ 2.0". (This is also on the web page). Even if you're not using Visual C++, I'd encourage you all to use this structure. It helps out a lot when you're separating different events.

Primitive Graphical Items

There are three basic operations that you can do on-screen:

A geometric object is an object defined by vertices, edges, and polygons. A raster object consists of (typically) a bitmap. The former is used when creating "geometry" (i.e. a cube representing a house). The latter is used for "texture". (i.e. what you see on the side of a house). We won't talk about texture and raster operations until the 2nd half of the course. We will be talking about the first two, and predominantly on the 2nd, for the rest of this half.

Clearing the Window

Clearing the window is usually a special command, because it is done predominantly in hardware. The reason we do it in hardware instead of in software is because if we clear the screen using a bunch of "clear" commands in software (which essentially just writes over the current buffer with a default color), we experience performance slowdowns and the infamous "flickering" effect. If we can clear buffers in hardware, this is guaranteed to be faster and it is treated as an atomic action, elimating the flickering effect.

To clear the screen in OpenGL, we must do two things:

To set the clear color, we use the OpenGL command glClearColor(); An example follows:

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

This command sets the clear color to be black. (0 red, 0 green, 0 blue, and 0 alpha).

After we set the clear color, we actually clear the screen with the glClear() command. However, we must insert a mask inside the function to tell OpenGL which buffer to clear. There are four buffers in OpenGL we can clear:

Don't worry about the last two for now. The color buffer is what holds the color information for every pixel on-screen - if we want to clear the screen, we obviously should clear this one. However, if we're working in 3D, we want to clear the depth buffer (known as a "z-buffer"). I'll talk about this more next week.

To use glClear, we use a bitwise-OR on all the bits we want to clear, like this:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

But in 2D, we just need to do this:

glClear(GL_COLOR_BUFFER_BIT);

Note that the following sequence:

glClear(GL_COLOR_BUFFER_BIT);

glClear(GL_DEPTH_BUFFER_BIT);

is not advisable, because it takes longer than if we had done a bitwise-OR on the masks.

Resizing the viewport

Whenever the user resizes the window, OpenGL executes our "myReshape" function. But because we have nothing in it now, OpenGL does nothing. So, when we resize the window, the original image will retain its original proportions. This means if you originally had a square in the middle of the screen, and you shrunk the window, the square would disappear off the upper right corner of the screen. (The origin of the window is on the lower left.)

To change the "viewport", or the space that OpenGL is allowed to draw in, we execute the glViewport() command. Typically, our myReshape function has two parameters: w and h. These are the sizes of the NEW window. So, inside this function, we would call:

glViewport(0, 0, w, h);

Please see the book (pg. 97) for more information on this command.

Flushing OpenGL commands to the server

Not everything is guaranteed to be drawn immediately. OpenGL is a client-server architecture. Because this is generic, the client and the server need not be on the same machine - they could be different machines on a network. (i.e. the GL commands we execute could be accumulating in a packet somewhere, but not sent yet.)

If we want to ensure that the commands do get sent to the server and the commands are drawn, we use glFlush() and glFinish(). The command glFlush() sends everything to the server, but does not wait for confirmation. The command glFinish() sends everything to the server, but blocks, waiting for confirmation from the server. Obviously, glFinish() will have a performance penalty. But maybe you'd want it if your network is questionable. (i.e. radio-based network on a battlefield. But whoever would be rendering in the middle of a war needs help I can't provide here.)

Note that even though you'll probably be using a single-machine client-server, get into the habit of using glFlush() at the end of all your programs. It's a good habit to learn.

Defining the Orthographic Projection

Whenever we set up a world in memory, we have to establish a "view". In the 2D world, this is simply a viewport on the world. Think of a map of the L.A. basin. If we want detail on a street, we don't look at the entire map. We instead define a viewport - a rectangular area on which we want to look - and show this. It's the same thing here - we must define a viewport on our 2D world.

There is a special command to do this in 2D worlds. (3D is another matter entirely, and will be discussed on week 3). It's gluOrtho2D(). This command takes 4 pieces of information - namely, the x and y coordinates of the two opposing corners of a rectangle which defines our viewport. (Rotated and skewed viewports are possible as well, but require transformations which aren't discussed until next week.)

gluOrtho2D(2.0f, 10.0f, 3.0f, 15.0f);

…sets up a viewport with vertices (2.0, 3.0) and (10.0, 15.0). Easy, huh?

Do not execute this command more than once. This command manipulates internal projection matrices, and executing this command more than once just doubles the effect. (in other words, the viewport will get bigger, and bigger, and bigger…) If you have a need for changing viewports, (for example animation), execute glLoadIdentity() beforehand. (This is an advanced topic and will be discussed week 3)

Points, Lines, and Polygons

A "point" is a vertex in 3D space. A "polygon" is a collection of edges, which are in turn collection of vertices. (Easy stuff.)

However, there are some restrictions that OpenGL places on polygons, in the interest of performance:

More commands to learn:

glColor…();

This command sets the current color. A whole slew of options can appear after the "color" part. Check the book for all the variations. One example is:

glColor3f(1.0f, 1.0f, 0.3f);

…sets the current color to be all red, all green, and a touch of blue.

glRect…();

This command draws a rectangle. Example:

glRectf(2.0f, 2.0f, 5.0f, 6.0f);

…draws a rectangle with corner vertices (2.0, 2.0) and (5.0, 6.0), in the current color.

glVertex…();

This command sets a vertex within a glBegin() and glEnd() sequence. An example:

glVertex3f(2.3f, 4.5f, 1.1f);

sets a vertex at (2.3, 4.5, 1.1) in 3D space.

glBegin(…) and glEnd()

These delimit a sequence of glVertex commands (among others.) We place one of the following in the glBegin parameter:

Example code fragment:

glBegin(GL_TRIANGLES);

glVertex2f(3.0f, 3.0f);

glVertex2f(5.0f, 3.0f);

glVertex2f(5.0f, 5.0f);

glVertex2f(6.0f, 4.0f);

glVertex2f(7.0f, 4.0f);

glVertex2f(7.0f, 7.0f);

glEnd();

…this sequence creates two triangles:

Of course, other C commands (loops, conditionals, etc.) can be issued within a glBegin/glEnd sequence. However, there is a restriction on other OpenGL commands. See the book for more information.

Normal Vectors

We can create normal vectors for each vertex (not face) by the glNormal() command. (This was just glossed over in class, so please read about this in the book.)

Hints on Modeling

These were also glossed over in class, but are also found in the book. Please see pgs. 54-56.

Class Project

A class project was given:

Object: Design an OpenGL program to draw 2 squares on-screen. The left square should be red; the right square should be blue. You can assume that gluOrtho2D(0.0, 10.0, 0.0, 10.0); has already been called.

The class came up with the following solution:

void CALLBACK display(void)

{

// Insert your OpenGL display code here.

// Don't forget glFlush() at the end.

glClearColor(0.0f, 0.0f, 0.0f, 0.0f);

glClear(GL_COLOR_BUFFER_BIT);

glColor3f(1.0f, 0.0f, 0.0f);

glRectf(1.0f, 1.0f, 3.0f, 3.0f);

glColor3f(0.0f, 0.0f, 1.0f);

glRectf(6.0f, 1.0f, 8.0f, 3.0f);

glFlush();

}

Assignment 2

Assignment 2 was distributed, which you can find on the web page. Note to lounge people: the CSUA lounge computer is temporarily out of commission, so your assignments will be postponed until it is fixed.

See you all week 3!

Jdd