Drawing in OpenGL CSC 2141 Introduction to Computer Graphics.
-
Upload
horace-eaton -
Category
Documents
-
view
261 -
download
0
Transcript of Drawing in OpenGL CSC 2141 Introduction to Computer Graphics.
Drawing in OpenGL
CSC 2141Introduction to Computer Graphics
GLUT
Basic elements of how to create a window OpenGL is intentionally designed to be independent
of any specific windowing system: window operations are not provided
A separate library, GLUT is created to provide functionality common to all windowing systems Open a window Get input from mouse and keyboard Menus Event-driven
GLUT links with the specific window system GLX for X window systems WGL for Windows AGL for Macintosh
MyFirstOpenGLProgram.cpp
Components of a typical main function:
glutInit(): must be called before others General initialization of GLUT and OpenGL Pass the command line arguments to it
glutInitDisplayMode(): Initializations related to the frame buffer OpenGL maintains an enhance version of frame buffer with
additional information Arguments: Logical-OR of following possible options Color: tell the system how colors will be represented
GLUT_RGB: 24-bit color GLUT_RGBA: fourth component indicates opaqueness (1=fully
opaque, 0 = fully transparent) Enabling the Depth buffer (we will need later in 3D for
hidden surface removal, do not display objects not visible to viewer)
GLUT_DEPTH Single or double buffering
GLUT_DOUBLE GLUT_SINGLE
Single Buffering
Recall: whatever is written to frame buffer is immediately transferred to display
Repeated 50-85 times a second (refresh rate) What if the contents of the frame buffer is changed
(e.g. animation) Typically
First erase the old contents by setting all pixels to some background color
Draw the new contents Not fast enough: noticeable flicker
Change could happen during refreshing (parts of the object could appear later!!)
Double Buffering
System maintains two buffers The front buffer is the one that is being displayed Drawing is done to the back buffer To update the image system swaps the two buffers Swapping is fast (no flicker) Twice the buffer space needed
glutInitWindowSize(int width, int height) specifies desired width and height in pixels
glutInitWindowPosition(int x, int y): Specifies the upper-left corner of the graphics window x and y are given relative to the upper-left corner of the
display: (0,0)
glutCreateWindow(char *title): Specifies the title and creates the window
(0,0)
(x,y)
Event-driven Programming and Callbacks All interactive graphics programs are event-driven
Program must be prepared at any time for input from a number of sources: mouse, keyboard, etc
In OpenGL, this is done through callbacks Program instructs the system to invoke a particular function
whenever an event of interest occurs: a key is hit That is, the graphics program registers various events:
involves telling the window system which event type you are interested in and passing it the name of the function you have written to handle that event
Types of callbacks
User input events: keyboard hit, mouse click, motion of a mouse (without clicking), also called passive motion. Note that, your program is only signaled about events that
happen to your window. System events:
Display event: 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 The program explicitly requests redrawing by calling
glutPostRedisplay()
System events cont’d
Reshape event: When window size is changed Callback provides information on the new size of the window For a newly created window as well, first a reshape event
then a display event is generated. Timer event:
There may not be any user input, but it might be necessary to update the image, e.g. plane keeps moving forward in a flight simulator
Request a timer event: your program goes to sleep for some period and it is awakened by an event sometime later to draw the next image.
Idle event: generated every time system has nothing else to do. Too
many events.
Callback registration functions
Event type Callback registration User callback function prototype
Mouse button glutMouseFunc myMouse(int b, int s, int x, int y)
Mouse motion glutPassiveMotionFunc myMotion(int x, int y)
Keyboard glutKeyboardFunc myKeyboard(unsigned char c, int x, int y)
Display glutDisplayFunc myDisplay()
Reshape window
glutreshapeFunc myReshape(int w, int h)
Timer glutTimerFunc myTimer(int id)
Idle glutIdleFunc myIdle()
glutTimerFunc
arguments Number of milliseconds to wait (unsigned int) Name of user’s callback function An integer identifier to be passed to the callback function (in
case of multiple timers, to know which one is generating the event)
e.g. glutTimerFunc(20, myTimeOut, 0)
Information associated with each event Information provided to user’s callback function by the
event Reshape event passes new window width and height Mouse click passes
Which button was hit: b GLUT_LEFT_BUTTON, GLUT_RIGHT_BUTTON,
GLUT_MIDDLE_BUTTON Button’s new state: s
GLUT_DOWN, GLUT_UP x and y coordinates of the mouse when it was clicked (in pixels)
Keyboard hit passes The character hit Current coordinates of the mouse
Timer event passes the integer id specified in registration
glutPostRedisplay()
Reshape callback and timer callback both invoke glutPostRedisplay() inform OpenGL that the state of the scene has changed and
request redrawing by calling user’s display function. If need be other callbacks can request redrawing as
well.
glutMainLoop()
After registering the callback functions, enter main event loop by calling glutMainLoop()
OpenGL will start handling events now.
What to draw?
Geometric primitives Points Line Segments Polygons
OpenGL has a small set of primitives GLU contains a richer set of objects derived from the
basic OpenGL library
OpenGL State
OpenGL is a state machine OpenGL functions are of two types
Primitive generating How vertices are processed and appearance of primitive are
controlled by the state State changing
Transformation functions Attribute functions
Lack of Object Orientation
OpenGL is not object oriented so that there are multiple functions for a given logical function glVertex3f glVertex2i glVertex3dv
Underlying storage mode is the same
Simplest geometric object in space: vertex
glVertex3f(x,y,z)
belongs to GL library
function name
x,y,z are floats
glVertex3fv(p)
p is a pointer to an array
dimensions
glVertex*
*: nt or ntv n: 2,3,4 (number of parameters) t: i,f,d (int, float or double parameters) v: variables are specified through a pointer to an
array
GLfloat vertex[3]; glVertex3fv(vertex);
GLfloat, GLint instead of float, int
Group vertices to define other primitives OpenGL is based on drawing objects with straight
sides, so it suffices to specify vertices of the object
glBegin(<type>) glVertex*(..); glVertex*(..); : glVertex*(..);
glEnd();
Calculations can appear within glBegin() and glEnd()
Object type
The value of type specifies how OpenGL interprets vertices Points: GL_POINTS Line segments: GL_LINES Polylines: GL_LINE_STRIP, GL_LINE_LOOP
Polylines
Finite sequence of line segments joined end to end closed: ends where it starts simple: it does not self intersect
Curves can be approximated by breaking them into large number of small polylines
closed simple
More primitives: Polygon
GL_POLYGON border described as a line loop Has an interior: filled object Variety of ways to display:
Only edges Fill with solid color or fill pattern (without edges) To fill with edges, polygon has to be drawn twice Fill is default
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 (all interior angles < 180) Flat: all vertices are in the same plane
User program can check if above true OpenGL will produce output if these conditions are violated but
it may not be what is desired Triangles satisfy all conditions
3 points define a plane
nonsimple polygon nonconvex polygon
Convex, noncovex
You must subdivide nonconvex polygons into convex pieces and draw each convex piece separately for correctness.
Other convex shapes : spheres, tetrahedra, cube, parallelepipeds, etc.
Polygon types
GL_QUADS: successive 4 vertices are treated as quadrilaterals
GL_TRIANGLES: successive 3 vertices are treated as triangles
Polygon types
Triangles and quads sharing vertices GL_TRIANGLE_STRIP: each additional vertex is
combined with previous two vertices to define a triangle
GL_QUAD_STRIP GL_TRIANGLE_FAN
Simplest polygon
glRectf(x_ll, y_ll, x_ur, y_ur) Lower left and upper right corners specified
Draws a filled rectangle Always on z=0 plane (2D) OpenGL does not distinguish 2D and 3D
representations, everything is represented in 3D internally (x,y) (x,y,0)
Text and Curved Objects: LATER
Curved objects: we can use mathematical definitions and create our own approximations OR use GLU functions
Attributes
Attributes are part of the OpenGL state and determine the appearance of objects Color (points, lines, polygons) Size and width (points, lines) Stipple pattern (lines, polygons) Polygon mode
Display as filled: solid color or stipple pattern Display edges Display vertices
Once set the attribute applies to all subsequently defined objects, until set to some other value
RGB color
Each color component is stored separately in the frame buffer Usually 8 bits per component in buffer
glColor3f(): 3 float parametersglColor3d(): 3 double parametersglColor3ui(): 3 unsigned intglColor3dv(): color stored in array parameter
Note in glColor3f the color values range from 0.0 (none) to 1.0 (all), whereas in glColor3ui the values range from 0 to 255
glColor3f(1.0, 0.0, 0.0): pure red
Other major colors
Cyan: green and blue fully on Magenta: red and blue fully on Yellow: red and green fully on White: red, green and blue fully on If R,G, B components are equal: shades of gray
Additive color: we think of color as being formed from three primary color (Red, Blue, Green) that are mixed to form desired color
RGBA System
The fourth components (A) is called alpha channel Indicates opaqueness of color
1: fully opaque 0: fully transparent
Now, we use glColor4d(..) and 4-argument forms for all the other types
Useful for creating transparent effects Recall:
Opaque object passes no light through Fully transparent object: passes all light through
Recall: 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
glIndexi(int element) select a color from color lookup table
glutSetColor(int color, GLfloat r, GLfloat g, GLfloat b): set entries in a color table
In OpenGL we will mostly use RGB color
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
Some other attributes
glPointSize(2.0): points are drawn 2 pixels wide glLineWidth(..) glLineStipple(..): create dashed or dotted lines
Drawing in OpenGL: Viewing and Viewports
CSC 2141Introduction to Computer Graphics
Let’s look at myDisplay() function
Display callback function, where the drawing is done. Clear window Do our drawing SWAP buffers so that what we have drawn becomes visible
(double buffering) glutSwapBuffers();
glFlush(): forces OpenGL to render as soon as possible. Avoids any delay.
myDisplay()
void myDisplay(){ glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 0.0, 0.0); // set color to red
glBegin(GL_POLYGON); // list the vertices to draw a 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 a rectangle glFlush(); // force OpenGL to
render glutSwapBuffers(); // swap buffers
}
Clearing the window
glClear(…): clears the window by overwriting it with the background color
How to set the background color? glClearColor(GLfloat Red, GLfloat Green, GLfloat Blue, GLfloat
Alpha) E.g. to set it to blue, and opaque: glClearColor(0.0,0.0,1.0,1.0);
Where to set the background color ? it is independent of drawing Typically set in your initialization functions, not in display
callback function
glClear(…) cont’d
Involves clearing frame buffer Frame buffer might store different types of
information Color, depth
glClear() allows user to select what to clear Logical OR of options can be given
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
Where are we drawing?
Next we have to specify the geometry of the objects we want to draw.
But, how do we specify the coordinates? Relative to what?
To understand this, it would be helpful to learn about orthographic viewing in general, because 2D viewing is a special case of 3D orthographic viewing
Viewing
Orthographic Viewing (Projection) simplest, default Camera (of synthetic-camera
model) infinitely far from objects Leave image plane fixed and move
camera far from the plane All projectors become parallel in the
limit Center of projection is replaced by
a direction of projection
Orthographic Viewing cont’d
Suppose that Projectors parallel to z-axis Projection plane at z= 0 Projectors perpendicular (orthogonal)
to projection plane We can slide the projection plane
along z-axis without changing where the projectors intersect this plane
Default OpenGL Camera
OpenGL places a camera on the projection plane at the origin pointing in the negative z direction
Sees only objects in the viewing volume The default viewing volume is a box centered at the origin with a side of length 2 We can change the viewing volume by specifying left, right, bottom, top, near, far
Orthographic Viewing
z=0
In the default orthographic view, points are projected forward along the z axis onto the plane z=0
Orthographic projection takes (x,y,z) and projects to (x,y,0)
2D viewing is a special case of 3D orthographic viewing
We could consider 2D viewing directly by taking a rectangular area of our 2D world. In 2D, all vertices are on z=0, so, point and projection are
the same All we need is to specify a viewing (clipping) rectangle (on
z=0 ) Any drawing outside this region is clipped away.
2D viewing is a special case of 3D orthographic viewing
It is a good idea to think of this in terms of drawing on a rectangular idealized drawing window We will specify coordinates relative to this window
We will then inform OpenGL of our idealized drawing window and OpenGL will scale the image drawn in our idealized drawing window to fit within the actual graphics window (the viewport in fact)
Why are we doing this?? Because we do not have complete control on actual graphics window size. We do not want to explicitly scale all of our coordinates
when the user resizes the window
Back to drawing…
Assume my idealized drawing window : [0,1] X [0,1] Unit square, whose lower left corner is at (0,0)
Note: As opposed to GLUT, OpenGL uses the convention that coordinates are floating point values and the origin is at the lower left corner.
0
0
0.5
1
10.5
myDisplay()
void myDisplay(){ glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0, 0.0, 0.0); // set color to red
glBegin(GL_POLYGON); // list the vertices to draw a 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 a rectangle
glFlush(); // force OpenGL to render
glutSwapBuffers(); // swap buffers}
Viewports
OpenGL does not force mapping your graphics (idealized drawing window) to the entire graphics window
Provides subwindows The subwindow into which current graphics are being
drawn is called a viewport Typically, we set the viewport as the entire window
(default), but it may generally be any rectangular subregion
What happens if the window is resized? We usually prefer to readjust the viewport Where should we do this?
In the reshape callback function!
myReshape
void myReshape(int winWidth, int winHeight) { windowHeight = winHeight; windowWidth = winWidth; ……. glViewport (0, 0, winWidth, winHeight); //reset
viewport…….
}
What happens if we do not reset it? TRY!
glViewport
General formglViewport(Glint x, Glint y, GLsizei w, GLsizei h)
(x, y) are pixel coordinates of the lower-left corner of the viewport as defined relative to the lower-left corner of the graphics window
w and h are the width and height of the viewport in pixels
Aspect ratio and viewports
We might choose to adjust the width and height of the viewport to match the aspect ratio of the idealized drawing window to prevent distortion of objects.
Aspect ratio of a rectangle : ratio of width to height
Viewport is a part of state
If we change the viewport between rendering objects, we achieve the effect of multiple viewports with different images on different parts of the window
Projection transformation
We need to inform OpenGL of our idealized drawing window, so that it can map it to our viewport.
This mapping is performed by a transformation called the projection matrix Maintained internally by OpenGL Part of the state that remains in effect until changed
OpenGL provides functions to set this matrix. For our 2D example, we simply inform OpenGL of the rectangular region that we called idealized drawing window
gluOrtho2D(left, right, bottom, top)
Typical code to set projection matrix in 2D
glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0, 1.0, 0.0, 1.0);glMatrixMode(GL_MODELVIEW); // good idea to always switch back to default matrix
mode to // keep track of the current matrix
Projection transformation cont’d OpenGL maintains three different types of
transformations (we will see later) And, there is only one set of transformation
functions so we must set the matrix mode first telling OpenGL that we will be modifying the projection matrix.
glMatrixMode (GL_PROJECTION) Transformation functions are incremental so we
start by initializing he current matrix to identity matrix and alter it with a projection transformation.
glLoadIdentity(); glOrtho2D(0.0 1.0, 0.0, 1.0);
Where does this code fragment go? If you do the drawing in the same idealized window
all the time, you can place this in your initialization function
If your program needs to change the drawing area depending on window size, place it in reshape callback function to alter the projection every time the window size is changed.
Summary of viewports and projection Viewport is a rectangle within the actual graphics
window
Projection defined by gluOrtho2D() simply defines a rectangle (we call it idealized drawing window or clipping rectangle) which you will use to specify the coordinates of your objects
It is OpenGL’s job to map your ideal drawing window to the actual viewport
(x, y)
w
h
viewport
Actual graphics window
Idealized drawing window
top
bottom
left right
gluOrtho2D glViewport
draw