OpenGL  is a core
component of MIVI and a basic awareness and knowledge of its functions
and principals is crucial in the reading of this report. This section
will furnish the reader with the fundamentals of the technology.
Other more advanced issues are dealt with as and when they appear
throughout the report. For a more detailed and less specialised
introduction to OpenGL and computer graphics, the author refers
the reader to Angel .
OpenGL is a cross-platform
implementation of graphics libraries for the creation and manipulation
of 3D and 4D objects. Following its inception, in 1992, the specification
took the industry and academic body by storm and quickly established
itself as the most popular standard for 3D graphics design and programming.
It is its library form that allows
for its incredible compatibility - the libraries are distributed
as C source code, and with minimal modifications can be compiled
on any platform with a C compiler, thus covering most operating
systems. Once compiled to the native format, the OS's infrastructure
allows the functions and sub-routines of the library to be called
from any programming language or application that supports external
The low-level functions and workings
of the libraries are discussed in detail in Angel , but for our
purposes, a rudimentary knowledge of the higher-level functions,
employed in the host programming language, will be sufficient for
OpenGL has 3 main libraries – the
GL (Core Library), GLU (Utility Library) and GLUT (Utility Toolkit
Library). The first defines methods for creation of the simplest
(atomic) 3D objects, such as individual vertices, lines and polygons,
and provides functions for handling global parameters for lighting
and viewport configuration, as well as functions to adjust material
properties and map simple bit-mapped images (textures) to objects.
Functions involving communication with the graphics hardware are
generally found in this library. The second library is simply a
collection of enumerated values, which map property names to internal
constants, allowing for easier recognition and recollection by graphics
developers. Finally, the third contains macros for creating common
primitives (cubes, sphere, pyramids, etc.) and handles communication
with the OS to allow for timing, user interaction, OS GUI (Graphical
User Interface) settings, etc.
To beginners, the relative nature
of OpenGL's matrix geometry can be counter-intuitive, at first.
OpenGL uses matrices to represent a 3D world. So, instead of telling
OpenGL to create a cube at (5,5,5) and one at (8,5,5), we must tell
it to move 5 right, 5 up and 5 in, from the origin, and create the
first cube. Then, we only need to move a further 3 right and create
the second. If we now want to create another object in relation
to the origin, we must remember how to get back there. So, scene
creation, in OpenGL, works on a stack-based principle.
fig B.1 - using the
you will, a cursor. When you draw a line from a to b,
the cursor moves from a to b as well. Imagine if you
were to draw a line 4 times sequentially, rotating 90° each time
- the resulting shape would be a square (figure B.1 (a)),
and in the process the cursor would have gone from a to b
to c to d to a.
by pushing the cursor20
onto the stack before the line is drawn, a snapshot of its location
is stored for retrieval (popping) later. Now, if, after the line
is drawn, we pop the stack, we return the cursor to the state we
were in beforehand. Then, if we rotate 90°, and repeat as before,
the result is a 'plus' shape (figure B.1 (b))
and the cursors itinerary is now a to b, then a to
c, then a to d, then a to e.
We can, of course, push to the stack
more than once without popping it in between - whatever data it
receives, it ‘stacks’ on top of what already exists (herein lies
its etymology). This allows us to abstract from complicated models
and consider them as the sum of their components, considering each
component independently from the parent body, possibly even as a
sum of its own components. For example, a hand is subordinate to
a body, and a finger to a hand. If we push the cursor before the
creation of the left arm, then execute the code for its creation,
we can pop the stack, move the cursor to the left and use the same
code for the other arm. Furthermore, during the drawing of each
arm, we can take the same approach for each finger - the result
is that fingers' positions are effected by the arm's rotation, which
is how we want it. Since every finger that is pushed to the stack
gets popped, when the fingers are drawn, the stack is left as it
was before, with the arm's cursor next in line at the top of the
stack. The use of this technique to model realistic physical interaction
(such as anatomy) is called Inverse Kinematics , and its use
its illustrated in figure B.2.
fig. B.2 - the use of
It is not hard to see that this approach
permits for the inclusion of the best of both worlds; relative and
coordinate geometry. Indeed, an interface could easily be written
to allow the user to work in coordinate geometry alone. By simply
pushing and popping, before and after (respectively) the creation
of every object, the cursor is forced to act relative to the origin.
Most graphics projects, however, are a compromise between the two
- the designing of 3D bodies with independently moveable parts,
for example, is made significantly simpler with a stack.
Unsurprisingly, the keywords and grammar
of the OpenGL programming language do not represent the final format
of graphics information, as it is presented to the hardware. OpenGL
interprets such high-level terminology into a more efficient
form before execution. This is the case with other interpreting
programming languages, like JAVA and PERL. Whereas this approach
has the advantage of visibility, and can result in easier porting
to other host systems, it is known to be significantly less efficient
than the alternative; compiled programming languages – where
the information must be converted into the final, executable code,
before runtime, and is distributed in this format. In this latter
case, no translation is necessary while the program is running.
OpenGL seizes the best of both the
interpretation and compilation worlds, by allowing an OpenGL program
to submit 3D object code for compilation at the outset of program
runtime. This code is then translated to the final, executable format
and stored in memory, where the OpenGL program can beckon its direct
execution. Compilation is a one-way ‘lossy’ process, so the 3D object
defined by the code cannot be reverse engineered and modified. Hence,
it is only of viable use in static objects, like our piano body,
whose attributes and form do not change.
of computers is the story of automation to make life faster or simpler
– and OpenGL's own history follows suit. There are sequences of
operations in OpenGL that must be performed in nearly every application
(eg. initialising hardware, initialising windows, etc.) and there
are certain sequences which are common
to many different software applications
– such as drawing standard primitives, like cubes and spheres, etc.
Just the initialisation can take over
100 lines of generic code. By calling a select number of GLUT functions,
these lines are executed for you. Furthermore, by supplying a number
of parameters to the functions, a certain degree of flexibility
and control over the environment’s creation is maintained.
The GLUT library also provides access
to event handlers, so that input, from devices attached to the system
– such as the keyboard – can be processed. As such, a lot of the
GLUT library is reliant on the program’s host Operating System’s
Hardware Abstraction Layer (HAL), and the code is thus littered
with compiler directives, specifying code segments appropriate to
each host OS.
The GLUT library’s finer intricacies,
including discussions of advantages and disadvantages, are covered
in the relevant sections, elsewhere in the report.