Deconstructing the OpenGL Pipeline in illiTorpot
28oct12
1.1. Introduction
This lesson teases the OpenGL pipeline structure from the code for
illiTorpot, which itself is a development of the standard illiSkel.
The latter has been the standard template code for almost all C/OpenGL
projects for illiMath in the decade 1994-2006. No complete illiSkel
exists at this time for OpenGL/Python, although it should be straightforward
to develop the torus.py with the missing functionality.
1.11.1. Prerequisites
The reader should be able to read C-code at the beginner's level, and should
have access to a way of recompiling skel.cpp and torpot.cpp on their computer.
On a PC running Windows, the torpot.cpp adapted for Windows compiles with
the native Windows compiler
mvc98 (provided in the illiMath Winaid package)
using the
win.mf makefile filter. On a mac, the
mac.mf
will recompile the unix adapted torpot.cpp. The mac.mf filter has been
adapted in the past to a variety of Linux distros as
lnx.mf ,
but these are very specific to the particular way your flavor of Linux handles
the graphics system on your PC.
1.21.2. Torpot versus Skel
The illiSkel, shortened to skel.c, skel.cpp, skel.py etc and compiled to
just
skel in Unix, and to
skel.exe in Windows, has a
simple pipeline, whose deconstruction we leave to the reader as an
exercise in understanding the present lesson.
1.31.3. Versions
On Windows PCs, use repo:
class198f12/resources/tecraD/geodesy/skel.c
with mvc98 or other Windows compilers (modify win.mf to suit).
The commandline entry for mvc98, reads:
nmake -f win.mf skel.exe
On a Mac (at least through OSX10.6) use repo:
class198f12/resources/illimac/skel/skel.c
and
class198f12/resources/illimac/toport/toport.c .
The commandline entry on a prepared mac reads:
make -f mac.mf torpot .
2.2. Analysis of the Code
2.12.1. Where do we start the deconstruction?
The function
drawcons() must be the display master for two
reasons:
- The command swapbuffers() is called at its very end. This
signals OpenGL to switch display buffers at the next opportunity.
- The overall master function main() identifies drawcons()
as the display callback .
So we start we always start with the
main() function.
If you understood the terms in this introduction, skip the following explanantion of them. OpenGL specifies that your graphics card is
double buffered. That means, OpenGL draws data (pixel color, transparency etc) into one display buffer, while the other display buffer is repeatedly copied to your video system.When this is complete (anywhere from 100 milliseconds or less, to hours for Hollywood quality computer animations), OpenGL redirects the computer's video system to display the new display buffer. The old is dealt with by your program. By default, it is erased and everything is redrawn from scratch. You can alter that for special effects or learning experiments when you know more OpenGL.
A
callback function in an OpenGL program is a modification of a
default function inside the so-called
display loop . Once the display loop
is started by the OpenGL command
glutMainLoop() , the only way you can
interact with it in real time is through the callbacks. For C-adepts, callbacks
work with function pointers. In object oriented programming (OOP), overloading
classes serves a similar purpose.
2.22.2. Notational convention
Recall that we use a simple meta syntax.
refers to an OpenGL
matrix (or product of matrices), qualified by the subscript "foo".
Similarly
refers to phrase in the pipeline to be elaborated
later.
Square brackets designate a push/pop pair for the current
matrix on the stack. Braces are comments not otherwise part of the
meta syntax. Recall that the
glPushMatrix() duplicates the
top entry in the stack so that it can be modified and applied to
a drawing without altering the previous top matrix. The
glPopMatrix()
removes the top matrix on the stack and restores the prior one to the top.
The brackets must be
properly nested , i.e.
while there can be brackets within brackets, they must not overlap.
This way, the brackets can also be interpreted as branches in a tree graph.
Finally,
is a function that actually draws vertices of an
object on the screen.
It represents a leaf in the tree graph. A pipeline graph is
well formed
if the push-pop brackets are properly nested. It is
complete , if
it begins with an
X
3.3. Deconstruction of drawcons()
For a first pass, assume the binocular flag,
binoc == 0 i.e.
"is false", so that the second eye's viewport is not drawn. The double ==
is part of C-syntax and means "really equal", not just setting the LHS to the
RHS, as in
binoc=0 . OpenGL has many stacks. We are concerned only with the
Projection
stack and the
Modelview stack . On the projection stack we load the
identity
and multiply by the OpenGL matrix
corresponding to
a frustum of a rectangular viewing window
(use of "window" predates Microsoft and belongs to Silicon Graphics!).
The exact meaning of the parameters are discussed elsewhere.
Immediately afterwards we draw the stars with
drawstar() to get
the initial phrase in the pipeline:
On the Modelview stack, we load the identity to avoid using junk already
theres, then multiply by one of four maintained matrices by flag
whichmat :
|
depending on your choice. In the original illiSkel, there are no choices. Only
is maintained. In the customary C/C++ OpenGL codes, this matrix is hidden
from the applications programmer. We draw all that is to be drawn. So
we can see what we're doing, there is a final drawing of the
messages
on the heads-up display. The heads-up needs its own viewport and projection matrix,
see below. We have the entire pipeline without the details:
We next unpack this summary of the OpenGL geometry pipeline for this RTICA.
3.13.1. Deconstruction of Component Functions
What we do next should remind you of unraveling symbols in your calculus course,
as in integration by substitution, or the chain rule.
3.1.13.1.1. The Stars
The stars in the basic version of this code are just random dots placed very far
away. They do not move. When the observer's head is turned, then the stars are
turned by a rotation matrix. Note that the observer's translation (forward,
sideways, up/down motion) has no effect on the stars.
3.1.23.1.2. All the Drawings
|
Since we want to place the torus and the teapot independently into
the same coordinate system, we use a pair of push/pops. If, for example,
you want a second torus to link the first and stay linked, the first
bracket would become
, where the
second torus is rotated by 90 degrees and translated to one side, before
it is drawn again. Try it!
3.1.33.1.3. Martin Newell's Utah Teapot
It is worth your while to google the Wikipedia article on the teapot. It
comes with the GLUT distribution as a pre-computed object for your
convenient. By all means, make the second object in illiTorpot something
less of a cliche, as an exercise.
Also note, the push/pop in this instance is unnecessary, because no placement
of the teapot is made. But you can certainly place the teapot somewhere else.
So the brackets are already in the code. Just construct your own place matrix.
3.1.43.1.4. The Torus
This is the placeholder for the primary object you want to draw. This part of
the code is discussed elsewhere.
3.23.2. The Messages
|
This drawing function calls for a new viewport. Since this is an unusual and
thing, we don't invent special symbols. And it isn't part of the geometry pipeline, though it effects what you see on the screen. All are by now familiar with
what is just called a
window . You open windows with a mouse, resize them,
move them around, closed them. There is even a Microsoft product called ``Windows", although Microsoft didn't invent windowing. Neither did Apple. It was
invented at Xerox-Parc, and used a 3-button mouse. Apple, initially decided that
business men (for whom the MacIntosh was intended) are too clumsy to handle a
three button mouse, and provided only a 1-button mouse. Microsoft offered a
2-button mouse to one-up Apple. But for the past decade, everybody saw the wisdom of Xerox and uses pretty much the same windowing system and 3 button mouse.
The OpenGL viewport is almost always synonymous with a window. But Silicon Graphics (which invented OpenGL) knew better. What if you want to display a mosaic
of many views inside the same window e.g. a stereopair, or an overlay on the entire screen, as with our
messages() That's when you specifiy new viewports.
3.33.3. Full Elaboration
We now put it all together, the original
becomes
|
4.4. Navigation with Chaptrack
So far we only know the structure of the pipeline, not how to the user input with
mouse and keypad is effected on the various placement matrices in the pipeline.
Here we discuss only the most difficult one, the native navigator for illiStuff.
In the illiSkel chaptrack is called in the
idle function . This callback
is, on a multiprocessor computer, done by a separate CPU so as not to impede
the graphics engines with computation. There, the input devices are polled
asynchronously from the graphics cards, and the processed information (
the changed entries in the various placement matrices) is made available to
the pipeline when it is requires. On a single processor machine, the idle()
function is done between successive display calls. Thus, heavy duty calculations
can slow down the animation, though not in this case.
4.14.1. Chaptrack
This subroutine borrows the graphics pipeline to do some matrix arithmetic. This
is generally a bad idea, but here it is meant to teach you the pipeline features.
If you do not want to write your own matrix arithmetic functions you
can also use the third stack ordinarily used for textures. Because we push the
Modelview stack, nothing else is affected by this occasional loan of the stack here.
Note that the input for the function
chaptrack(MAT, PAW, XX, YY, SHFT) , where MAT=
is an arbitrary matrix.
We can expand
, but
the brackets do not mean push/pop. They remind you that the components of
an OpenGL matrix is a Euclidean rotation
followed by a translation by
.
So
is a 3x3 orthogonal matrix and
a 3-vector. Reading by columns,
remember an OpenGL matrix a flat array of 16 floats,
.
More later, or elsewhere, on OpenGL matrices.
The remaining three inputs contain the mouse button situation, the x-y coordinates
of the mouse when polled, and the state of the shift-key respectively.
Chaptrack continues by computing
if
chapmat==3 .
It next calculates a small displacement
dx, dy of the mouse from the
center of the viewing window, but with "dead zone". Then it modifies various
placement matrices from the left by constructing a matrix on a clean stack by
multiplying the identity matrix on the right. We use short lines to leave room
for comments. But this is one long push/pop.
[
if3{
}
ifturn{
}
ifshift{faster}
iffly{[
]}
ifarrows{other translations}
ifturn{
}
]
and finishes up by rotating the sun (light source) in the opposite direction to
keep the bright spot from the same direction on a turning object.
4.24.2. Explanation
The best way to understand this lesson is to choose various of the
the (greater than
) cases and write down what
Geometry Pipeline matrix product (as in the Full Elaboration above)
actually looks like in each case you considered.
Examples follow.
I would appreciate it if you looked for and reported typos, especially
misinterpretations of the code into symbols.