Changes between Version 1 and Version 2 of opengl-intro

Jul 1, 2013, 3:03:17 PM (7 years ago)



  • opengl-intro

    v1 v2  
    3838graphics performance. Programming knowledge of OpenGL 1.x is therefore not
    3939recommended for nowadays and can simply be forgotten and treated as legacy.
     41[[Image(OpenGL-pipeline.svg, right)]]
     42Modern OpenGL changed previously fixed rendering pipeline to fully
     43programmable graphics pipeline as shown in Fig.1
     44Processors that transform input vertex data to the window context at the
     45end are called ''shaders''. The Vertex shader and the Fragment shader
     46are most important in the rendering pipeline. To use rendering pipeline as
     47shown in Fig.1 one has to provide program for them
     48as there is no default because they are essential part of every OpenGL
     49program. Programming shaders is done in GLSL (OpenGL Shading Language) that
     50is similar to C language with some predefined variables and reserved
     51keywords that help describing communication between OS and GPU. Programs
     52(for shaders) written in GLSL are compiled on-the-fly, assembled and
     53transferred to GPU for execution.
     55OpenGL is designed as a hardware-independent interface between the program
     56code and graphics accelerator. Hardware independence of OpenGL means also
     57that in the language specification there is no support for control of
     58window system events that occur with interactive programming. For such
     59interactive control for each operating system were designed interfaces that
     60connect the machine with the OpenGL system. Due to the specifics of
     61different window systems (Windows, XWindow, MacOS, iOS, Android) it is
     62required that for each system tailored techniques are used to call OpenGL
     63commands in hardware. Portability is thus limited by graphical user
     64interface (GUI) that handles OpenGL context (window). In order to still be
     65able to write ''portable programs'' with otherwise limited functionality
     66of the user interface, GLUT library (OpenGL Utility Toolkit) was created.
     67It compensates all the differences between operating systems and introduces
     68a unified methods of manipulating ''events''. With the GLUT library it
     69is possible to write portable programs that are easy to write and have
     70sufficient capacity for simple user interfaces.
     72== Legacy OpenGL coding ==
     73Basics of the OpenGL language are given in the (core) GL library. More
     74complex primitives can be build by the GLU library (GL Utility) which
     75contain the routines that use GL routines only. GLU routines contain
     76multiple GL commands that are generally applicable and have therefore been
     77implemented to ease OpenGL programming.
     79To get quickly introduced into OpenGL it is better to start with legacy
     80(short and simple) program that will be later replaced with modern OpenGL
     81after discussion that caused replacement with OpenGL 3.x. Before we can
     82dive in OpenGL we need to revise windowing systems and how they interact
     83with users.
     85== Events ==
     86All window interfaces (GUI) are designed to operate on the principle of
     87''events''. Events are signals from the Window system to our program.
     88Our program is fully responsible for the content of the window. Windowing
     89system only assigns area (window). The contents of the window area must
     90then be fully controlled. In addition to the window assignment the
     91windowing system to sends messages (events) to our program. The most common
     92messages are:
     93 display:: The command asks for presentation of window contents. There
     94  are several possible occasions when this happens. For example, when
     95  another window reveals part of our window or when window is moved on the
     96  screen. Another example is when window is re-displayed after icon is
     97  being pressed at the taskbar. Interception of such events is mandatory,
     98  because every program must ensure that the contents of the window is
     99  restored window, when such event occurs.
     100 reshape:: Command to our program that occurs when the size and/or
     101  shape of the window changes. In this case the content of the window must
     102  be provided for a new window size. Event occurs, inter alia, when the
     103  mouse resizes the window. Immediately after reshape, display event is
     104  sent.
     105 keyboard:: Commands coming from the keyboard.
     106 mouse:: Describes the mouse buttons at their change when user pressed
     107  or released one of the buttons.
     108 motion:: This command defines the motion tracking of the moving mouse
     109  with pressed button.
     110 timer:: Program requests message after a certain time in order to
     111  change the contents of the window. The function is suitable for timed
     112  simulation (animation).
     113In addition to these events there exist some other too. In general it is
     114not necessary that all events to a window are implemented in our program.
     115It is our responsibility to decide which
     116events will be used in the application. Usually program must notify
     117windowing system which events will took over and for that window will
     118receive events.
     120== GLUT ==
     121For an abstraction of events (commands from the windowing system) we will
     122use GLUT library (OpenGL Utility Toolkit). Many other GUI libraries are
     123available (native and portable). GLUT falls into the category of simple
     124operating/windowing system independent GUIs for OpenGL. An example of a
     125minimal program that draws a single line is shown in Listing 1 (first.c).
     126\lstinputlisting[caption=Drawing a line with OpenGL and GLUT.,
     127label=first.c ]{first.c} Program in C language consists of two parts: the
     128subroutine display and the main program. Program runs from the start in
     129{{{main()}}} and at the end falls into endless loop
     130{{{glutMainLoop}}} that calls registered subroutines when event
     131occurs. Before falling into {{{glutMainLoop}}} we need to prepare drawing
     135#include <GL/glut.h>
     137void display()
     139  glClear(GL_COLOR_BUFFER_BIT);
     140  glColor3f(1.0, 0.4, 1.0);
     141  glBegin(GL_LINES);
     142    glVertex2f(0.1, 0.1);
     143    glVertex3f(0.8, 0.8, 1.0);
     144  glEnd();
     145  glutSwapBuffers();
     148int main(int argc, char *argv[])
     150  glutInit(&argc,argv);
     151  glutInitDisplayMode(GLUT_DOUBLE);
     152  glutCreateWindow("first.c GL code");
     153  glutDisplayFunc(display);
     154  glutMainLoop();
     155  return 0;
     160from OpenGL.GLUT import *
     161from OpenGL.GL import *
     162import sys
     164def display():
     165    glClear(GL_COLOR_BUFFER_BIT)
     166    glColor3f(1.0, 0.4, 1.0)
     167    glBegin(GL_LINES)
     168    glVertex2f(0.1, 0.1)
     169    glVertex3f(0.8, 0.8, 1.0)
     170    glEnd()
     171    glutSwapBuffers()
     173if __name__ == "__main__":
     174    glutInit(sys.argv)
     175    glutInitDisplayMode(GLUT_DOUBLE)
     176    glutCreateWindow(" GL code")
     177    glutDisplayFunc(display)
     178    glutMainLoop()
     181Structure of the program is usually very similar for
     182all languages. Confer Listing 2 ( rewritten in Python. All GLUT
     183programs include commands in the following order:
     185 *Include definitions of constants and functions for OpenGL and GLUT
     186  with the include statement.
     187 * Initialize GLUT and setup other variables that are not directly
     188  related to OpenGL but rather to the object that is being visualized.
     189 * Set window parameters such as initial position, size, type, bit plane
     190  memory.
     191 * Create the window and name it.
     192 * Setup the features of the OpenGL machine. These are usually commands
     193  {{{glEnable}}} for setup of lighting, materials, lists, and non-default
     194  behavior of OpenGL machine.
     195 * Register call-back routines which will be called at events. Mandatory
     196  registration is just for {{{glutDisplayFunc(display)}}}. The rest are
     197  optional.
     198 * The last command in {{{main" is a call to "glutMainLoop}}}, from which
     199  the program returns when the window is closed. At the same time the
     200  {{{main}}} program ends.
     203The command {{{glutInit}}} initializes GLUT library routines. It is followed by
     204a request for window creation of a certain type. The constant {{{GLUT_DOUBLE}}}
     205and the default {{{GLUT_RGB}}} suggests that we want a double-buffered window
     206with a RGB space. Variable {{{window}}} keeps reference of window returned by
     207{{{glutCreateWindow}}} and at the same time instructs the OS to set the window
     208title. We have to tell to the window system which events the program will
     209intercept. For example given, this is only {{{display}}} of the contents of the
     210window. Call of the subroutine {{{glutDisplayFunc}}} instructs the
     211{{{glutMainLoop}}} that whenever requests from OS for window redisplay occurs
     212subroutine {{{display}}} should be called. Routines for handling events are
     213usually called ``call-back'' routines as it reside in program as standalone
     214code snippets that are called auto-magically at certain events from the
     215windowing system. When some event occurs is up to the windowing system that
     216follows user interaction. The main point to emphasize here is that
     217registered call-back routines do get additional information on the kind of
     218event. For example of keyboard event we can get also mouse (x,y)
     219coordinates besides the key pressed.
     222We have seen that the subroutine {{{display}}} includes commands responsible
     223for drawing in the window. All routines or functions there are OpenGL and
     224have prefix {{{gl}}} to the name. Prefix is necessary to distinguish them and
     225prevent name clash with other libraries. To understand the language one can
     226interpret function names without prefixes and suffixes as the OpenGL is
     227designed so, that the types of the arguments for all programming languages
     228are similar. Subroutine {{{display}}} is therefore responsible for drawing the
     229contents of the window. The {{{glClear}}} command clears the entire area of the
     230window. When clearing we need to define precisely what we want to clear by
     231argument given. In our case, this is {{{GL_COLOR_BUFFER_BIT}}}, which means
     232clearing of all pixels in the color buffer.
     234The {{{glColor}}} command to sets the current color of graphic elements that
     235will be drawn in subsequent commands. As an argument RGB color components
     236are passed. Usually commands with multiple arguments are provide for
     237different data types (integer, float, double) and some command can have
     238different number of arguments for the same command. To distinguish them
     239suffix is added. For the {{{glColor3f}}} suffix {{{3f}}} therefore means that the
     240subroutine has three arguments of type float. Choice of the arguments type
     241depends on application requirements. Programmer can freely choose data type
     242that suits most without the need of data type conversion. In our example we
     243have two variants for vertex command with different number of arguments of
     244the same type. {{{glVertex2f}}} means that we are specifying just two
     245coordinates while the third is by default z=0. Types of the arguments
     246specified as the suffix letter are as follows:
     247 f:: float in C language and {{{real*4}}} in Fortran.
     248 d:: double for C and {{{real*8}}} in Fortran.
     249 i:: integer (4 bytes).
     250 s:: short integer in C and {{{integer*2}}} in Fortran.
     251Besides fixed number of arguments there are also functions that take as an
     252argument vector (as a pointer to memory). For these the suffix contains
     253letter {{{v}}} at the end. Below are some interpretations of suffixes:
     254 3f:: Three arguments of {{{real}}}s follow as arguments.
     255 3i:: Three arguments of {{{integer}}}s follow as arguments.
     256 3fv:: One argument as a vector that contains three {{{float}}}s
     257  follows.
     258Variety of different arguments for the same command can be in {{{glVertex}}}
     259command where we can find
     262  glVertex2d,  glVertex2f,  glVertex2i, glVertex2s,  glVertex3d,  glVertex3f,
     263  glVertex3i,  glVertex3s,  glVertex4d, glVertex4f,  glVertex4i,  glVertex4s,
     264  glVertex2dv, glVertex2fv, glVertex2iv,glVertex2sv, glVertex3dv, glVertex3fv,
     265  glVertex3iv, glVertex3sv, glVertex4dv,glVertex4fv, glVertex4iv, glVertex4sv.
     267Large number of routines for the same function is performance and language
     268related in order to waive the default conversion and thus provide a more
     269comprehensive and faster code. For languages with name mangling like C++
     270one can find simpler OpenGL wrapped functions (eg. just {{{glVertex}}}) that
     271don't affects performance. But as many languages does not have name
     272mangling built into compiler such practise is not widespread. Besides
     273specifying single vertex each time one can use {{{glVertexPointer}}} and points
     274to memory where number of vertices of specified type exist. This can save
     275us of some looping, but as this is essentially copying of system memory
     276into OpenGL hardware engine, the performance is not really improved.
     278Drawing of graphic primitives in OpenGL occurs between two commands
     279{{{glBegin(primitive type)}}} and {{{glEnd()}}}. Primitive type given as argument
     280at the beginning specifies how subsequent vertices will be used for
     281primitive generation. Instead of giving primitive type as number several
     282predefined constant are provided within {{{include}}} directive to ease
     283readability and portability of the OpenGL programs. Before providing vertex
     284position one can change OpenGL engine primitive state such as current
     285drawing {{{glColor3f" or "glNormal}}} that is per vertex property.
     287The last command in the {{{display}}} subroutine is {{{glutSwapBuffers()}}}. For
     288applications in which the contents of the display changes frequently, it is
     289most appropriate to use windows dual graphics buffers, which is setup by
     290using the {{{GLUT_DOUBLE}}} at window initialization. The advantage of such
     291drawing strategy is in the fact that while one buffer is used for current
     292drawing the other is shown. Drawing thus occurs in the background and when
     293buffer is ready for display we simply flip the buffers. In particular it
     294should be noted that such behaviour is system dependent and once upon a
     295time when the {{{GLUT_SINGLE" (without double buffers) with the "glFlush()}}}
     296at the end was used instead. Nowadays {{{GLUT_DOUBLE}}} is usually used, which
     297is most helpful with high frame-rate applications such as animation.
     298Only simple primitives are used within OpenGL. Reason for that is mainly
     299due to the requirement of performance and possible hardware acceleration.
     300There are three types of simple primitives: points, lines, and triangles.
     301Higher level primitives (like quadrilaterals) can be assembled from simple
     302ones. Curves can be approximated by lines. Large surfaces can be tessellated
     303with triangles. For complex surfaces (like NURBS) GLU library can be used
     304to calculate vertices. The following line primitives are possible:
     305 GL_LINES:: Pairs of vertices in a vertex stream create line
     306  segments.
     307 GL_LINE_STRIP:: Vertex stream builds connected lines
     308  (polyline).
     309 GL_LINE_LOOP:: Same as polyline above except that last
     310  vertex is connected by a line to the first.
     311Every surface can be assembled with triangles.
     312 GL_TRIANGLES:: For each triangle three vertices are required
     313  from vertex stream.
     314 GL_TRIANGLE_STRIP:: Strip of triangles. For first triangle
     315  three vertices are needed. For every additional vertex new triangle is
     316  created by using last two vertices.
     317 GL_TRIANGLE_FAN:: Triangles are added to the first one by
     318  using first and last vertex to create a triangle fan.
     319== Modern OpenGL ==
     320Immediate mode programming with {{{glBegin" and "glEnd}}} was removed from
     321OpenGL 3.x as such transmission of vertex streams and its attributes
     322(colors, normals, ...) from system memory to GPU is considered as a major
     323performance drawback. Display lists were previously used to save stream of
     324OpenGL calls that also included vertex data and was just replayed at
     325redraw. But this is inherently sequential operation that blocked parallel
     326vertex processing. Requirement to store vertex arrays to GPU directly as an
     327''object'' can solve problem described. Storing vertex arrays into GPU
     328also means that manipulation on them to build the model should be inside
     329the GPU. Legacy OpenGL included many ``modelling'' utilities for
     330transforming world coordinates into viewport. Transformations of coordinate
     331systems in 3D space allowed manipulate model stack easily with
     332{{{glPushMatrix" and "glPopMatrix}}} commands. But similarly to
     333{{{glBegin"/"glEnd}}} such manipulations are not used outside GPU anymore.
     334Instead all operations on vertex data is transferred to ''vertex shader''.
     335There operations on data can be performed with standard vector
     336math in homogeneous coordinates.