1/26/05

In one of our previous classes we looked at a simple algorithm that produces a fractal image. We considered a triangle and select a random point within it as the "current point". Take the midpoint of the segment connecting the current point and a random vertex of the triangle; this becomes the new current point. Plot each current point as it is determined. Repeat "several" times. Here's the output of a program with 50 iterations (50 random points used):

gasket-50

And this one is the output after 5000 iterations (5000 random pointswere used).

gasket-5000

Here's a different way to produce the same image. Connect the midpoints of the edges of a red triangle. This subdivides the triangle into 4 triangles. Color the middle triangle white. Now repeat the procedure (recursively) on the other three triangles.

Here's our author's program using the first of the two methods:


/* gasket.c, by Ed Angel, modfied by Mark Harris
Draws a red Sierpinski gasket*/

#include <GL/glut.h>
#include <stdlib.h>

void myinit(void)
{

/* attributes */

glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
glColor3f(1.0, 0.0, 0.0); /* draw in red */

/* set up viewing */
/* 500 x 500 window with origin lower left */

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 500.0, 0.0, 500.0);
glMatrixMode(GL_MODELVIEW);
}

void display( void )
{

/* define a point data type */

typedef GLfloat point2[2];

point2 vertices[3]={{0.0,0.0},{250.0,500.0},{500.0,0.0}}; /* A triangle */

int i, j, k;
point2 p ={75.0,50.0}; /* An arbitrary initial point */

glClear(GL_COLOR_BUFFER_BIT); /*clear the window */


/* computes and plots 5000 new points */

for( k=0; k<50000; k++)
{
j=rand()%3; /* pick a vertex at random */


/* Compute point halfway between vertex and old point */

p[0] = (p[0]+vertices[j][0])/2.0;
p[1] = (p[1]+vertices[j][1])/2.0;

/* plot new point */

glBegin(GL_POINTS);
glVertex2fv(p);
glEnd();

}
glFlush(); /* clear buffers */
}


void main(int argc, char** argv)
{

/* Standard GLUT initialization */

glutInit(&argc,argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); /* default, not needed */
glutInitWindowSize(500,500); /* 500 x 500 pixel window */
glutInitWindowPosition(0,0); /* place window top left on display */
glutCreateWindow("Sierpinski Gasket"); /* window title */
glutDisplayFunc(display); /* display callback invoked when window opened */

myinit(); /* set attributes */

glutMainLoop(); /* enter event loop */
}

We went over the program in class; see chapter 2 of our text for similar details.

We can group OpenGL functions into 6 categories:

  1. primitive functions: draw lines, points, etc.
  2. attribute functions: state variables such as color, width
  3. viewing functions: choose lens for camera
  4. transformation functions: rotate, translate, scale objects
  5. input functions: read mouse, keyboard
  6. control functions: interact with other windows

 Families of related functions have common names with different endings indicating the types of the argument(s). For example, you'll use the glVertex* family often. glVertex2i takes two GLint arguments (x and y coordinates), while glVertex3f takes three GLfloat arguments.

GLfloat is defined to be e.g. float or double, but using

#define GLfloat float

in an OpenGL header file allows the type to be changed later.

glVertex3fv takes a pointer to an array (vector) of three GLfloats. Using a typedef for such a vector:


typedef GLfloat point3[3];

lets us use convenient declarations.

The most commonly used OpenGL functions are probably glBegin, glEnd, and the glVertex family. For example:


glBegin(GL_POINTS);
glVertex3fv(p);
glEnd();

will draw the point p. The constant argument to glBegin can be one of:

GL_POINTS, GL_LINES, GL_LINE_STRIP, GL_LINE_LOOP, GL_TRIANGLES, GL_TRIANGLE_STRIP, GL_TRIANGLE_FAN, GL_QUADS, GL_QUAD_STRIP, and GL_POLYGON

We'll explore several of these in class. We'll try a few programs which draw OpenGL primitives. We'll start by setting the clear color:

glClearColor(1,1,1,1);

and clearing the window:


glClear(GL_COLOR_BUFFER_BIT); /*clear the window */

We'll also need to set the color for the primitives we'll be drawing:


glColor3f(0.0, 0.0, 0.0); /* draw in black */

When using the glBegin(GL_POLYGON), you can show a filled or outlined polygon by changing a global state variable with glPolygonMode. Just specify e.g. glPolygonMode(GL_FRONT,GL_LINE) for outline or glPolygonMode(GL_FRONT,GL_FILL) for filled polygons. The first parameter can be one of GL_FRONT, GL_BACK, or GL_FRONT_AND_BACK depending on which sides of the polygon you want to draw. With our current parallel projection, front does fine by itself -- we'll look at polygons from both sides later.

You may have wondered about the fourth color parameter; e.g.


glClearColor(1.0, 1.0, 1.0, 1.0);

This gives a transparency factor from 0 (transparent) to 1 (opaque). It's ignored unless blending is enabled:


glEnable(GL_BLEND);

Then you need to specify the way in which blending is performed; e.g.


glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

is the most common method. Following is a program which draws some red triangles (pie wedges) over a blue background, increasing the opacity of the triangles each time:


/* Shades of blue, 1/18/01 by late Mark Harris.
Modified by Rahman tashakkori spring 2004*/
#include <stdlib.h>
#include <GL/glut.h>
#include <math.h>
double PI = 3.1415926535898;
void myinit(void)
{
/* attributes */
glClearColor(0.0, 0.0, 1.0, 1); /* blue background */
// Enable use of alpha factor and assign normal
// foreground/background mixing:
// uncommnet if you want to try but you also have to uncomment
// the line marked with (****) below
// glEnable(GL_BLEND);

/* set up viewing */
/* 50 x 50 window with origin lower left */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 50.0, 0.0, 50.0);
glMatrixMode(GL_MODELVIEW);
}

void display( void )
{
glClear(GL_COLOR_BUFFER_BIT); /*clear the window */
const int N=10;
double t=0,h=2*PI/N;
const double RAD=50;
double rx=RAD,ry=0;
int i;
for(i=0;i<N;i++){
// Draw N pie wedges of different transparency
//(****) glColor4f(0.0, 0.0, 1.0, (float)i/N); /* draw in shades of red/blue */
glColor3f(1.0-(float)i/N, 0.0, (float)i/N); /* draw in shades of red/blue */
glBegin(GL_POLYGON);
glVertex2f(25,25);
glVertex2f(25+rx,25+ry);
t+=h;
rx=RAD*cos(t);
ry=RAD*sin(t);
glVertex2f(25+rx,25+ry);
glEnd();
}

glFlush(); /* clear buffers */
}

void main(int argc, char** argv)
{
/* Standard GLUT initialization */
glutInit(&argc,argv);
glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB); /* default, not needed */
glutInitWindowSize(500,500); /* 500 x 500 pixel window */
glutInitWindowPosition(0,0); /* place window top left on display */
glutCreateWindow("Test"); /* window title */
glutDisplayFunc(display); /* display callback invoked when window opened */
myinit(); /* set attributes */
glutMainLoop(); /* enter event loop */
}

Here's the image produced:

shades