All the source code for the examples on this page (minus some portions left as exercises) can be obtained from SampleProgramSet2_SourceCode.tar.gz during semesters that EECS 672 is being taught. It will uncompress into the indicated directory structure. Notice that we have added two new "utility" directories: cryphutil and fontutil. The former will be introduced in our first example below; the latter will be introduced in the second.
Nothing has changed in either the glslutil or the mvcutil directories.
![]() |
Now that you have explored color space issues using the Color Spaces tool, this example shows you how to build your own color wheel. We model a color wheel as a single circle filled in with colors of all hues. We create a piecewise linear (PWL) approximation of the circle, determining at runtime how many points to generate around the wheel. Doing so requires slightly more general calls to glBufferData. Since we want our color wheel to be solid, we use the points of our PWL approximation to define a triangle fan. The first vertex is at the center of the circle, and the rest are around the perimeter.
We will study points and vectors in affine and projective spaces more formally later, but we introduce here some simple tools for performing arithmetic that require only the most basic understanding of points and vectors. Creating models as the previous examples have illustrated (i.e., simply populating arrays of coordinates to be passed to glBufferData) is practical for only the simplest of scenes. It is often much more efficient to algorithmically compute coordinates. The cryph tools introduced here can simplify such geometric computations and make it easier to create many types of models.
Before studying the use of the cryph tools in this example, study the examples on this page for a quick idea behind the toolkit.
This more complete documentation for the cryph toolkit is also available.
Notice how the main program in colorwheel.c++ creates the center
point, orientation vectors, and radius
that get passed to the ModelView
constructor and used by
ModelView::createColoredCircle. The first for
loop in ModelView::createColoredCircle creates each point in turn
around the perimeter
of the circle, placing the coordinates into a
vec3 array similar to what
you saw in pwlApproxOfParabola
and sendToGPU_AsVec3Array. The only difference is that here we add each point in turn to
the vec3 array, rather than first buffering all points into an AffPoint array.
The benefits may seem marginal here, but you will get a much better appreciation for how they can simplify geometry construction when you see in the next example how easy it is to change the orientation of our "bowtie".
To get the desired coloring, we could pass relevant information to the fragment shader, letting it determine the colors. Here we illustrate an alternative technique that exploits the way that per-vertex attributes work by associating explicit colors with the various vertices of our PWL approximation. To start, we associate pure white with the center of the circle (the first point of our "triangle fan" PWL approximation). The colors associated with the vertices around the perimeter of the circle are assigned a color based on an HSV value in which the hue is computed directly from the angle around the circle, and the saturation and value are each fixed at 1.0. The implementation of the HSV to RGB algorithm in this example was derived from the one presented on www.easyrgb.com.
Note the changes to the calls to glBufferData and the required dynamic allocation and deletion of the client-side per-vertex attribute arrays.
![]() |
We can oftentimes use simple tricks to create interesting shapes. In addition to using theta to compute a hue, we also use it here to continuously modify the radius of the circle as: r = radius * (cos2(theta) + a)/(1 + a)". The arbitrary small positive constant, a, keeps the radius from ever reaching zero, and then dividing by (1+a) ensures that the original diameter does not change.
This simple trick results in a "bowtie" sort of shape. This example reinforces the value of the cryph tools; look at how similar this version of createColoredCircle is to that in the previous example. Notice also how easy it is to adjust the angle at which our tilted bowtie appears.
Text can be added to our scenes using an approach based on a modified version of some utilities written by George Sealy. (At one time, his description and code could be accessed here, however this link seems to be broken now.)
My modified version of Sealy's utilities are in the fontutil directory. As you can see in the ModelView.c++ file here, the approach is fairly simple, although it does require some additional coordination between the client and the GLSL shaders. Specifically:
Pressing the 'a' key turns on (or off) an animation in which the text rotates around the bowtie. Animations such as this require some sort of time interface. In GLFW, you can query the current "time" in seconds. By default, this will be the number of seconds since GLFW was initialized. The time is returned as a double precision value in seconds. The accuracy is system-dependent, but it is typically sufficiently accurate for basic animation.
To use the GLFW
approach to animation, you must instruct the GLFWController::run method not to wait for
events, but instead
to immediately invoke your display callback even if there are no pending events.
(See calls to setRunWaitsForAnEvent in ModelView
and the implementation of
GLFWController::run.)
During display callbacks (specifically during calls to ModelView::render),
you can then check the current time to see whether you should make some change to the scene for
your animation. In this example, that logic is implemented in ModelView::maybeRotateLabel
which is called from ModelView::render.
Full documentation on the GLFW timer interface can be found in the GLFW documentation on the GLFW web site.