Affine Geometry and Homogeneous Coordinates: Lecture Notes for CMSC 427 - Prof. David M. M, Study notes of Computer Graphics

Lecture notes on affine geometry and homogeneous coordinates as covered in the cmsc 427 course. Topics include the distinction between points and vectors, affine combinations, coordinate frames, change of coordinates, and the use of homogeneous coordinates for ideal points and camera transformations.

Typology: Study notes

Pre 2010

Uploaded on 02/13/2009

koofers-user-emk
koofers-user-emk 🇺🇸

10 documents

1 / 131

Toggle sidebar

This page cannot be seen from the preview

Don't miss anything!

bg1
CMSC 427
Computer Graphics1
David M. Mount
Department of Computer Science
University of Maryland
Spring 2004
1Copyright, David M. Mount, 2004, Dept. of Computer Science, University of Maryland, College Park, MD, 20742. These lecture notes were
prepared by David Mount for the course CMSC 427, Computer Graphics, at the University of Maryland. Permission to use, copy, modify, and
distribute these notes for educational purposes and without fee is hereby granted, provided that this copyright notice appear in all copies.
Lecture Notes 1 CMSC 427
pf3
pf4
pf5
pf8
pf9
pfa
pfd
pfe
pff
pf12
pf13
pf14
pf15
pf16
pf17
pf18
pf19
pf1a
pf1b
pf1c
pf1d
pf1e
pf1f
pf20
pf21
pf22
pf23
pf24
pf25
pf26
pf27
pf28
pf29
pf2a
pf2b
pf2c
pf2d
pf2e
pf2f
pf30
pf31
pf32
pf33
pf34
pf35
pf36
pf37
pf38
pf39
pf3a
pf3b
pf3c
pf3d
pf3e
pf3f
pf40
pf41
pf42
pf43
pf44
pf45
pf46
pf47
pf48
pf49
pf4a
pf4b
pf4c
pf4d
pf4e
pf4f
pf50
pf51
pf52
pf53
pf54
pf55
pf56
pf57
pf58
pf59
pf5a
pf5b
pf5c
pf5d
pf5e
pf5f
pf60
pf61
pf62
pf63
pf64

Partial preview of the text

Download Affine Geometry and Homogeneous Coordinates: Lecture Notes for CMSC 427 - Prof. David M. M and more Study notes Computer Graphics in PDF only on Docsity!

CMSC 427

Computer Graphics

David M. Mount

Department of Computer Science

University of Maryland

Spring 2004

(^1) Copyright, David M. Mount, 2004, Dept. of Computer Science, University of Maryland, College Park, MD, 20742. These lecture notes were prepared by David Mount for the course CMSC 427, Computer Graphics, at the University of Maryland. Permission to use, copy, modify, and distribute these notes for educational purposes and without fee is hereby granted, provided that this copyright notice appear in all copies.

Lecture 1: Course Introduction

Reading: Chapter 1 in Hearn and Baker.

Computer Graphics: Computer graphics is concerned with producing images and animations (or sequences of im- ages) using a computer. This includes the hardware and software systems used to make these images. The task of producing photo-realistic images is an extremely complex one, but this is a field that is in great demand because of the nearly limitless variety of applications. The field of computer graphics has grown enormously over the past 10–20 years, and many software systems have been developed for generating computer graphics of various sorts. This can include systems for producing 3-dimensional models of the scene to be drawn, the rendering software for drawing the images, and the associated user-interface software and hardware. Our focus in this course will not be on how to use these systems to produce these images (you can take courses in the art department for this), but rather in understanding how these systems are constructed, and the underlying mathematics, physics, algorithms, and data structures needed in the construction of these systems. The field of computer graphics dates back to the early 1960’s with Ivan Sutherland, one of the pioneers of the field. This began with the development of the (by current standards) very simple software for performing the necessary mathematical transformations to produce simple line-drawings of 2- and 3-dimensional scenes. As time went on, and the capacity and speed of computer technology improved, successively greater degrees of realism were achievable. Today it is possible to produce images that are practically indistinguishable from photographic images (or at least that create a pretty convincing illusion of reality).

Course Overview: Given the state of current technology, it would be possible to design an entire university major to cover everything (important) that is known about computer graphics. In this introductory course, we will attempt to cover only the merest fundamentals upon which the field is based. Nonetheless, with these funda- mentals, you will have a remarkably good insight into how many of the modern video games and “Hollywood” movie animations are produced. This is true since even very sophisticated graphics stem from the same basic elements that simple graphics do. They just involve much more complex light and physical modeling, and more sophisticated rendering techniques. In this course we will deal primarily with the task of producing a single image from a 2- or 3-dimensional scene model. This is really a very limited aspect of computer graphics. For example, it ignores the role of computer graphics in tasks such as visualizing things that cannot be described as such scenes. This includes rendering of technical drawings including engineering charts and architectural blueprints, and also scientific visualization such as mathematical functions, ocean temperatures, wind velocities, and so on. We will also ignore many of the issues in producing animations. We will produce simple animations (by producing lots of single images), but issues that are particular to animation, such as motion blur, morphing and blending, temporal anti-aliasing, will not be covered. They are the topic of a more advanced course in graphics. Let us begin by considering the process of drawing (or rendering ) a single image of a 3-dimensional scene. This is crudely illustrated in the figure below. The process begins by producing a mathematical model of the object to be rendered. Such a model should describe not only the shape of the object but its color, its surface finish (shiny, matte, transparent, fuzzy, scaly, rocky). Producing realistic models is extremely complex, but luckily it is not our main concern. We will leave this to the artists and modelers. The scene model should also include information about the location and characteristics of the light sources (their color, brightness), and the atmospheric nature of the medium through which the light travels (is it foggy or clear). In addition we will need to know the location of the viewer. We can think of the viewer as holding a “synthetic camera”, through which the image is to be photographed. We need to know the characteristics of this camera (its focal length, for example). Based on all of this information, we need to perform a number of steps to produce our desired image.

Projection: Project the scene from 3-dimensional space onto the 2-dimensional image plane in our synthetic camera.

Ray tracing: Ray-tracing model, reflective and transparent objects, shadows. Color: Gamma-correction, halftoning, and color models.

Although this order represents a “reasonable” way in which to present the material. We will present the topics in a different order, mostly to suit our need to get material covered before major programming assignments.

Lecture 2: Graphics Systems and Models

Reading: Today’s material is covered roughly in Chapters 2 and 4 of our text. We will discuss the drawing and filling algorithms of Chapter 4, and OpenGL commands later in the semester.

Elements of Pictures: Computer graphics is all about producing pictures (realistic or stylistic) by computer. Before discussing how to do this, let us first consider the elements that make up images and the devices that produce them. How are graphical images represented? There are four basic types that make up virtually of computer generated pictures: polylines , filled regions , text , and raster images.

Polylines: A polyline (or more properly a polygonal curve is a finite sequence of line segments joined end to end. These line segments are called edges , and the endpoints of the line segments are called vertices. A single line segment is a special case. (An infinite line, which stretches to infinity on both sides, is not usually considered to be a polyline.) A polyline is closed if it ends where it starts. It is simple if it does not self-intersect. Self-intersections include such things as two edge crossing one another, a vertex intersecting in the interior of an edge, or more than two edges sharing a common vertex. A simple, closed polyline is also called a simple polygon. If all its internal angle are at most 180 ◦, then it is a convex polygon. A polyline in the plane can be represented simply as a sequence of the (x, y) coordinates of its vertices. This is sufficient to encode the geometry of a polyline. In contrast, the way in which the polyline is rendered is determined by a set of properties call graphical attributes. These include elements such as color , line width , and line style (solid, dotted, dashed), how consecutive segments are joined (rounded, mitered or beveled; see the book for further explanation).

Closed polyline Simple polyline

No joint

Simple polygon Convex polygon

Mitered Rounded Beveled

Fig. 2: Polylines and joint styles.

Many graphics systems support common special cases of curves such as circles, ellipses, circular arcs, and Bezier and B-splines. We should probably include curves as a generalization of polylines. Most graphics drawing systems implement curves by breaking them up into a large number of very small polylines, so this distinction is not very important. Filled regions: Any simple, closed polyline in the plane defines a region consisting of an inside and outside. (This is a typical example of an utterly obvious fact from topology that is notoriously hard to prove. It is called the Jordan curve theorem .) We can fill any such region with a color or repeating pattern. In some instances the bounding polyline itself is also drawn and others the polyline is not drawn.

A polyline with embedded “holes” also naturally defines a region that can be filled. In fact this can be generalized by nesting holes within holes (alternating color with the background color). Even if a polyline is not simple, it is possible to generalize the notion of interior. Given any point, shoot a ray to infinity. If it crosses the boundary an odd number of times it is colored. If it crosses an even number of times, then it is given the background color.

with boundary without boundary with holes self intersecting

Fig. 3: Filled regions.

Text: Although we do not normally think of text as a graphical output, it occurs frequently within graphical images such as engineering diagrams. Text can be thought of as a sequence of characters in some font. As with polylines there are numerous attributes which affect how the text appears. This includes the font’s face (Times-Roman, Helvetica, Courier, for example), its weight (normal, bold, light), its style or slant (normal, italic, oblique, for example), its size , which is usually measured in points , a printer’s unit of measure equal to 1 / 72 -inch), and its color.

12 point

10 point

8 point

Face (family) Size

Courier

Times−Roman

Helvetica Bold

Normal

Weight

Italic

Normal

Style (slant)

Fig. 4: Text font properties.

Raster Images: Raster images are what most of us think of when we think of a computer generated image. Such an image is a 2-dimensional array of square (or generally rectangular) cells called pixels (short for “picture elements”). Such images are sometimes called pixel maps. The simplest example is an image made up of black and white pixels, each represented by a single bit ( for black and 1 for white). This is called a bitmap. For gray-scale (or monochrome ) raster images raster images, each pixel is represented by assigning it a numerical value over some range (e.g., from 0 to 255, ranging from black to white). There are many possible ways of encoding color images. We will discuss these further below.

Graphics Devices: The standard interactive graphics device today is called a raster display. As with a television, the display consists of a two-dimensional array of pixels. There are two common types of raster displays.

Video displays: consist of a screen with a phosphor coating, that allows each pixel to be illuminated momen- tarily when struck by an electron beam. A pixel is either illuminated (white) or not (black). The level of intensity can be varied to achieve arbitrary gray values. Because the phosphor only holds its color briefly, the image is repeatedly rescanned, at a rate of at least 30 times per second. Liquid crystal displays (LCD’s): use an electronic field to alter polarization of crystalline molecules in each pixel. The light shining through the pixel is already polarized in some direction. By changing the polar- ization of the pixel, it is possible to vary the amount of light which shines through, thus controlling its intensity.

transmitter

TMDS

monitor

cursor

port

input

Analog

Video stream

Video

monitor

Digital

Graphics port

Video I/O interface

Renderer Renderer

2−d Engine

Host bus interface

Hardware DVD/ HDTV

stream Scaler YUV/ RGB

Texture units

Vertex skinning (^) cache

cache

Texture

z−buffer

Graphics

overlay control expander

Ratiometric

D/A converter

Triangle setup

Keyframe interpolation

Transform, clip, lighting

double data−rate memory

Synchronous DRAM or

3−d Engine

Display engine

Command engine

Pallette and

decoder

Video Engine

YUV to RGB

Scaler

VGA graphics controller

Memory controller and interface

cache

Pixel

Vertex

Fig. 6: The architecture of a sample graphics accelerator.

Color: The method chosen for representing color depends on the characteristics of the graphics output device (e.g., whether it is additive as are video displays or subtractive as are printers). It also depends on the number of bits per pixel that are provided, called the pixel depth. For example, the most method used currently in video and color LCD displays is a 24-bit RGB representation. Each pixel is represented as a mixture of red, green and blue components, and each of these three colors is represented as a 8-bit quantity (0 for black and 255 for the brightest color). In many graphics systems it is common to add a fourth component, sometimes called alpha , denoted A. This component is used to achieve various special effects, most commonly in describing how opaque a color is. We will discuss its use later in the semester. For now we will ignore it. In some instances 24-bits may be unacceptably large. For example, when downloading images from the web, 24-bits of information for each pixel may be more than what is needed. A common alternative is to used a color map , also called a color look-up-table (LUT). (This is the method used in most gif files, for example.) In a typical instance, each pixel is represented by an 8-bit quantity in the range from 0 to 255. This number is an index to a 256-element array, each of whose entries is a 234-bit RGB value. To represent the image, we store both the LUT and the image itself. The 256 different colors are usually chosen so as to produce the best possible reproduction of the image. For example, if the image is mostly blue and red, the LUT will contain many more blue and red shades than others. A typical photorealistic image contains many more than 256 colors. This can be overcome by a fair amount of clever trickery to fool the eye into seeing many shades of colors where only a small number of distinct colors exist. This process is called digital halftoning , as shown in Fig. 8. Colors are approximated by putting combinations of similar colors in the same area. The human eye averages them out.

154 247

Frame buffer R^ G^ B

122

121

124 125

Colormap

031

176 002 123

123015

Fig. 7: Color-mapped color.

Fig. 8: Color approximation by digital halftoning. (Note that you are probably not seeing the true image, since has already been halftoned by your document viewer or printer.)

Display Mode Meaning GLUT RGB Use RGB colors GLUT RGBA Use RGB plus α (for transparency) GLUT INDEX Use colormapped colors (not recommended) GLUT DOUBLE Use double buffering (recommended) GLUT SINGLE Use single buffering (not recommended) GLUT DEPTH Use depth buffer (needed for hidden surface removal)

Table 1: Arguments to glutInitDisplayMode(). .

Color: First off, we need to tell the system how colors will be represented. There are three methods, of which two are fairly commonly used: GLUT RGB or GLUT RGBA. The first uses standard RGB colors (24-bit color, consisting of 8 bits of red, green, and blue), and is the default. The second requests RGBA coloring. In this color system there is a fourth component (A or α), which indicates the opaqueness of the color (1 = fully opaque, 0 = fully transparent). This is useful in creating transparent effects. We will discuss how this is applied later this semester. Single or Double Buffering: The next option specifies whether single or double buffering is to be used, GLUT SINGLE or GLUT DOUBLE, respectively. To explain the difference, we need to understand a bit more about how the frame buffer works. In raster graphics systems, whatever is written to the frame buffer is immediately transferred to the display. (Recall this from Lecture 2.) This process is repeated frequently, say 30– times a second. To do this, the typical approach is to first erase the old contents by setting all the pixels to some background color, say black. After this, the new contents are drawn. However, even though it might happen very fast, the process of setting the image to black and then redrawing everything produces a noticeable flicker in the image. Double buffering is a method to eliminate this flicker. In double buffering, the system maintains two separate frame buffers. The front buffer is the one which is displayed, and the back buffer is the other one. Drawing is always done to the back buffer. Then to update the image, the system simply swaps the two buffers. The swapping process is very fast, and appears to happen instantaneously (with no flicker). Double buffering requires twice the buffer space as single buffering, but since memory is relatively cheap these days, it is the preferred method for interactive graphics. Depth Buffer: One other option that we will need later with 3-dimensional graphics will be hidden surface removal. This fastest and easiest (but most space-consuming) way to do this is with a special array called a depth buffer. We will discuss in greater detail later, but intuitively this is a 2-dimensional array which stores the distance (or depth) of each pixel from the viewer. This makes it possible to determine which surfaces are closest, and hence visible, and which are farther, and hence hidden. The depth buffer is enabled with the option GLUT DEPTH. For this program it is not needed, and so has been omitted. glutInitWindowSize(): This command specifies the desired width and height of the graphics window. The general form is glutInitWindowSize(int width, int height). The values are given in numbers of pixels. glutInitPosition(): This command specifies the location of the upper left corner of the graphics window. The form is glutInitWindowPosition(int x, int y) where the (x, y) coordinates are given relative to the upper left corner of the display. Thus, the arguments (0, 0) places the window in the upper left corner of the display. Note that glutInitWindowSize() and glutInitWindowPosition() are both considered to be only suggestions to the system as to how to where to place the graphics window. Depending on the window system’s policies, and the size of the display, it may not honor these requests. glutCreateWindow(): This command actually creates the graphics window. The general form of the command is glutCreateWindowchar(*title), where title is a character string. Each window has a title, and the argument is a string which specifies the window’s title. We pass in argv[0]. In Unix argv[0] is the name of the program (the executable file name) so our graphics window’s name is the same as the name of our program.

Note that glutCreateWindow() does not really create the window, but rather sends a request to the system that the window be created. Thus, it is not possible to start sending output to the window, until notification has been received that this window is finished its creation. This is done by a display event callback, which we describe below.

Event-driven Programming and Callbacks: Virtually all interactive graphics programs are event driven. Unlike traditional programs that read from a standard input file, a graphics program must be prepared at any time for input from any number of sources, including the mouse, or keyboard, or other graphics devises such as trackballs and joysticks. In OpenGL this is done through the use of callbacks. The graphics program instructs the system to invoke a particular procedure whenever an event of interest occurs, say, the mouse button is clicked. The graphics program indicates its interest, or registers , for various events. This involves telling the window system which event type you are interested in, and passing it the name of a procedure you have written to handle the event.

Types of Callbacks: Callbacks are used for two purposes, user input events and system events. User input events include things such as mouse clicks, the motion of the mouse (without clicking) also called passive motion , keyboard hits. Note that your program is only signaled about events that happen to your window. For example, entering text into another window’s dialogue box will not generate a keyboard event for your program. There are a number of different events that are generated by the system. There is one such special event that every OpenGL program must handle, called a display event. A display event is invoked when the system senses that the contents of the window need to be redisplayed, either because:

  • the graphics window has completed its initial creation,
  • an obscuring window has moved away, thus revealing all or part of the graphics window,
  • the program explicitly requests redrawing, by calling glutPostRedisplay().

Recall from above that the command glutCreateWindow() does not actually create the window, but merely re- quests that creation be started. In order to inform your program that the creation has completed, the system generates a display event. This is how you know that you can now start drawing into the graphics window. Another type of system event is a reshape event. This happens whenever the window’s size is altered. The callback provides information on the new size of the window. Recall that your initial call to glutInitWindowSize() is only taken as a suggestion of the actual window size. When the system determines the actual size of your window, it generates such a callback to inform you of this size. Typically, the first two events that the system will generate for any newly created window are a reshape event (indicating the size of the new window) followed immediately by a display event (indicating that it is now safe to draw graphics in the window). Often in an interactive graphics program, the user may not be providing any input at all, but it may still be necessary to update the image. For example, in a flight simulator the plane keeps moving forward, even without user input. To do this, the program goes to sleep and requests that it be awakened in order to draw the next image. There are two ways to do this, a timer event and an idle event. An idle event is generated every time the system has nothing better to do. This may generate a huge number of events. A better approach is to request a timer event. In a timer event you request that your program go to sleep for some period of time and that it be “awakened” by an event some time later, say 1/30 of a second later. In glutTimerFunc() the first argument gives the sleep time as an integer in milliseconds and the last argument is an integer identifier, which is passed into the callback function. Various input and system events and their associated callback function prototypes are given in Table 2. For example, the following code fragment shows how to register for the following events: display events, reshape events, mouse clicks, keyboard strikes, and timer events. The functions like myDraw() and myReshape() are supplied by the user, and will be described later. Most of these callback registrations simply pass the name of the desired user function to be called for the corresponding event. The one exception is glutTimeFunc() whose arguments are the number of milliseconds to

Examples of Callback Functions for User Input Events // called if mouse click void myMouse(int b, int s, int x, int y) { switch (b) { // b indicates the button case GLUT_LEFT_BUTTON: if (s == GLUT_DOWN) // button pressed // ... else if (s == GLUT_UP) // button released // ... break; // ... // other button events } } // called if keyboard key hit void myKeyboard(unsigned char c, int x, int y) { switch (c) { // c is the key that is hit case ’q’: // ’q’ means quit exit(0); break; // ... // other keyboard events } }

event callback passes in the new window width and height. A mouse click callback passes in four arguments, which button was hit (b: left, middle, right), what the buttons new state is (s: up or down), the (x, y) coordinates of the mouse when it was clicked (in pixels). The various parameters used for b and s are described in Table 3. A keyboard event callback passes in the character that was hit and the current coordinates of the mouse. The timer event callback passes in the integer identifier, of the timer event which caused the callback. Note that each call to glutTimerFunc() creates only one request for a timer event. (That is, you do not get automatic repetition of timer events.) If you want to generate events on a regular basis, then insert a call to glutTimerFunc() from within the callback function to generate the next one.

GLUT Parameter Name Meaning GLUT LEFT BUTTON left mouse button GLUT MIDDLE BUTTON middle mouse button GLUT RIGHT BUTTON right mouse button GLUT DOWN mouse button pressed down GLUT UP mouse button released

Table 3: GLUT parameter names associated with mouse events.

Lecture 4: Drawing in OpenGL: Drawing and Viewports

Reading: Chapters 2 and 3 in Hearn and Baker.

Basic Drawing: We have shown how to create a window, how to get user input, but we have not discussed how to get graphics to appear in the window. Today we discuss OpenGL’s capabilities for drawing objects. Before being able to draw a scene, OpenGL needs to know the following information: what are the objects to be drawn, how is the image to be projected onto the window, and how lighting and shading are to be performed.

To begin with, we will consider a very the simple case. There are only 2-dimensional objects, no lighting or shading. Also we will consider only relatively little user interaction. Because we generally do not have complete control over the window size, it is a good idea to think in terms of drawing on a rectangular idealized drawing region , whose size and shape are completely under our control. Then we will scale this region to fit within the actual graphics window on the display. More generally, OpenGL allows for the grahics window to be broken up into smaller rectangular subwindows, called viewports. We will then have OpenGL scale the image drawn in the idealized drawing region to fit within the viewport. The main advantage of this approach is that it is very easy to deal with changes in the window size. We will consider a simple drawing routine for the picture shown in the figure. We assume that our idealized drawing region is a unit square over the real interval [0, 1] × [0, 1]. (Throughout the course we will use the notation [a, b] to denote the interval of real values z such that a ≤ z ≤ b. Hence, [0, 1] × [0, 1] is a unit square whose lower left corner is the origin.) This is illustrated in Fig. 9.

1

0 0.5 1

red

blue

0

Fig. 9: Drawing produced by the simple display function.

Glut uses the convention that the origin is in the upper left corner and coordinates are given as integers. This makes sense for Glut, because its principal job is to communicate with the window system, and most window systems (X-windows, for example) use this convention. On the other hand, OpenGL uses the convention that coordinates are (generally) floating point values and the origin is in the lower left corner. Recalling the OpenGL goal is to provide us with an idealized drawing surface, this convention is mathematically more elegant.

The Display Callback: Recall that the display callback function is the function that is called whenever it is necessary to redraw the image, which arises for example:

  • The initial creation of the window,
  • Whenever the window is uncovered by the removal of some overlapping window,
  • Whenever your program requests that it be redrawn (through the use of glutPostRedisplay() function, as in the case of an animation, where this would happen continuously.

The display callback function for our program is shown below. We first erase the contents of the image window, then do our drawing, and finally swap buffers so that what we have drawn becomes visible. (Recall double buffering from the previous lecture.) This function first draws a red diamond and then (on top of this) it draws a blue rectangle. Let us assume double buffering is being performed, and so the last thing to do is invoke glutSwapBuffers() to make everything visible. Let us present the code, and we will discuss the various elements of the solution in greater detail below.

Clearing the Window: The command glClear() clears the window, by overwriting it with the background color. This is set by the call

glClearColor(GLfloat Red, GLfloat Green, GLfloat Blue, GLfloat Alpha).

floats and doubles, the arguments range from 0 (no intensity) to 1 (full intensity). For integer types (byte, short, int, long) the input is assumed to be in the range from 0 (no intensity) to its maximum possible positive value (full intensity). But that is not all! The three argument versions assume RGB color. If we were using RGBA color instead, we would use glColor4d() variant instead. Here “4” signifies four arguments. (Recall that the A or alpha value is used for various effects, such an transparency. For standard (opaque) color we set A = 1. 0 .) In some cases it is more convenient to store your colors in an array with three elements. The suffix “v” means that the argument is a vector. For example glColor3dv() expects a single argument, a vector containing three GLdouble’s. (Note that this is a standard C/C++ style array, not the class vector from the C++ Standard Template Library.) Using C’s convention that a vector is represented as a pointer to its first element, the corresponding argument type would be “const GLdouble*”. Whenever you look up the prototypes for OpenGL commands, you often see a long list, some of which are shown below.

void glColor3d(GLdouble red, GLdouble green, GLdouble blue) void glColor3f(GLfloat red, GLfloat green, GLfloat blue) void glColor3i(GLint red, GLint green, GLint blue) ... (and forms for byte, short, unsigned byte and unsigned short) ...

void glColor4d(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha) ... (and 4-argument forms for all the other types) ...

void glColor3dv(const GLdouble *v) ... (and other 3- and 4-argument forms for all the other types) ...

Drawing commands: OpenGL supports drawing of a number of different types of objects. The simplest is glRectf(), which draws a filled rectangle. All the others are complex objects consisting of a (generally) unpredictable number of elements. This is handled in OpenGL by the constructs glBegin(mode) and glEnd(). Between these two commands a list of vertices is given, which defines the object. The sort of object to be defined is determined by the mode argument of the glBegin() command. Some of the possible modes are illustrated in Fig. 10. For details on the semantics of the drawing methods, see the reference manuals. Note that in the case of GL POLYGON only convex polygons (internal angles less than 180 degrees) are sup- ported. You must subdivide nonconvex polygons into convex pieces, and draw each convex piece separately.

glBegin(mode); glVertex(v0); glVertex(v1); ... glEnd();

In the example above we only defined the x- and y-coordinates of the vertices. How does OpenGL know whether our object is 2-dimensional or 3-dimensional? The answer is that it does not know. OpenGL represents all vertices as 3-dimensional coordinates internally. This may seem wasteful, but remember that OpenGL is designed primarily for 3-d graphics. If you do not specify the z-coordinate, then it simply sets the z-coordinate to 0. 0. By the way, glRectf() always draws its rectangle on the z = 0 plane. Between any glBegin()...glEnd() pair, there is a restricted set of OpenGL commands that may be given. This includes glVertex() and also other command attribute commands, such as glColor3f(). At first it may seem a bit strange that you can assign different colors to the different vertices of an object, but this is a very useful feature. Depending on the shading model, it allows you to produce shapes whose color blends smoothly from one end to the other. There are a number of drawing attributes other than color. For example, for points it is possible adjust their size (with glPointSize()). For lines, it is possible to adjust their width (with glLineWidth()), and create dashed

5

v 4

v 1 v 2

v

1

0

v 3

GL_LINE_LOOP

v 5

v v 2

v 6

GL TRIANGLE STRIP

v 5

v 4

v 1 v 2

v 0

v 3

GL_LINE_STRIP

v 0

GL_LINES

v 5

v v 4 3 v 1 v 2

v 0

GL_POINTS

v v 4

v 3

GL_POLYGON

v 5

v v 4 3 v 1 v 2

v 0

4

v 6

v 3 v 5

v 7

GL QUAD STRIP

v 0

v 1 v 2

v 3 v

v (^54)

v 4

v 1 v 2

v 0

v 3

GL TRIANGLES

v 0 v 1

v 2

v

4

5 v 6

GL TRIANGLE FAN

v 3 v 0 v 1

v 2 v 5

v (^) v

v 5

v v^6 7

GL QUADS

v 3

v 0

v 1 v 2

v 4

Fig. 10: Some OpenGL object definition modes.

or dotted lines (with glLineStipple()). It is also possible to pattern or stipple polygons (with glPolygonStipple()). When we discuss 3-dimensional graphics we will discuss many more properties that are used in shading and hidden surface removal. After drawing the diamond, we change the color to blue, and then invoke glRectf() to draw a rectangle. This procedure takes four arguments, the (x, y) coordinates of any two opposite corners of the rectangle, in this case (0. 25 , 0 .25) and (0. 75 , 0 .75). (There are also versions of this command that takes double or int arguments, and vector arguments as well.) We could have drawn the rectangle by drawing a GL POLYGON, but this form is easier to use.

Viewports: OpenGL does not assume that you are mapping your graphics to the entire window. Often it is desirable to subdivide the graphics window into a set of smaller subwindows and then draw separate pictures in each window. The subwindow into which the current graphics are being drawn is called a viewport. The viewport is typically the entire display window, but it may generally be any rectangular subregion. The size of the viewport depends on the dimensions of our window. Thus, every time the window is resized (and this includes when the window is created originally) we need to readjust the viewport to ensure proper transformation of the graphics. For example, in the typical case, where the graphics are drawn to the entire window, the reshape callback would contain the following call which resizes the viewport, whenever the window is resized. Setting the Viewport in the Reshape Callback void myReshape(int winWidth, int winHeight) // reshape window { ... glViewport (0, 0, winWidth, winHeight); // reset the viewport ... }

The other thing that might typically go in the myReshape() function would be a call to glutPostRedisplay(), since you will need to redraw your image after the window changes size. The general form of the command is

glViewport(GLint x, GLint y, GLsizei width, GLsizei height),

top

bottom

Your graphics window

right

Drawing gluOrtho2d glViewport

left

viewport

height

width

(x,y)

idealized drawing region

Fig. 11: Projection and viewport transformations.

#include // standard definitions #include // C++ I/O

#include <GL/glut.h> // GLUT #include <GL/glu.h> // GLU #include <GL/gl.h> // OpenGL

using namespace std; // make std accessible

// ... insert callbacks here

int main(int argc, char** argv) { glutInit(&argc, argv); // OpenGL initializations glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB);// double buffering and RGB glutInitWindowSize(400, 400); // create a 400x400 window glutInitWindowPosition(0, 0); // ...in the upper left glutCreateWindow(argv[0]); // create the window

glutDisplayFunc(myDisplay); // setup callbacks glutReshapeFunc(myReshape); glutMainLoop(); // start it running return 0; // ANSI C expects this }

Fig. 12: Sample OpenGL Program: Header and Main program.

void myReshape(int w, int h) { // window is reshaped glViewport (0, 0, w, h); // update the viewport glMatrixMode(GL_PROJECTION); // update projection glLoadIdentity(); gluOrtho2D(0.0, 1.0, 0.0, 1.0); // map unit square to viewport glMatrixMode(GL_MODELVIEW); glutPostRedisplay(); // request redisplay }

void myDisplay(void) { // (re)display callback glClearColor(0.5, 0.5, 0.5, 1.0); // background is gray glClear(GL_COLOR_BUFFER_BIT); // clear the window glColor3f(1.0, 0.0, 0.0); // set color to red glBegin(GL_POLYGON); // draw the diamond glVertex2f(0.90, 0.50); glVertex2f(0.50, 0.90); glVertex2f(0.10, 0.50); glVertex2f(0.50, 0.10); glEnd(); glColor3f(0.0, 0.0, 1.0); // set color to blue glRectf(0.25, 0.25, 0.75, 0.75); // draw the rectangle glutSwapBuffers(); // swap buffers }

Fig. 13: Sample OpenGL Program: Callbacks.

Lecture 5: Drawing in OpenGL: Transformations

Reading: Transformation are discussed (for 3-space) in Chapter 5. Two dimensional projections and the viewport transformation are discussed at the start of Chapter 6. For reference documentation, visit the OpenGL documentation links on the course web page.

More about Drawing: So far we have discussed how to draw simple 2-dimensional objects using OpenGL. Suppose that we want to draw more complex scenes. For example, we want to draw objects that move and rotate or to change the projection. We could do this by computing (ourselves) the coordinates of the transformed vertices. However, this would be inconvenient for us. It would also be inefficient, since we would need to retransmit all the vertices of these objects to the display processor with each redrawing cycle, making it impossible for the display processor to cache recently processed vertices. For this reason, OpenGL provides tools to handle transformations. Today we consider how this is done in 2-space. This will form a foundation for the more complex transformations, which will be needed for 3-dimensional viewing.

Transformations: Linear and affine transformations are central to computer graphics. Recall from your linear alge- bra class that a linear transformation is a mapping in a vector space that preserves linear combinations. Such transformations include rotations, scalings, shearings (which stretch rectangles into parallelograms), and com- binations thereof. Affine transformations are somewhat more general, and include translations. We will discuss affine transformations in detail in a later lecture. The important features of both transformations is that they map straight lines to straight lines, they preserve parallelism, and they can be implemented through matrix multiplication. They arise in various ways in graphics.

Moving Objects: from frame to frame in an animation. Change of Coordinates: which is used when objects that are stored relative to one reference frame are to be accessed in a different reference frame. One important case of this is that of mapping objects stored in a standard coordinate system to a coordinate system that is associated with the camera (or viewer).