Lecture 3 Advanced Computer Graphics (CS & SE 233.420)
Programming with OpenGL Program Structure Primitives Attributes and States Programming in three dimensions Inputs and Interaction Working with Callbacks
Program Structure Most OpenGL programs have a similar structure that consists of the following functions main(): defines the callback functions opens one or more windows with the required properties enters event loop (last executable statement) init(): : sets the state variables Viewing Attributes callbacks Display function Input and window functions
Basic Glut Program GLUT initialisation glutinit(& (&argc, argv); glutinitdisplaymode (GLUT_DOUBLE GLUT_RGB); Window initialisation glutinitwindowsize (500, 500); glutinitwindowposition (100, 100); glutcreatewindow (argv[0]); User defined initialisation init (); Declare callback functions glutdisplayfunc(display); glutreshapefunc(reshape); glutkeyboardfunc(keyboard); Begin Glut event loop glutmainloop();
Event Loop The main function ends with the program entering an event loop At this point program is triggered by events Event types: Window: resize, expose, iconify Mouse: click one or more buttons Motion: move mouse Keyboard: press or release a key Idle: nonevent - Define what should be done if no other event is in queue
Event Mode Most systems have more than one input device, each of which can be triggered at an arbitrary time by a user Each trigger generates an event whose measure is put in an event queue which can be examined by the user program Trigger Measure Event Process Process Queue Trigger Measure Await Event Program
GLUT Event Loop Remember that the last line in main.c for a program using GLUT must be glutmainloop(); puts the program in an infinite event loop In each pass through the event loop, GLUT Looks at the events in the queue For each event in the queue, GLUT executes the appropriate callback function if one is defined If no callback is defined for the event, the event is ignored
Callbacks Programming interface for event-driven input Define a callback function for each type of event the graphics system recognizes This user-supplied supplied function is executed when the event occurs
GLUT Callbacks GLUT recognizes a subset of the events recognized by any particular window system (Windows, X, Macintosh) glutdisplayfunc glutmousefunc glutreshapefunc glutkeyboardfunc glutidlefunc glutmotionfunc glutpassivemotionfunc
The Display Callback The display callback is executed whenever GLUT determines that the window should be refreshed, for example When the window is first opened When the window is reshaped When a window is exposed When the user program decides it wants to change the display In main.c glutdisplayfunc(mydisplay) identifies the function to be executed Every GLUT program must have a display callback
Using the Idle Callback The idle callback is executed whenever there are no events in the event queue glutidlefunc(myidle) Useful for animations void myidle() { /* change something */ t += dt glutpostredisplay(); } void mydisplay() { glclear(); /* draw something that depends on t */ glutswapbuffers(); }
The Mouse Callback glutmousefunc(mymouse) void mymouse(glint button, GLint state, GLint x, GLint y) Returns Which button (GLUT_LEFT_BUTTON( GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, GLUT_RIGHT_BUTTON) ) caused event -State of that button (GL_UP( GL_UP, GLUT_DOWN) Position in window
Drawing Squares at Cursor Location void mymouse(int btn, int state, int x, int y) { if (btn( btn==glut_right_button && state==glut_down) exit(0); if (btn( btn==glut_left_button && state==glut_down) drawsquare(x,, y); } void drawsquare(int x, int y) { y=w-y; ; /* invert y position */ glcolor3ub( (char) rand()%256, (char) rand )%256, (char) rand()%256); glbegin(gl_polygon); glvertex2f(x+size, y+size); glvertex2f(x-size, y+size); glvertex2f(x-size, y-size); y glvertex2f(x+size, y-size); y glend(); }
Using the Motion Callback Can draw squares (or anything else) continuously as long as a mouse button is depressed by using the motion callback glutmotionfunc(drawsquare) Can draw squares without depressing a button using the passive motion callback glutpassivemotionfunc(drawsquare)
The Reshape Callback glutreshapefunc(myreshape) void myreshape( int w, int h) Returns width and height of new window (in pixels) A redisplay is posted automatically at end of execution of the callback GLUT has a default reshape callback but you probably want to define your own The reshape callback is good place to put camera functions because it is invoked when the window is first opened
Example Reshape This reshape preserves shapes by making the viewport and world window have the same aspect ratio } void myreshape(int w, int h) { glviewport(0, 0, w, h); glmatrixmode(gl_projection); /* switch matrix mode */ glloadidentity(); if (w <= h) gluortho2d(-2.0, 2.0, 2.0, -2.0 * (GLfloat( GLfloat) ) h / (GLfloat( GLfloat) ) w, 2.0 * (GLfloat( GLfloat) ) h / (GLfloat( GLfloat) ) w); else gluortho2d(-2.0 2.0 * (GLfloat( GLfloat) ) w / (GLfloat( GLfloat) ) h, 2.0 * (GLfloat)) w / (GLfloat( GLfloat) ) h, -2.0, 2.0); glmatrixmode(gl_modelview); /* return to modelview mode */
Using Globals The form of all GLUT callbacks is fixed void mydisplay() void mymouse(glint button, GLint state, GLint x, GLint y) Must use globals to pass information to callbacks float t; /*global */ void mydisplay() { /* draw something that depends on t /* draw something that depends on t }
Posting Redisplays Many events may invoke the display callback function Can lead to multiple executions of the display callback on a single pass through the event loop We can avoid this problem by instead using glutpostredisplay(); sets a flag. GLUT checks to see if the flag is set at the end of the event loop If set then the display callback function is executed
OpenGL Primitives All rendering operations are composed of primitives. These need to be useful to the programmer and doable efficiently by the library & hardware. We will now look at those OpenGL primitives that are handled via the glbegin-glend glend mechanism. There are ten of these; they consist of ways to draw: Points. Polylines. Filled polygons. Other primitive rendering operations are handled differently in OpenGL. Specifically, those involving screen-aligned rectangles: pixmaps, bitmaps, and screen-aligned rectangular polygons. Recall: OpenGL has no circle/ellipse/curve primitives.
Ten Basic Primitives The ten glbegin-style OpenGL Primitives Points (1 primitive) GL_POINTS Polylines (3 primitives) GL_LINES GL_LINE_STRIP GL_LINE_LOOP Filled Polygons (6 primitives) Triangles GL_TRIANGLES GL_TRIANGLE_STRIP GL_TRIANGLE_FAN Quadrilaterals GL_QUADS GL_QUAD_STRIP General Polygons GL_POLYGON
Points A primitive is given a number of vertices (specified with glvertex ). Now we look at what the primitives do with the vertices they are given. Numbers indicate vertex ordering. Pink objects mark what is actually rendered. Points GL_POINTS 5 6 1 3 4 2
Polylines GL_LINES 5 6 4 1 3 2 GL_LINE_STRIP 5 6 4 1 3 2 6 1 3 GL_LINE_LOOP 5 4 2
Triangles GL_TRIANGLES Clockwise or counterclockwise 1 does not matter (yet). GL_TRIANGLE_STRIP 2 4 3 2 4 1 3 1 5 5 6 6 6 GL_TRIANGLE_FAN 3 4 5
Quadrilaterals & General Polygons Polygons: Quadrilaterals GL_QUADS Clockwise or counterclockwise does not matter (yet). 2 3 1 4 5 6 7 8 GL_QUAD_STRIP Note differences in vertex ordering! Polygons: General GL_POLYGON 2 1 3 1 4 5 6 6 8 7
Primitive Restrictions When drawing points, lines, and triangles, vertices can be in any positions you like. Individual quadrilaterals and general polygons must be: Planar (this is easy in 2-D). 2 Simple (no crossings, holes). Convex (bulging outward; no concavities). Know the ten primitives! Know the associated vertex orderings!
Polygon Issues OpenGL will only display polygons correctly that are Simple: edges cannot cross Convex: All points on line segment between two points in a polygon are also in the polygon Flat: all vertices are in the same plane User program must check if above true Triangles satisfy all conditions Nonsimple Nonconvex
Attributes Attributes are part of the OpenGL state and determine the appearance of objects Size and width (points, lines) Stipple pattern (lines, polygons) Polygon mode Display as filled: solid color or stipple pattern Display edges Color (points, lines, polygons)
Primitives and Attribute States As a geometric primitive is drawn, each of its vertices is affected by the current OpenGL attribute "state" variables. State variables refer to OpenGL capabilities that are Either "off" (set to the value GL_FALSE) or "on" (set to the value GL_TRUE). Or refer to a certain mode (set to a value of type GLenum) chosen from a fixed set of modes. Or are set to certain values (GLfloat( GLfloat, GLint,, etc...). Each state variable has a default value. The values of the state variables, whether set by default or by the programmer, remain in effect until changed.
"On" and "Off" State Variables State variables that refer to OpenGL capabilities can be either Enabled with the command glenable(glenum capability) Disabled With the command gldisable(glenum capability) Their current value can be queried using the command glisenabled(glenum capability) returns either GL_TRUE or GL_FALSE. Some OpenGL capabilities include: GL_POINT_SMOOTH If enabled, draw points with proper filtering, otherwise draw aliased a points. GL_LINE_SMOOTH If enabled, draw lines with correct filtering, otherwise, draw aliased a lines. GL_LINE_STIPPLE If enabled, use the current line stipple pattern when drawing lines. l
Mode State Variables Mode state variables require commands specific to the state variable being accessed in order to change its value. One example of this is the command to set the shading mode state variable, GL_SHADE_MODEL. A line or filled polygon primitive can be drawn with a single color (flat shading) or with many different colors (smooth shading) The desired shading technique can be specified with the command glshademodel(glenum mode) where mode GL_SMOOTH for smooth shading or GL_FLAT for flat shading, the default
Value State Variables Value state variables require commands specific to the state variable being accessed in order to change it value. At any point, the programmer can query the system for any variable's current value. Typically, one of the four following commands is used to do this depending upon the desired data type of the answer: glgetbooleanv() glgetdoublev() glgetfloatv() glgetintegerv()
Color RGB color Each color component is stored separately in the frame buffer Usually 8 bits per component in buffer glcolor3f the color values range from 0.0 (none) to 1.0 (all) glcolor3ub the values range from 0 to 255 Indexed Color Colors are indices into tables of RGB values Requires less memory indices usually 8 bits not as important now Memory inexpensive Need more colors for shading
Color and State The color as set by glcolor becomes part of the state and will be used until changed Colors and other attributes are not part of the object but are assigned when the object is rendered We can create conceptual vertex colors by code such as glcolor glvertex glcolor glvertex
Smooth Color Default is smooth shading OpenGL interpolates vertex colors across visible polygons Alternative is flat shading Color of first vertex determines fill color glshademodel (GL_SMOOTH) or GL_FLAT
Point Size and Line Width Point Size To control the size of a rendered point use the command glpointsize(glfloat size) size is the desired width in pixels for rendered points size must be greater than 0.0 and by default is 1.0 Line Width To control the width of lines use the commandgllinewidth(glfloat width) width is the desired width in pixels for rendered lines width must be greater than 0.0 and by default is 1.0
Stippled Lines To make stippled (dotted or dashed) lines, the stipple pattern must be defined using the command gllinestipple(glint factor, GLushort pattern) the pattern argument is a 16-bit series of 0s and 1s, and it's repeated as necessary to stipple a given line. 1 indicates that drawing occurs, and 0 that it does not, on a pixel by pixel basis. The pattern can be stretched out by using factor, which multiplies each sub-series series of consecutive 1s and 0s. factor is any value between 0 and 255, inclusive. The capability state variable GL_LINE_STIPPLE must be enabled by the call glenable(gl_line_stipple) ) for stippling to occur.
Three-dimensional Applications In OpenGL, two-dimensional applications are a special case of three-dimensional graphics Going to 3D Not much changes Use glvertex3*( ) Have to worry about the order in which polygons are drawn or use hidden-surface removal Polygons should be simple, convex, flat
Sierpinski Gasket The Sierpinski Gasket is named for the Polish mathematician who first proposed it. It is a fractal image that is made from equilateral triangles. Consider the filled area (black) and the perimeter (the length of all the lines around the filled triangles) As we continue subdividing area goes to zero perimeter goes to infinity Theoretically, the addition of the black triangles goes on forever. Does the black ever completely cover the white? This is not an ordinary geometric object It is neither two- nor three-dimensional It is a fractal (fractional dimension) object
Sierpinski Gasket (2D) Start with a triangle Connect bisectors of sides and remove central triangle Repeat
OpenGL Sierpinski Gasket (2D)
Moving to 3D We can easily make the program three dimensional by using typedef Glfloat point3[3] glvertex3f glortho But that would not be very interesting Instead, we can start with a tetrahedron
3D Gasket Start with a tetrahedon Subdivide each of the four faces Appears as if we remove a solid tetrahedron from the center leaving four smaller tetrahedtra
Problem Because the triangles are drawn in the order they are defined in the program, the front triangles are not always rendered in front of triangles behind them Does not account for hidden surfaces
Hidden-Surface Removal Want to see only those surfaces in front of other surfaces Only a problem in 3D OpenGL uses a hidden- surface method called the z-buffer algorithm saves depth information as objects are rendered so that only the front objects appear in the image
Using the z-buffer algorithm The algorithm uses an extra buffer, the z-buffer, z to store depth information as geometry travels down the pipeline It must be Requested in main.c glutinitdisplaymode (GLUT_SINGLE GLUT_RGB GLUT_DEPTH) Enabled in init.c glenable(gl_depth_test) Cleared in the display callback glclear(gl_color_buffer_bit GL_DEPTH_BUFFER_BIT) If the current rendered pixel is closer than the existing pixel then it replaces the existing pixel The pixel in the closer position to the viewer is the one that will w be displayed
Double Buffering Instead of one color buffer, we use two Front Buffer: : one that is displayed but not written to Back Buffer: : one that is written to but not displayed Program then requests a double buffer in main.c glutinitdisplaymode(gl_rgb GL_DOUBLE) At the end of the display callback buffers are swapped void mydisplay() { glclear() /* draw graphics here */ glutswapbuffers() }
Graphical Input Devices can be described either by Physical properties Mouse Keyboard Trackball Joystick Logical Properties What is returned to program via API A position An object identifier Modes How and when input is obtained Request or event
Incremental (Relative) Devices Devices such as the data tablet return a position directly to the operating system Devices such as the mouse, trackball, and joy stick return incremental inputs (or velocities) to the operating system Must integrate these inputs to obtain an absolute position Rotation of wheels in mouse Roll of trackball Difficult to obtain absolute position Can get variable sensitivity
Input Modes Input devices contain a trigger which can be used to send a signal to the operating system Button on mouse Pressing or releasing a key When triggered, input devices return information (their measure) ) to the system Mouse returns position information Keyboard returns ASCII code
References http://www.eecs.tulane.edu/ www/terry/opengl/changing_state.html www.inf.pucrs.br/~flash/tcg/aulas/oglfaq/viewing.htm - www.cs.uaf.edu/~cs381/slides/20030910ogl.ppt http://www.dgp.toronto.edu/~ah/csc418/fall_2001/tut/ogl_draw.html http://isg.cs.tcd.ie/dingliaj/3d4/lab2_p2.html http://www.opengl.org/about/overview.html http://www.winnetmag.com/article/articleid/3581/3581.html http://www.csee.umbc.edu/~ebert/691/au00/notes/c1_viewing.html www.inf.ufrgs.br/~comba/gh-files/talk1.pdf files/talk1.pdf http://www.dgp.toronto.edu/~hertzman/courses/csc418/winter_2004/notes notes /lecture/pipeline.html Ed Angel Lecture notes (Lectures 4, 5, 6, 7, 8 and 9) Open GL web page www.opengl.org