introducing OpenGL
appendix B
 

OpenGL [42] 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 [3].

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.

compatibility

 

   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 dependencies.

   The low-level functions and workings of the libraries are discussed in detail in Angel [3], but for our purposes, a rudimentary knowledge of the higher-level functions, employed in the host programming language, will be sufficient for the reader.

structure

 

   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.

matrices and
stack-based
geometry

 

   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
OpenGL stack

 

(a) without stack

(b) with stack

   

 

  Imagine, if 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.

   However, 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.

hierarchical
modelling 

 

   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 [3], and its use its illustrated in figure B.2.

fig. B.2 - the use of

Inverse Kinematics

 

 

 

   

   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.

display lists

 

   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.

 the GLUT
utility library

 

   The history 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.

 
 


All content, including code and media, (c) Copyright 2002 Chris Nash.