Back to July Calendar Previous Entry Next Entry→

July, 15, 2005

 

So I’ll maybe show my pinko background when I make personal and/or political commentary, that way the disinterested reader can skip it or verse vice, huh?

 

Aye, the ides of July, and Karl Rove/Dick Cheney are discovering that the Nixonian treason (going to war on false pretext) has some of the same ornaments of collateral crime (Watergate break-in & revealing state secrets for political gain & subsequent lying/cover-up.)  Sounds like as good a time as any to investigate

 

Saving the State

 

Geometric primitives (points, lines, polygons) are rendered according to the OpenGL state.  Since recalculating perspectives, colors, etc., which takes valuable cpu resources, often it’s more efficient to store a state and recall it for later use.  Depending on whether the state is in GL_MODELVIEW or GL_PROJECTION mode, OpenGL uses matrix stacks to store model-view and projection matrices.  You push/pop on/off the stack using glPushMatrix() and glPopMatrix.

 

There is a parallel here with the cascading style sheets of yesterday’s log.  The idea is to remember a condition/state so that you don’t have to specify it in detail each time you want to revisit it.

 

Angel points out two major uses of matrix stacks.

 

  • Something hierarchal models and tree data structure to traverse these models that we’ll study in more detail later.  This is the model-view type.
  • Say you want to temporarily zoom in our out or around some view and then you want to quickly get back to your original position.  This is an obvious application of the projection type.

 

The following code snippet outlines how projection mode toggling generally works:

 

glMatrixMode(GL_PROJECTIONMODE);

// set projection matrix

// and draw scence

glPushMatrix();  // save the projection state

// change the projection matrix to zoom/rotate POV

// and draw new scene

glPopMatrix();  // recall the previous state

 

Note that if you do n pushes, then you need n pops to get back to where you started.

 

There are 20 groupings of attributes in OpenGL, such as GL_POLYGON_BIT and GL_LINE_BIT, which you can be push/pop on/off the attribute stack with glPushAttrib() and glPopAttrib().


 

This brings me to the end of chapter 2 in Edward Angel’s OpenGL Primer.  Some interest problems at the end promotes the following investigations.

 

Why is the circle not a primitive geometric object in OpenGL?  Probably because the basic structure of computer displays is built on rectangular arrays of pixels.  The first exercise suggests trying several ways to draw a circle:

  • use simple trigonometry to locate points on a circle or
  • subdivide an equilateral triangle into “finer and finer polygons.”

In the code immediately below, I’ve used simple trig to walk 25 points counterclockwise around the unit circle and drawing the line segments between them.  The result, together with the color interpolation from red to green that I tossed in as an extra, is shown at right.  One possible drawback of this code is that each point is plotted twice: once as a starting point and again as endpoint. 

          Note also that I’m omitting the init() and  main() functions, since they’re the same as before.

 

/* circle */

#include <GL/glut.h>   // This includes gl.h and glu.h

#include <cmath>

#define TwoPI 6.283185307

 

void circle(GLfloat *center, GLfloat radius, GLfloat smoothness) {

      GLfloat v1[2], v2[2];

      double i;

      v1[0] = center[0]+radius;

      v1[1] = center[1];

      for(i = 0; i <= smoothness; ++i) {

         v2[0] = center[0]+radius*cos(i*TwoPI/smoothness);

         v2[1] = center[1]+radius*sin(i*TwoPI/smoothness);

         glBegin(GL_LINES);

            glColor3f(1.0-i/smoothness,i/smoothness,0.0);

            glVertex2fv(v1);

            glVertex2fv(v2);

         glEnd();

         v1[0] = v2[0];

         v1[1] = v2[1];

      } // end for

}

 

GLfloat center[2] = {0.0,0.0};

GLfloat radius = 1.0;  //unit circle

void display(void) {

      glClear(GL_COLOR_BUFFER_BIT);

      glPolygonMode(GL_FRONT, GL_LINE);

      GLfloat smoothness = 25.0;

      circle(center, radius, smoothness);

      glFlush();

}

 

As for the second suggestion: cutting corners off an equilateral triangle until you have a smooth enough circlish thing, or whatever.  After several attempts at this I confess to being uncertain how to proceed.  Maybe come back to this later.

 

Another idea occurs to me: take your 25 (or whatever smoothness resolution is required) points equally distributed around the unit circle as a kind of look-up table database and then for a circle of different center and radius, simply scale (multiply all coordinates by the radius) and shift.(add a fixed value to the x-ccordinates for a horizontal shift and likewise for the y-coordinate.

 

Angel’s second exercise is to “rewrite the triangle subdivision program for tessellations so that at each subdivision step, the middle triangle is omitted.”  The first several iterations of my first attempt at this (with a little extra color thrown in) are shown below, followed by the code that produced them. 

 

The code is essentially the tessellation code simplified to draw each of the four sub-triangles in a different color (red, green, blue and white in the middle.)

 

 

 

void triangle(GLfloat *a, GLfloat *b, GLfloat *c) {

      glBegin(GL_POLYGON);

        glVertex2fv(a);

        glVertex2fv(b);

        glVertex2fv(c);

    glEnd();

}

 

void sierpinsk(GLfloat *a, GLfloat *b, GLfloat *c, int m) {

      //Triangle subdivision using vertices

      GLfloat v[3][2];  //starting triangle for all furtherly divided:

      if(m>0) {

            for(int j=0;j<2;j++) {

                  v[0][j] = (a[j] + b[j])/2;

                  v[1][j] = (b[j] + c[j])/2;

                  v[2][j] = (a[j] + c[j])/2;

            }

            glColor3f(1.0,0.0,0.0);

            sierpinsk(a, v[0], v[2], m-1 );                

            glColor3f(0.0,1.0,0.0);

            sierpinsk(v[0], b, v[1], m-1 );

            glColor3f(0.0,0.0,1.0);

            sierpinsk(v[2], v[1], c, m-1 );

            glColor3f(1.0,1.0,1.0);

            sierpinsk(v[0], v[1], v[2], m-1 );

      }

      else 

            triangle(a,b,c);

}

 

GLfloat v[3][2] = {{0,0.866},{-1,-1},{1,-1}};

void display(void) {

      glClear(GL_COLOR_BUFFER_BIT);

      glPolygonMode(GL_FRONT, GL_FILL);

      int n = 6;  //  The nesting number of triangles

      glColor3f(1.0, 0.0, 0.0);

      sierpinsk(v[0], v[1], v[2], n);    

      glFlush();

}