2/04/04

In our last class we talked about the idea of a depth buffer (also called a "z-buffer" since it is the z-coordinate, or vertical distance from the viewpoint, which is being buffered). When projecting three dimensions into two, we don't want background points to cover foreground points. We only plot a point if it is closer to the observer than the previous point in this position.

As an example, compare the Sierpinski tetrahedron graphed with and without depth buffering.  Here is the result with it:
 
And The one below shows the result without it.  In this all sides are drawn in the same order as they appear in the program.

 
To suppress the depth buffering, I just commented out the line

glEnable(GL_DEPTH_TEST); 

in the Angel code below:

/* Recursive subdivision of tetrahedron to form
3D Sierpinski gasket */


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

typedef float point[3];

/* initial tetrahedron */

point v[]={{0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},
{-0.816497, -0.471405, -0.333333}, {0.816497, -0.471405, -0.333333}};

static GLfloat theta[] = {0.0,0.0,0.0};

int n;

void triangle( point a, point b, point c)

/* display one triangle using a line loop for wire frame, a single
normal for constant shading, or three normals for interpolative shading */
{
glBegin(GL_POLYGON);
glNormal3fv(a);
glVertex3fv(a);
glVertex3fv(b);
glVertex3fv(c);
glEnd();
}

void divide_triangle(point a, point b, point c, int m)
{

/* triangle subdivision using vertex numbers
righthand rule applied to create outward pointing faces */

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)); /* draw triangle at end of recursion */
}

void tetrahedron( int m)
{

/* Apply triangle subdivision to faces of tetrahedron */

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);
}

void display(void)
{


glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
tetrahedron(n);
glFlush();
}


void myReshape(int w, int h)
{
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
if (w <= h)
glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w,
2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0);
else
glOrtho(-2.0 * (GLfloat) w / (GLfloat) h,
2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0);
glMatrixMode(GL_MODELVIEW);
glutPostRedisplay();
}


void
main(int argc, char **argv)
{
n=atoi(argv[1]); // caution: either supply an integer on the command line
// or set n here
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH);

glutInitWindowSize(500, 500);
glutCreateWindow("3D Gasket");
glutReshapeFunc(myReshape);
glutDisplayFunc(display);
glEnable(GL_DEPTH_TEST);
glClearColor (1.0, 1.0, 1.0, 1.0);
glutMainLoop();
}

We started Chapter (3).

We went  3.1, 3.2, 3.3, and 3.4.  We went trhough section 3.4.1 with an example of a display list shown below:

/*
 * Copyright (c) 1993-1997, Silicon Graphics, Inc.
 * ALL RIGHTS RESERVED
 * Permission to use, copy, modify, and distribute this software for
 * any purpose and without fee is hereby granted, provided that the above
 * copyright notice appear in all copies and that both the copyright notice
 * and this permission notice appear in supporting documentation, and that
 * the name of Silicon Graphics, Inc. not be used in advertising
 * or publicity pertaining to distribution of the software without specific,
 * written prior permission.
 *
 * OpenGL(R) is a registered trademark of Silicon Graphics, Inc.
 */

/*
 *  list.cpp - The original program came from the SGI site, it was modified
 *  by Rahman Tashakkori at ASU in Spring 2004.
 *  This program demonstrates how to make and execute a
 *  display list.  Note that attributes, such as current
 *  color and matrix, are changed.
 */
#include <GL/glut.h>
#include <stdlib.h>

GLuint listName, listName2;

static void init (void)
{
   listName = glGenLists (1);
   glNewList (listName, GL_COMPILE);
      glColor3f (1.0, 0.0, 0.0);  /*  current color red  */
      glBegin (GL_TRIANGLES);
      glVertex2f (0.0, 0.0);
      glVertex2f (1.0, 0.0);
      glVertex2f (0.0, 1.0);
      glEnd ();
      glTranslatef (1.5, 0.0, 0.0); /*  move position  */
   glEndList ();
   glShadeModel (GL_FLAT);

   listName2 = glGenLists (2);
   glNewList (listName2, GL_COMPILE);
      glColor3f (0.0, 1.0, 0.0);  /*  current color red  */
      glBegin (GL_QUADS);
      glVertex2f (0.0, 0.0);
      glVertex2f (1.0, 0.0);
      glVertex2f (1.0, 1.0);
      glVertex2f (0.0, 1.0);
      glEnd ();
      glTranslatef (1.5, 0.0, 0.0); /*  move position  */
   glEndList ();
   glShadeModel (GL_FLAT);
}

static void drawLine (void)
{
   glBegin (GL_LINES);
   glVertex2f (0.0, 0.5);
   glVertex2f (21.0, 0.5);
   glEnd ();
}

void display(void)
{
   GLuint i;

   glClear (GL_COLOR_BUFFER_BIT);
   glColor3f (0.0, 1.0, 0.0);  /*  current color green  */
   for (i = 0; i < 10; i++)    /*  draw 10 triangles    */
      glCallList (listName);
   for (i = 0; i < 4; i++)    /*  draw 10 triangles    */
      glCallList (listName2);

   drawLine ();  /*  is this line green?  NO!  */
                 /*  where is the line drawn?  */
   glFlush ();
}

void reshape(int w, int h)
{
   glViewport(0, 0, w, h);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   if (w <= h)
      gluOrtho2D (0.0, 2.0, -0.5 * (GLfloat) h/(GLfloat) w,
         1.5 * (GLfloat) h/(GLfloat) w);
   else
      gluOrtho2D (0.0, 2.0 * (GLfloat) w/(GLfloat) h, -0.5, 1.5);
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
}

void keyboard(unsigned char key, int x, int y)
{
   switch (key) {
      case 27:
         exit(0);
         break;
   }
}

/*  Main Loop
 *  Open window with initial window size, title bar,
 *  RGBA display mode, and handle input events.
 */
int main(int argc, char** argv)
{
   glutInit(&argc, argv);
   glutInitDisplayMode (GLUT_SINGLE | GLUT_RGB);
   glutInitWindowSize(650, 50);

   glutCreateWindow(argv[0]);
   init ();
   glutReshapeFunc (reshape);
   glutDisplayFunc (display);
   glutKeyboardFunc (keyboard);
   glutMainLoop();
   return 0;
}


Mouse
Program

Next we wrote a primative drawing program.

#include <GL/glut.h>
int anchorx, anchory;
void myinit(void)
{

/* attributes */
glClearColor(1.0, 1.0, 1.0, 1.0); /* white background */
glColor3f(1.0, 0.0, 0.0); /* draw in black */
/* set up viewing */
/* 50 x 50 window with origin lower left */
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, 500.0, 0.0, 500.0);
glMatrixMode(GL_MODELVIEW);
}

void display( void )
{
glClear(GL_COLOR_BUFFER_BIT); /*clear the window */
// add "connect the dots" code here
glFlush(); /* clear buffers */
}
void mouse(int button, int state,int x, int y)
{
anchorx=x;
anchory=500-y;
}
void mousemove(int x,int y)
{
glBegin(GL_LINES);
glVertex2f(anchorx,anchory);
glVertex2f(x,500-y);
glEnd();
anchorx=x;
anchory=500-y;
}
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 */
glutMouseFunc(mouse);
glutMotionFunc(mousemove);
myinit(); /* set attributes */
glutMainLoop(); /* enter event loop */
}

This draws curves in red, but does not refresh them when the screen is "damaged" and redisplayed. (We'll need to save our points and connect them in the display callback for that to work.) We implement a mouse callback to save the position of the mouse when a button is pressed, and a mouse motion callback to connect dots as the mouse is moved while a button is pressed. Here are some "fine points" to worry about: the callbacks return the mouse position in screen coordinates, not world coordinates. The screen origin in Windows is at the upper left, while OpenGL puts the origin at the lower left. Also, screen coordinates are integers while our world coordinates are GLfloats. We can address the second problem by making the range of values in world coordinates agree with the window size:

	glutInitWindowSize(500,500); /* 500 x 500 pixel window */
gluOrtho2D(0.0, 500.0, 0.0, 500.0);

We can fix the second problem by subtracting y values returned from the operating system from the height of the window: y = 500 - y.

For your next homework assignment, you'll be fixing the redisplay problem and adding menus for changing the width and colors of the curves.

Please read through section 3.9.2 in our text.