chapter 2
Programming with OpenGL
Objectives
- Development of the OpenGL API
- OpenGL Architecture
- OpenGL as a state machine
- Functions
- Types
- Formats
- Simple program
Early History of APIs
IFIPS (1973) formed two committees to come up with a standard graphics API
- Graphical Kernel System (GKS)
- 2D but contained good workstation model
- Core
- Both 2D and 3D
GKS adopted as IS0 and later ANSI standard (1980s)
- GKS not easily extended to 3D (GKS-3D)
- Far behind hardware development
Programmers Hierarchical Graphics System (PHIGS)
- arose from the CAD community
- Database model with retained graphics (structures)
X Window System
- DEC/MIT effort
- Client-server architecture with graphics
PEX combined X and PHIGS
- Not easy to use (all the defects of each)
SGI and GL Silicon Graphics (SGI)
- revolutionized the graphics workstation by implementing the pipeline in hardware (1982)
- To access the system, application programmers used a library called GL
- With GL, it was relatively simple to program three dimensional interactive applications
OpenGL
- The success of GL lead to OpenGL (1992), a
platform-independent API that was
- Easy to use
- Close enough to the hardware to get excellent performance
- Focus on rendering
- Omitted windowing and input to avoid window system dependencies
OpenGL Evolution
- Controlled by an Architectural Review Board (ARB)
- Members include SGI, Microsoft, Nvidia, HP, 3DLabs, IBM,…….
- It is now relatively stable (newest version has added programmable shaders)
- Evolution reflects new hardware capabilities
- 3D texture mapping and texture objects
- Vertex programs
- Allows for platform specific features through extensions
OpenGL Libraries
- OpenGL core library
- OpenGL32 on Windows
- GL on most unix/linux systems
- OpenGL Utility Library (GLU)
- Provides functionality in OpenGL core but avoids having to rewrite code
- Links with window system
- GLX for X window systems
- WGL for Windows
- AGL for Macintosh
- GLUT OpenGL Utility Library (GLUT)
- Provides functionality common to all window systems
- Open a window
- Get input from mouse and keyboard
- Menus
- Event-driven
- Code is portable but GLUT lacks the functionality of
a good toolkit for a specific platform
- Slide bars
- Provides functionality common to all window systems
Software Organization
OpenGL Architecture
OpenGL Functions
- Primitives
- Points
- Line Segments
- Polygons
- Attributes
- Transformations
- Viewing
- Modeling
- Control Input (GLUT)
OpenGL State
- OpenGL is a state machine
- OpenGL functions are of two types
- Primitive generating
- Can cause output if primitive is visible
- How vertices are processed and appearance of primitive are controlled by the state
- State changing
- Transformation functions
- Attribute functions
- Primitive generating
Lack of Objects
- 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
- Easy to create overloaded functions in C++ but issue is efficiency
suffix Data type C type OpenGL type b 8 bit int signed char GLbyte s 16 bit int short GLshort i 32 bit int int/long GLint,GLsizei f 32 bit fp float GLfloat,GLclampf d 64 bit fp double GLdouble,GLclampd ub 8 bit unsign. int unsigned char GLubyte,GLboolean us 16 bit unsign. int unsigned short GLushort ui 32 bit uns. int. unsigned int/long GLuint,GLenum,GLbitfield
OpenGL function format
The command for specifying vertex coordinates has the
following forms :
glVertex{2|3|4}{sifd}[v](TYPE coords);You must specify 2, 3, or 4 coordinates per vertex. You must specify short, integer, float or double as the type of coordinates. You may directly specify the coordinates or supply an array of coordinates in the v form of the command. Several examples follow: glVertex2s(2,3); glVertex3d(0.0,0.0, 3.14159); glVertex4f(2.3,1.0,-2.2,2.0); GLdouble dvect[ ] = {5.0,9.0,1992.0}; glVertex3dv(dvect); //vform |
OpenGL #defines
- Most constants are defined in the include files gl.h, glu.h
and glut.h
- Note #include
<GLUT/glut.h> should automatically include the others (using XCode or gcc) - Examples
- Note #include
glBegin(GL_POLYGON)
glClear(GL_COLOR_BUFFER_BIT)
- include files also define OpenGL data types: GLfloat, GLdouble,….
OpenGl uses a very simple command
syntax. All functions begin with gl and each additional
word is capitialized :glClearColor(0.0,0.0,0.0,0.0); glPushMatrix(); Constants are in uppercase, beginning with GL_, each word is separated by the _ : GL_POLYGONS, GL_COLOR_BUFFER_BIT
|
A Simple Program
Generate a square on a solid background
square.c
#include
void mydisplay(){
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
glFlush(); }
int main(int argc, char** argv){
glutInit(&argc, argv);
glutCreateWindow("simple");
glutDisplayFunc(mydisplay);
glutMainLoop(); }
Event Loop
- Note that the program defines a display callback function
that is named mydisplay in this example
- Every glut program must have a display callback
- The display callback is executed whenever the display must be refreshed, for example when the window is opened in glutMainLoop()
- The main function ends with the program entering an event loop
Defaults
- simple.c is too simple
- Makes heavy use of state variable default values for
- Viewing
- Colors
- Window parameters
- Next version will make the defaults more explicit
Programming with OpenGL Part 2: Complete Programs
Objectives
- Refine the first program
- Alter the default values
- Introduce a standard program structure
- Simple viewing
- Two-dimensional viewing as a special case of three-dimensional viewing
- Fundamental OpenGL primitives
- Attributes
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
- sets the state variables
- callbacks
- Display function
- Input and window functions
- main():
Square.c revisited
- In this version, we will see the same output but have defined all the relevant state values through function calls with the default values
- In particular, we set
- Colors
- Viewing conditions
- Window properties
main.c
#include <GLUT/glut.h> //include gl
int main(int argc, char** argv) {
glutInit(&argc,argv);
//set window properties
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500,500);
glutInitWindowPosition(0,0);
glutCreateWindow("simple");
glutDisplayFunc(mydisplay); //display callback
init(); //set OpenGL state
glutMainLoop();//enter event loop}
GLUT functions
- glutInit allows application to get command line arguments and initializes system
- glutInitDisplayMode requests properties for the window(the
rendering context)
- RGB color
- Single buffering
- Properties logically ORed together
- glutWindowSize
- in pixels
- glutWindowPosition
- from top-left corner of display
- glutCreateWindow
- create window with title “simple”
- glutDisplayFunc
- display callback
- glutMainLoop
- enter infinite event loop
init.c
void init() {
glClearColor (0.0, 0.0, 0.0, 1.0); //black opaque window
glColor3f(1.0, 1.0, 1.0); //white color
glMatrixMode (GL_PROJECTION);
glLoadIdentity ();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0); } //view volume 2X2X2 at origin
Coordinate Systems
- The units of a glVertex are determined by the application and are called object or problem coordinates
- The viewing specifications are in world coordinates and it is the size of the viewing volume that determines what will appear in the image
- Internally, OpenGL will convert to camera coordinates and later to screen coordinates
OpenGL Camera
- OpenGL places a camera at the origin pointing in the negative z direction
- The default viewing volume is a box centered at the origin with a side of length 2
glOrtho(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble near, GLdouble far);
All parameters are a measurement of DISTANCE from the camera. Unlike a real camera, objects behind the camera are visible when using an orthographic projection. This can be a little confusing.
The camera is at (0, 0, 0) looking down the -z axis. The far plane is located one unit down the -z axis, therefore the far plane is at -z = 1 or z = -1. The near plane is located negative one unit down the -z axis, therefore the near plane is at -z = -1 or z = 1. We are looking at the far plane and the near plane is behind us.
Orthographic Viewing
- In the default orthographic view, points are projected forward along the z axis onto the plane, z = 0
Transformations and Viewing
- In OpenGL, the projection is carried out by a projection matrix (transformation)
- There is only one set of transformation functions so we must
set the matrix mode first
glMatrixMode (GL_PROJECTION)
- Transformation functions are incremental so we start with an
identity matrix and alter it with a projection matrix that
gives the view volume
glLoadIdentity ();
glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
Two- and three-dimensional viewing
- In glOrtho(left, right, bottom, top, near, far) the near and far distances are measured from the camera
- Two-dimensional vertex commands place all vertices in the plane, z = 0
- If the application is in two dimensions, we can use the function
- In two dimensions, the view or clipping volume becomes a
clipping window
mydisplay.c
void mydisplay() {
glClear(GL_COLOR_BUFFER_BIT);
glBegin(GL_POLYGON);
glVertex2f(-0.5, -0.5);
glVertex2f(-0.5, 0.5);
glVertex2f(0.5, 0.5);
glVertex2f(0.5, -0.5);
glEnd();
glFlush(); }
gluOrtho2D(left, right,bottom,top)
OpenGL Primitives
glBegin(GLenum mode);
where mode is the type of primitive to be drawn. The allowable 2D/3D primitives are
glEnd();
Drawing a Trangular fan
Drawing PointsA point can be displayed by specifying the size of the point and then drawing the point(s) as in:
Drawing LinesA line might be displayed by specifying a line width and then drawing the line(s).
|
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
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
RGB color
- Each color component is stored separately in the frame buffer
- Usually 8 bits per component in buffer
- Note in glColor3f the color values range from 0.0 (none) to 1.0 (all), while in 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
- Code
- Approximating a sphere with polygons (class question)
Viewports
- Do not have to use the entire window for the
image:
glViewport(x,y,w,h)
- Values in pixels (screen coordinates)
Programming with OpenGL Part 3: Three Dimensions
Objectives
- Develop a more sophisticated
three-dimensional
example
- Sierpinski gasket: a fractal
- Introduce hidden-surface removal
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
- Not much changes
- Going to 3D
Sierpinski Gasket (2D)
- Start with a triangle
- Connect bisectors of sides and remove central triangle
- Repeat
Example
- Five subdivisions
The gasket as a fractal
- Consider the filled area (black) and the perimeter (the length of all the lines around the filled triangles)
- As we continue subdividing the
- area goes to zero
- but the perimeter goes to infinity
- This is not an ordinary geometric object
- It is neither two- nor three-dimensional
- It is a fractal (fractional dimension) object
- Code - 2D gasket
Repeated Subdivision Gasket Program
#include <GLUT/glut.h>
/* a point data type >
typedef GLfloat point2[2];
/* initial triangle */
point2 v[]={{-1.0, -0.58}, {1.0, -0.58},
{0.0, 1.15}};
int n; /* number of recursive steps
void triangle( point2 a, point2 b,
point2 c)/*
display one triangle */ {
glBegin(GL_TRIANGLES);
glVertex2fv(a);
glVertex2fv(b);
glVertex2fv(c);
glEnd(); }
void divide_triangle(point2 a, point2
b,
point2 c, int m) {
/* triangle subdivision using vertex
numbers */
point2 v0, v1, v2;
int j;
if(m>0) {
for(j=0; j<2; j++)v0[j]=(a[j]+b[j])/2;
for(j=0; j<2; j++)v1[j]=(a[j]+c[j])/2;
for(j=0; j<2; j++)
v2[j]=(b[j]+c[j])/2;
divide_triangle(a, v0, v1, m-1);
divide_triangle(c, v1, v2, m-1);
divide_triangle(b, v2, v0, m-1); }
else(triangle(a,b,c)); /* draw triangle
at
end of recursion */ }
void display(void) {
glClear(GL_COLOR_BUFFER_BIT);
divide_triangle(v[0], v[1], v[2], n);
glFlush(); }
void myinit() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(-2.0, 2.0, -2.0, 2.0);
glMatrixMode(GL_MODELVIEW);
glClearColor (1.0, 1.0, 1.0,1.0)
glColor3f(0.0,0.0,0.0); }
int main(int argc, char **argv) {
n=4;
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB);
glutInitWindowSize(500, 500);
glutCreateWindow(“2D Gasket");
glutDisplayFunc(display);
myinit();
glutMainLoop(); }
- Code - repeated subdivision gasket
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
- We can subdivide each of the four faces
- Appears as if we remove a solid tetrahedron from the center leaving four smaller tetrahedra
- After 5 iterations
Example triangle code
void triangle( point a, point b, point c){
glBegin(GL_POLYGON);
glVertex3fv(a);
glVertex3fv(b);
glVertex3fv(c);
glEnd(); }
void divide_triangle(point a, point b, point c, int m) {
point v1, v2, v3;
int j;
if(m>0) {
for(j=0; j<3; j++) v1[j]=(a[j]+b[j])/2;
for(j=0; j<3; j++) v2[j]=(a[j]+c[j])/2;
for(j=0; j<3; j++) v3[j]=(b[j]+c[j])/2;
divide_triangle(a,v1, v2, m-1);
divide_triangle(c, v2, v3, m-1);
divide_triangle(b, v3, v1, m-1); }
else(triangle(a,b,c)); }void tetrahedron( int m) {
glColor3f(1.0,0.0,0.0);
divide_triangle(v[0], v[1], v[2], m);
glColor3f(0.0,1.0,0.0);
divide_triangle(v[3], v[2], v[1], m);
glColor3f(0.0,0.0,1.0);
divide_triangle(v[0], v[3], v[1], m);
glColor3f(0.0,0.0,0.0);
divide_triangle(v[0], v[2], v[3], m); }
Almost Correct
- 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
Hidden-Surface Removal
- We want to see only those surfaces in front of other surfaces
- OpenGL uses a hidden-surface method called the z-buffer algorithm that 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, to store depth information as geometry travels down the pipeline
- It must be requested in main
- Enabled in init
glEnable(GL_DEPTH_TEST)
- Cleared in the display callback
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH)