graphics output primitives hearn & baker chapter...
TRANSCRIPT
Graphics Output Primitives
Hearn & Baker Chapter 3
Some slides are taken from Robert Thomsons notes.
OVERVIEW
• Coordinate reference frames
• OpenGL Point & Line functions
• Line drawing algorithms
• Curve drawing algorithms
• Fill-area primitives
• Pixel-array primitives
• Character primitives
• Picture Partitioning
Basic Elements
Three basic elements
– Scalars
– Vectors
– Points
• Develop mathematical operations among them
• Define basic primitives:
– Points
– Line segments
Basic Elements
• Points are associated with locations in space
• Vectors have magnitude and direction
– represent displacements between points, or directions
• Points, vectors, and operators that combine them are the
common tools for solving many geometric problems that
arise in
– Geometric Modeling,
– Computer Graphics,
– Animation,
– Visualization, and
– Computational Geometry.
3.1 COORDINATE REFERENCE FRAMES
To describe a picture, we first decide upon
• A convenient Cartesian coordinate system, called the world-coordinate
reference frame, which could be either 2D or 3D.
• We then describe the objects in our picture by giving their geometric specifications in terms of positions in world coordinates.
– e.g., we define a straight-line segment with two endpoint positions, and a polygon is specified with a set of positions for its vertices.
– These coordinate positions are stored in the scene description along with other info about the objects, such as their color and their coordinate extents
• coordinate extents are the minimum and maximum x, y, and z values for each object.
• A set of coordinate extents is also described as a bounding box for an object.
– For a 2D figure, the coordinate extents are sometimes called its bounding rectangle.
3.1 COORDINATE REFERENCE FRAMES
• Objects are then displayed by passing the scene description to the viewing routines
• which identify visible surfaces and map the objects to the frame buffer positions and then on the video monitor.
• The scan-conversion algorithm stores info about the scene, such as color values, at the appropriate locations in the frame buffer, and then the scene is displayed on the output device.
• locations on a video monitor • are referenced in integer screen coordinates, which
correspond to the integer pixel positions in the frame buffer.
3.1 COORDINATE REFERENCE FRAMES
• Scan-line algorithms for the graphics primitives use the coordinate
descriptions to determine the locations of pixels
– E.g., given the endpoint coordinates for a line segment, a display
algorithm must calculate the positions for those pixels that lie
along the line path between the endpoints.
• Since a pixel position occupies a finite area of the screen
– the finite size of a pixel must be taken into account by the
implementation algorithms.
– for the present, we assume that each integer screen position
references the centre of a pixel area.
3.1 COORDINATE REFERENCE FRAMES
• Once pixel positions have been identified the color values must be stored in the frame buffer
• Assume we have available a low-level procedure of the form
setPixel (x, y); stores the current color setting into the frame buffer at integer position
(x, y), relative to the position of the screen-coordinate origin
getPixel (x, y, color); retrieves the current frame-buffer setting for a pixel location;
• parameter color receives an integer value corresponding to the combined RGB bit codes stored for the specified pixel at position (x,y).
• additional screen-coordinate information is needed for 3D scenes. For a two-dimensional scene, all depth values are 0.
3.1 Absolute and Relative Coordinate
Specifications
• So far, the coordinate references discussed are
given as absolute coordinate values
– values are actual positions wrt origin of current
coordinate system
• some graphics packages also allow positions to
be specified using relative coordinates
– as an offset from the last position that was
referenced (called the current position)
Specifying A 2D World-coordinate Reference Frame in OpenGL
• World-coordinate limits for a display window, as specified in the glOrtho2D function.
• gluOrtho2D function specifies an orthogonal projection, we need also to be sure that the coordinate values are placed in the OpenGL projection matrix. – In addition, we could assign the identity matrix as the projection matrix
before defining the world-coordinate range.
– This would ensure that the coordinate values were not accumulated with any values we may have previously set for the projection matrix.
glMatrixMode (GL_PROJECTION);
glLoadIdentity ( );
glu0rtho2D (xmin, xmax, ymin, ymax);
– The display window will then be referenced by coordinates (xmin,
ymin) at the lower-left corner and by coordinates (xmax, ymax) at the upper-right corner, as shown in Fig. 3-2.
3-3 OpenGL POINT FUNCTIONS
• To specify the geometry of a point, we simply give a
coordinate position in the world reference frame.
• Then along with other geometric descriptions this data is
passed to the viewing routines. – Unless we specify other attribute values, OpenGL primitives are
displayed with a default size and color.
• The default color for primitives is white and the default point
size is equal to the size of one screen pixel.
3-3 OpenGL POINT FUNCTIONS
• A glVertex function must be placed between a glBegin function and a glEnd function.
• The argument of the glBegin function is used to identify the kind of output primitive that is to be displayed
• For point plotting, the argument of the glBegin function is the symbolic constant GL_POINTS.
• and glEnd takes no arguments.
glBegin (GL_POINTS);
glVertex* ( );
glEnd ( ) ;
3-3 OpenGL POINT FUNCTIONS
glVertex* ( ); • state the coordinate values for a single position
• where the asterisk (*) indicates that suffix codes are required for
this function.
• These suffix codes are used to identify the spatial dimension, 2,
3, or 4 (indicates a scaling factor for the Cartesian-coordinate
values.)
• the numerical data type
– i (integer), s (short), f (float), and d (double)
• and a possible vector form for the coordinate specification
– append a third suffix code: v (for "vector").
• the glVertex function is used in OpenGL to specify
coordinates for any point position. – In this way, a single function is used for point, line, and polygon
specifications
3-3 OpenGL POINT FUNCTIONS.
glBegin (GL_POINTS); glVertex2i (50, 100);
glVertex2i (75, 150);
glVertex2i (100, 200);
g1End ( ) ;
• Alternatively, we could specify the coordinate values for the preceding points in arrays such as
int point1 [ ] = {50, 100};
int point2 [ ] = {75, 150};
int point3 [ ] = {100, 200};
and call the OpenGL functions for plotting the three points as
glBegin (GL_POINTS); glVertex2iv (pointl);
glVertex2iv (point2);
glVertex2iv (point3);
glEnd ( ) ;
3-3 OpenGL POINT FUNCTIONS.
class wcPt2D {
public: GLfloat x, y;
};
• Using this class definition, we could specify a 2D, world-coordinate point position with the statements
wcPt2D pointPos;
pointPos.x = 120.75;
pointPos.y = 45.30;
glBegin (GL_POINTS); glVertex2f (pointPos.x, pointPos.y);
glEnd ( )
3-4 OpenGL LINE FUNCTIONS • now we use a symbolic constant as the argument for the glBegin
function that interprets a list of positions as the endpoint coordinates for line segments.
– A set of straight-line segments between each successive pair of endpoints in a list is generated using the primitive line constant GL_LINES
glBegin (GL_LINES):
glVertex2iv(pl);
glVertex2iv(p2);
glVertex2iv(p3);
glVertex2iv(p4);
glVertex2iv(p5);
glEnd ( );
• Nothing is displayed if we do not list at least two coordinate positions
pl
p3
p2 p4
3-4 OpenGL LINE FUNCTIONS. glBegin (GL_LINE_STRIP);
glVertex2iv (pl); glVertex2iv (p2); glVertex2iv (p3); glVertex2iv (p4); glVertex2iv (p5);
glEnd ( )
• The first line segment in the polyline is displayed between the first endpoint and the second endpoint;
• the second line segment is between the second and third
endpoints; and so forth, up to the last line endpoint.
pl
p3
p2 p4
p5
3-4 OpenGL LINE FUNCTIONS giBegin (GL_LINE_LOOP);
glVertex2iv (pl);
glVertex2iv (p2);
glVertex2iv (p3);
glVertex2iv (p4);
glVertex2iv (p5);
glEnd ( ) ;
• produces a closed polyline.
• the last coordinate endpoint in the sequence is
connected to the first coordinate endpoint of the polyline.
pl
p3
p2 p4
p5
3-5 LINE-DRAWING ALGORITHMS
A straight-line segment in a scene is defined by the coordinate positions for the endpoints of the segment.
1. To display the line on a raster monitor, the graphics system must
– first project the endpoints to integer screen coordinates and
– determine the nearest pixel positions along the line path between the two endpoints.
2. Then the line color is loaded into the frame buffer at the corresponding pixel coordinates.
3. Reading from the frame buffer, the video controller plots the screen pixels.
– This process digitizes the line into a set of discrete integer positions that, in general, only approximates the actual line path.
3-5 LINE-DRAWING ALGORITHMS
• On raster systems, lines are plotted with pixels, and step sizes in the horizontal and vertical directions are constrained by pixel separations.
• That is, we must "sample" a line at discrete positions and determine the nearest pixel to the line at sampled position. – Sampling is measuring the values of the function at equal
intervals
• Idea: A line is sampled at unit intervals in one coordinate and the corresponding integer values nearest the line path are determined for the other coordinate.
Towards the Ideal Line
• We can only do a discrete approximation
• Illuminate pixels as close to the true path as possible, consider bi-level display only – Pixels are either lit or not lit
• In the raster line alg., – we sample at unit intervals and
– determine the closest pixel position to the specified line path at each step
What is an ideal line
• Must appear straight and continuous
– Only possible with axis-aligned and 45o lines
• Must interpolate both defining end points
• Must have uniform density and intensity
– Consistent within a line and over all lines
– What about anti-aliasing ?
• Aliasing is the jagged edges on curves and diagonal lines in a
bitmap image.
• Anti-aliasing is the process of smoothing out those jaggies.
– Graphics software programs have options for anti-aliasing text and
graphics.
– Enlarging a bitmap image accentuates the effect of aliasing.
• Must be efficient, drawn quickly
– Lots of them are required
Simple Line
The Cartesian slope-intercept
equation for a straight line is :
y = mx + b
with m as the slope of the line
and b as the y intercept.
Simple approach:
• increment x, solve for y
Line-Drawing Algorithms:
DDA
Bresenham’s Midpoint
Algorithm
Algorithms for displaying lines are based on the Cartesian
slope-intercept equation
y = m.x + b
where m and b can be calculated from the line endpoints:
m = (y1-y0) / (x1-x0)
b = y0 - m. x0
For any x interval x along a line the corresponding y interval
y = m.x
y0
y1
x0 x1
Simple Line
Based on slope-intercept
algorithm from algebra:
y = mx + b
Simple approach:
increment x, solve for y
Floating point arithmetic
required
Does it Work?
It works for lines with a slope of
1 or less,
but doesn’t work well for lines
with slope greater than 1 – lines
become more discontinuous in
appearance and we must add
more than 1 pixel per column to
make it work.
Solution? - use symmetry.
Modify algorithm per octant
OR, increment along x-axis if dy<dx else increment along
y-axis
DDA Algorithm
• The digital differential analyser (DDA) is a scan-conversion line
algorithm based on using x or y.
• A line is sampled at unit intervals in one coordinate and the
corresponding integer values nearest the line path are determined for
the other coordinate.
Line with positive slope
• If m<=1,
– Sample at unit x intervals (dx=1)
– Compute successive y values as
• yk+1=yk+m 0<=k<=xend-x0
• Increment k by 1 for each step
• Round y to nearest integer value.
• If m>1,
– Sample at unit y intervals (dy=1)
– Compute successive x values as
• xk+1=xk+1/m 0<=k<=yend-y0
• Increment k by 1 for each step
• Round x to nearest integer value.
inline int round (const float a) { return int (a + 0.5); }
void lineDDA (int x0, int y0, int xEnd, int yEnd)
{
int dx = xEnd - x0, dy = yEnd - y0, steps, k;
float xIncrement, yIncrement, x = x0, y = y0;
if (fabs (dx) > fabs (dy))
steps = fabs (dx);
else
steps = fabs (dy);
xIncrement = float (dx) / float (steps);
yIncrement = float (dy) / float (steps);
setPixel (round (x), round (y));
for (k = 0; k < steps; k++) {
x += xIncrement;
y += yIncrement;
setPixel (round (x), round (y));
}
}
DDA algorithm
• Need a lot of floating point arithmetic.
– 2 ‘round’s and 2 adds per pixel.
• Is there a simpler way ?
• Can we use only integer arithmetic ?
– Easier to implement in hardware.
Bresenham's line algorithm
• Accurate and efficient
• Uses only incremental integer calculations
The method is described for a line segment with a
positive slope less than one
The method generalizes to line segments of other slopes
by considering the symmetry between the various
octants and quadrants of the xy plane
Bresenham's line algorithm
• Decide what is
the next pixel
position
– (11,11) or
(11,12)
Specified
line path
10 11 12 13
10
11
12
13
Illustrating Bresenham’s Approach
• For the pixel position
xk+1=xk+1, which one
we should choose:
• (xk+1,yk) or (xk+1, yk+1) y=mx+b
yk
yk+1
yk+2
yk+3
xk xk+1 xk+2 xk+3
Bresenham’s Approach
• y=m(xk + 1)+b
• dlower=y-yk
=m(xk + 1)+b-yk
• dupper=(yk+1)-y
= yk+1 -m(xk + 1)-b
y
yk+1
xk+1
yk
dupper
dlower
• dlower- dupper= 2m(xk + 1)-2yk+2b-1
• Rearrange it to have integer calculations:
m=Δy/Δx
Decision parameter: pk= Δx(dlower- dupper)=2Δy.xk - 2Δx. yk + c
The Decision Parameter
Decision parameter: pk= Δx(dlower- dupper)=2Δy.xk - 2Δx. yk + c
• pk has the same sign with dlower- dupper since Δx>0.
• c is constant and has the value c= 2Δy + Δx(2b-1)
– c is independent of the pixel positions and is eliminated from
decision parameter pk.
• If dlower< dupper then pk is negative.
– Plot the lower pixel (East)
• Otherwise
– Plot the upper pixel (North East)
Succesive decision parameter
• At step k+1 pk+1= 2Δy.xk+1 - 2Δx. yk+1 + c
• Subtracting two subsequent decision parameters yields:
pk+1-pk= 2Δy.(xk+1-xk) - 2Δx. (yk+1-yk)
• xk+1=xk+1 so
pk+1= pk + 2Δy - 2Δx. (yk+1-yk)
– yk+1-yk is either 0 or 1 depending on the sign of pk
• First parameter p0
– p0=2 Δy - Δx
Bresenham's Line-Drawing Algorithm for I m I < 1
1. Input the twoline endpoints and store the left endpoint in (x0 ,y0).
2. Load (x0 ,y0) into the frame buffer; that is, plot the first point.
3. Calculate constants Δx, Δy, 2Δy, and 2Δy - 2Δx, and obtain the starting value for the decision parameter as
p0=2 Δy - Δx
4. At each xk along the line, starting at k = 0, perform the following test:
If pk < 0, the next point to plot is (xk+1, yk) and
pk+1=pk + 2Δy
Otherwise, the next point to plot is (xk+1, yk+1) and
pk+1=pk + 2Δy - 2Δx
5. Repeat step 4 Δx -1 times.
Trivial Situations: Do not need Bresenham
line horizontal0 m
xym line1
line vertical m
Example
• Draw the line with endpoints (20,10) and (30, 18).
– Δx=30-20=10, Δy=18-10=8,
– p0 = 2Δy – Δx=16-10=6
– 2Δy=16, and 2Δy - 2Δx=-4
• Plot the initial position at (20,10), then
Example
• Line end points:
• Deltas:
)11,9(),;)8,5(), 1100 (( yxyx
3;4 dydx
NEp
dx-dy ,p
2
0246
)()(2)85(initially
Graph
13
12
11
10
9
8
7
6 4 5 6 7 8 9 10 11
Continue the process...
13
12
11
10
9
8
7
6 4 5 6 7 8 9 10 11
Graph
13
12
11
10
9
8
7
6 4 5 6 7 8 9 10 11
Graph
13
12
11
10
9
8
7
6 4 5 6 7 8 9 10 11
Graph
13
12
11
10
9
8
7
6 4 5 6 7 8 9 10 11
/* Bresenham line-drawing procedure for |m| < 1.0. */ void lineBres (int x0, int y0, int xEnd, int yEnd) { int dx = fabs (xEnd - x0), dy = fabs(yEnd - y0); int x, y, p = 2 * dy - dx; int twoDy = 2 * dy, twoDyMinusDx = 2 * (dy - dx);
/* Determine which endpoint to use as start position. */ if (x0 > xEnd) { x = xEnd; y = yEnd; xEnd = x0; } else { x = x0; y = y0; } setPixel (x, y);
while (x < xEnd) { x++; if (p < 0) p += twoDy; else { y++; p += twoDyMinusDx; } setPixel (x, y); } }
0<m<1
0>m>-1
m>1
m>1
0<m<1
0>m>-1
m<-1
m<-1
Line-drawing algorithm should work in every
octant, and special cases
Simulating the
Bresenham
algorithm in
drawing 8 radii on a
circle of radius 20
Horizontal, vertical
and 45 radii
handled as special
cases
Circle / Curve Drawing in OpenGL
• Routines for drawing circles or ellipses are not
included in the OpenGL core library.
– Does include functions for displaying Bezier splines
• GLU (OpenGL Utility) library has some routines
for drawing spheres, cylinders, B-splines.
• Rational B-splines can be used to display circles
and ellipses.
• GLUT (OpenGL Utility Toolkit) has some
routines to display 3D shapes such as cones,
spheres
– All these discussed later…
Another method:
Approximate it using
a polyline.
• Explicit: y = f(x)
Scan Converting Circles
2 2y R x
We could draw a quarter circle by incrementing x from 0 to R in unit steps and solving for +y for each step.
22
222
)(
)()(
cc
cc
xxRyy
Ryyxx
Method needs lots of computation, and gives non-uniform
pixel spacing
Scan Converting Circles
• Parametric: cos
sin
x R
y R
Draw quarter circle by stepping through the angle from 0 to 90 -avoids large gaps but still unsatisfactory -How to set angular increment Computationally expensive trigonometric calculations
Scan Converting Circles
• Implicit: f(x,y) = x2+y2-R2
If f(x,y) = 0 then it is on the circle. f(x,y) > 0 then it is outside the circle. f(x,y) < 0 then it is inside the circle.
Try to adapt the Bresenham midpoint approach
Again, exploit symmetries
Generalising the Bresenham midpoint
approach
• Set up decision parameters for finding the
closest pixel to the cırcumference at each
sampling step
– Avoid square root calculations by considering the
squares of the pixel separation distances
• Use direct comparison without squaring.
Adapt the midpoint test idea: test the halfway
position between pixels to determine if this
midpoint is inside or outside the curve
This gives the midpoint algorithm for circles
Can be adapted to other curves: conic sections
Eight-way Symmetry
- only one octant’s calculation needed
The 2nd Octant is a good arc to draw
• It is a well-defined function in this domain
– single-valued
– no vertical tangents: |slope| 1
• Lends itself to the midpoint approach
– only need consider E or SE
• Implicit formulation F(x,y) = x
2 + y
2 – r
2
– For (x,y) on the circle, F(x,y) = 0
– F(x,y) > 0 (x,y) Outside
– F(x,y) < 0 (x,y) Inside
Choose E or SE
• Decision variable d is x 2 + y 2 – r 2
• Then d = F(M) 0 SE
• Or d = F(M) < 0 E
E
SE
Mideal
curve
F (M) 0 SE
current
pixel
E
SE
M
ideal
curve
F (M) < 0 E
Decision Variable p
As in the Bresenham line algorithm we
use a decision variable to direct the
selection of pixels.
Use the implicit form of the circle
equation
p = F (M ) = x
2 + y
2 – r
2
Midpoint coordinates are )2
1,1( kk yx
222 )2
1()1(
)2
1,1(
ryx
yxFp
kk
kkcirck
Assuming we have just plotted point at
(xk,yk) we determine whether move E or SE
by evaluating the circle function at the
midpoint between the two candidate pixel
positions
pk is the decision variable
if pk <0 the midpoint is inside the circle
Thus the pixel above the midpoint is closer to the ideal
circle, and we select pixel on scan line yk. i.e. Go E
If pk >0 the midpoint is outside the circle.
Thus the pixel below the midpoint is closer
to the ideal circle, and we select pixel on
scan line yk-1. i.e. Go SE
Calculate successive decision parameter values p by
incremental calculations.
22
1
2
111
)2
1(]1)1[(
)2
1,1(
ryx
yxFp
kk
kkcirck
recursive definition for successive decision
parameter values p
1)()()1(2
)2
1(]1)1[(
)2
1,1(
1
22
11
22
1
2
111
kkkkkkk
kk
kkcirck
yyyyxpp
ryx
yxFp
Where yk+1 = yk if p<0 (move E)
yk+1 = yk-1 if p>0 (move SE)
yk+1 and xk+1 can also be defined recursively
Initialisation
x0 = 0, y0 = r
Initial decision variable found by evaluating circle
function at first midpoint test position
r
rr
rFp circ
4
5
)2
1(1
)2
1,1(
22
0
For integer radius r p0 can be rounded to p0 =1-r
since all increments are integer.
Midpoint Circle Algorithm (cont.)
Example
• r=10
Conic Sections
A conic section, or conic, is any figure that can be
formed by slicing a double cone with a plane
Parabola Circle Ellipse Hyperbola
General equation of a Conic Section
• Parabola: A = 0 OR B = 0
• Circle: A = B
• Ellipse: AB, but both have the same sign
• Hyperbola: A and B have different signs
022 FEyDxCxyByAx
Ellipses
F1
F2
P = (x,y)
d1
d2
Ellipse generated about foci F1 and F2
d1 + d2 = constant
Scan Converting Ellipses
• a is the length of the semi-major axis along the x axis.
• b is the length of the semi-minor axis along the y axis.
• The midpoint algorithm can also be applied to ellipses.
• For simplicity, we draw only the arc of the ellipse that lies in the
first quadrant, the other three quadrants can be drawn by
symmetry
a
b
2 2 2 2 2 2( , ) 0F x y b x a y a b
Regions
Region 1
Region 2
Fill area : an area that is filled with solid colour or pattern
Identifying a concave polygon
• has at least one interior angle >180 degrees
• extensions of some edges will intersect other
edges
One test:
Express each polygon edge as a vector, with a
consistent orientation.
Can then calculate cross-products of adjacent
edges
Identifying a concave polygon
• When polygon edges are oriented with an anti-
clockwise sense
– z coordinate of the cross product at convex vertex has
positive sign
– concave vertex gives negative sign
Normals
• Every plane has a vector n normal (perpendicular,
orthogonal) to it
• n = u x v (vector cross product)
u
v
P
xyyx
zxxz
yzzy
vuvu
vuvu
vuvu
vu
Vector method for splitting concave polygons
• E1=(1,0,0) E2=(1,1,0)
• E3=(1,-1,0) E4=(0,2,0)
• E5=(-3,0,0) E6=(0,-2,0)
• All z components have 0 value.
• Cross product of two vectors EjxEk is perpendicular to them with z component
EjxEky-EkxEjy
E1
E2 E3
E4
E5
E6
0 1 2 3
1
2
3
Example continued
• E1xE2= (0,0,1) E2xE3= (0,0,-2) E3xE4= (0,0,2) E4xE5= (0,0,6) E5xE6= (0,0,6) E6xE1= (0,0,2)
• Since E2xE3 has negative sign, split the polygonalong the line of vector E2
E1
E2 E3
E4
E5
E6
0 1 2 3
1
2
3
Rotational method
• Rotate the polygon so that each vertex in turn is
at coordinate origin.
• If following vertex is below the x axis, polygon is
concave.
• Split the polygon by x axis.
E1
E2 E3
E4
E5
E6
A winding number is an attribute of a point with respect to a polygon
that tells us how many times the polygon encloses (or wraps around)
the point. It is an integer, greater than or equal to 0. Regions of
winding number 0 (unenclosed) are obviously outside the polygon,
and regions of winding number 1 (simply enclosed) are obviously
inside the polygon.
Initially 0
+1: edge crossing the line from right to left
-1: left to right
Inside-Outside? nonzero winding-number rule
Winding Number
• Count clockwise encirclements of point
• Alternate definition of inside: inside if winding
number 0
winding number = 2
winding number = 1
Polygon tables
• store descriptions of polygon geometry and
topology, and surface parameters: colour,
transparency, light-reflection
• organise in 2 groups
– geometric data
– attribute data
Polygon Tables:
Geometric data
•Data can be used for consistency checking
•Additional geometric data stored: slopes, bounding boxes
Shared Edges
• Vertex lists will draw filled polygons correctly but if we
draw the polygon by its edges, shared edges are
drawn twice
• Can store mesh by edge list
Inward and Outward Facing
Polygons
• The order {v1, v6, v7} and {v6, v7, v1} are equivalent in that
the same polygon will be rendered by OpenGL but the
order {v1, v7, v6} is different
• The first two describe outwardly
facing polygons
• Use the right-hand rule =
counter-clockwise encirclement
of outward-pointing normal
• OpenGL can treat inward and
outward facing polygons differently
OpenGL Primitives
• GL_POLYGON
• GL_TRIANGLES
• GL_TRIANGLE_STRIP
• GL_TRIANGLE_FAN
• GL_QUADS
• GL_QUADSTRIP
Modelling a Cube
GLfloat vertices[][3] = {{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0},
{1.0,1.0,-1.0}, {-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},
{1.0,-1.0,1.0}, {1.0,1.0,1.0}, {-1.0,1.0,1.0}};
GLfloat colors[][3] = {{0.0,0.0,0.0},{1.0,0.0,0.0},
{1.0,1.0,0.0}, {0.0,1.0,0.0}, {0.0,0.0,1.0},
{1.0,0.0,1.0}, {1.0,1.0,1.0}, {0.0,1.0,1.0}};
Model a color cube for rotating cube program
Define global arrays for vertices and colors
3.17 : OpenGL vertex arrays
Drawing a polygon from a list of indices
Draw a quadrilateral from a list of indices into the array vertices and use color corresponding to first index
void polygon(int a, int b, int c
, int d)
{
glBegin(GL_POLYGON);
glColor3fv(colors[a]);
glVertex3fv(vertices[a]);
glVertex3fv(vertices[b]);
glVertex3fv(vertices[c]);
glVertex3fv(vertices[d]);
glEnd();
}
Draw cube from faces
void colorcube( )
{
polygon(0,3,2,1);
polygon(2,3,7,6);
polygon(0,4,7,3);
polygon(1,2,6,5);
polygon(4,5,6,7);
polygon(0,1,5,4);
}
0
5 6
2
4 7
1
3
Note that vertices are ordered so that
we obtain correct outward facing normals
Efficiency
• The weakness of our approach is that we are building the model in the application and must do many function calls to draw the cube
• Drawing a cube by its faces in the most straight forward way requires – 6 glBegin, 6 glEnd
– 6 glColor
– 24 glVertex
– More if we use texture and lighting
Vertex Arrays
• OpenGL provides a facility called vertex arrays that
allows us to store array data in the implementation
• Six types of arrays supported
– Vertices
– Colors
– Color indices
– Normals
– Texture coordinates
– Edge flags
• We will need only colors and vertices
Initialization
• Using the same color and vertex data, first we enable glEnableClientState(GL_COLOR_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
• Identify location of arrays glVertexPointer(3, GL_FLOAT, 0, vertices);
glColorPointer(3, GL_FLOAT, 0, colors);
3d arrays stored as floats data contiguous (offset)
data array
Mapping indices to faces
• Form an array of face indices
• Each successive four indices describe a face of
the cube
• Draw through glDrawElements which replaces
all glVertex and glColor calls in the display
callback
GLubyte cubeIndices[24] = {0,3,2,1,2,3,7,6
0,4,7,3,1,2,6,5,4,5,6,7,0,1,5,4};
Drawing the cube
• Method 1:
• Method 2:
for(i=0; i<6; i++) glDrawElements(GL_POLYGON, 4,
GL_UNSIGNED_BYTE, &cubeIndices[4*i]);
format of index data start of index data
what to draw number of indices
glDrawElements(GL_QUADS, 24,
GL_UNSIGNED_BYTE, cubeIndices);
Draws cube with 1 function call!!
OpenGL Character Functions
• Characters are defined as bitmap functions.
• Some predefined character sets are available in
GLUT.
• Display a bitmap GLUT character with
– glutBitmapCharacter (font, character)
– Use either the ASCII code (i.e. 65) or the specific
character (i.e. ‘A’)
• Can select a fixed-width fonts
– GLUT_BITMAP_8_BY_13 or GLUT_BITMAP_9_BY_15
– GLUT_BITMAP_TIMES_ROMAN_10
OpenGL Character Functions
• Define the lower left corner of the bitmap as
current raster position. glRasterPosition2i (x, y)
for (k=0; k<36;k++)
glutBitmapCharacter (GLUT_BITMAP_9_BY_15,text [k]);
Characters in text array is displayed starting from position (x,y) with
current color.
OpenGL Display Lists
• Structures for storing object descriptions
– Must define (name, create)
– Add contents
– Close
– Reference the list, with different display options
• In client-server environment, display list is
placed on server
– Can be redisplayed without sending primitives over
network each time
Display List Functions
• Creating a display list
GLuint listId;
void init()
{
listId = glGenLists( 1 ); //generates a unique identifier
glNewList( listId, GL_COMPILE );
/* other OpenGL routines */
glEndList();
}
• Call a created list
void display()
{
glCallList( listId ); //executes the display list
}
Display Lists and State
• Most OpenGL functions can be put in display
lists
– Can put one list in another
• State changes made inside a display list persist
after the display list is executed
Hierarchy and Display Lists
•Consider model of a car
- Create display list for chassis
- Create display list for wheel
glNewList( CAR, GL_COMPILE );
glCallList( CHASSIS );
glTranslatef( … );
glCallList( WHEEL );
glTranslatef( … );
glCallList( WHEEL );
…
glEndList();
Handling Input in OpenGL
• 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
Request Mode
• Input provided to program only when user
triggers the device
• Typical of keyboard input
– Can erase (backspace), edit, correct until the enter
(return) key (the trigger) is depressed
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
GLUT Event Loop
• Recall that the last line in main.c for a program
using GLUT must be
glutMainLoop();
which 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
Event Types
• Window: resize, expose
• 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
Callbacks
• Programming interface for event-driven input
• Define a callback function for each type of event
the graphics system recognizes
• This user-supplied function is executed when
the event occurs
• GLUT example:
glutMouseFunc(mymouse)
mouse callback function
Interaction in OpenGL : callbacks
Handling Input Events • You can use these routines to register callback commands that are
invoked when specified events occur.
• glutKeyboardFunc(void (*func)(unsigned char key, int x, int y)) and
glutMouseFunc(void (*func)(int button, int state, int x, int y)) allow you to
link a keyboard key or a mouse button with a routine that's invoked when
the key or mouse button is pressed or released.
• glutMotionFunc(void (*func)(int x, int y)) registers a routine to call back
when the mouse is moved while a mouse button is also pressed.
• glutReshapeFunc(void (*func)(int w, int h)) indicates what action should
be taken when the window is resized.
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 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
Display function
• After the window is created, but before you enter the
main loop, you should register callback functions using
the following routines.
void glutDisplayFunc(void (*func)(void));
• Specifies the function that's called whenever the
contents of the window need to be redrawn. The
contents of the window may need to be redrawn when
the window is initially opened, when the window is
popped and window damage is exposed, and when
glutPostRedisplay() is explicitly called.
Post redisplay
void glutPostRedisplay(void);
Marks the current window as needing to be redrawn.
At the next opportunity, the callback function registered by
glutDisplayFunc() will be called.
• 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();
which 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
Keyboard function
glutKeyboardFunc(void (*func)(unsigned char key, int x, int y))
• Specifies the function, func, that's called when a key that
generates an ASCII character is pressed.
• The key callback parameter is the generated ASCII value.
• The x and y callback parameters indicate the location of the
mouse (in window-relative coordinates) when the key was
pressed.
Mouse function
void glutMouseFunc(void (*func)(int button, int state, int x, int y));
• Specifies the function, func, that's called when a mouse button is pressed or released.
• The button callback parameter is one of GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON, or GLUT_RIGHT_BUTTON.
• The state callback parameter is either GLUT_UP or GLUT_DOWN,depending upon whether the mouse has been released or pressed.
• The x and y callback parameters indicate the location (in window-relative coordinates) of the mouse when the event occurred.
Motion function
void glutMotionFunc(void (*func)(int x, int y));
• Specifies the function, func, that's called when
the mouse pointer moves within the window
while one or more mouse buttons is pressed.
• The x and y callback parameters indicate the
location (in window-relative coordinates) of the
mouse when the event occurred.
Reshape function
void glutReshapeFunc(void (*func)(int width, int height));
• Specifies the function that's called whenever the window is resized or moved. The argument func is a pointer to a function that expects two arguments, the new width and height of the window.
• Typically, func calls glViewport(), so that the display is clipped to the new size, and it redefines the projection matrix so that the aspect ratio of the projected image matches the viewport, avoiding aspect ratio distortion.
• If glutReshapeFunc() isn't called or is deregistered by passing NULL, a default reshape function is called, which calls glViewport(0, 0, width, height).
• Viewports are discussed in H&B Ch.6
Example: handling a mouse button press
void myKeyboardFunc (unsigned char key, int x, int y)
{
switch (key) {
case 'f':
removeFirstPoint();
glutPostRedisplay();
break;
case 27: // Escape key
exit(0);
break;
}
}
Example: handling a mouse button press
// use left button presses place a control point.
void myMouseFunc( int button, int state, int x, int y ) {
if ( button==GLUT_LEFT_BUTTON &&
state==GLUT_DOWN ) {
float xPos = ((float)x)/((float)(windowWidth-1));
float yPos = ((float)y)/((float)(windowHeight-1));
yPos = 1.0f-yPos;
// Flip value since y position is from top row.
addNewPoint( xPos, yPos );
glutPostRedisplay();
}
}
Positioning
• The position in the screen window is usually measured in
pixels with the origin at the top-left corner
• Consequence of refresh done from top to bottom
• OpenGL uses a world coordinate system with origin at the
bottom left
• Must invert y coordinate returned by callback by height
of window
• y = h – y;
(0,0) h
w
Obtaining the window size
• To invert the y position we need the window
height
– Height can change during program execution
– Track with a global variable
– New height returned to reshape callback
Terminating a program
• In our original programs, there was no way to
terminate them through OpenGL
• We can use the simple mouse callback
void mouse(int btn, int state, int x, int y)
{
if(btn==GLUT_RIGHT_BUTTON && state==GLUT_DOWN)
exit(0);
}
Using the mouse position
• In the next example, we draw a small square at
the location of the mouse each time the left mouse
button is clicked
• This example does not use the display callback
but one is required by GLUT; We can use the
empty display callback function
mydisplay(){}
Drawing squares at cursor location
void mymouse(int btn, int state, int x, int y)
{
if(btn==GLUT_RIGHT_BUTTON && state==GLUT_DOWN)
exit(0);
if(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); /* a random color */
glBegin(GL_POLYGON);
glVertex2f(x+size, y+size);
glVertex2f(x-size, y+size);
glVertex2f(x-size, y-size);
glVertex2f(x+size, y-size);
glEnd();
}