During these practicals, you will learn hands-on about graphics application basics using Python and the OpenGL and GLFW APIs. We will cover in particular the following topics:
creating an OpenGL render window with GLFW.
understanding the standard structure of a graphics application and its rendering loop
communicating your code, primitives, and parameters to the GPU with OpenGL
write shader code in GLSL (the shading language associated to OpenGL) which describes how to render primitives on the GPU
learn some typical aspects of handling meshes in a graphics program
implement standard illumination and texture mapping techniques
implement some typical algorithms used in computer animation
OpenGL is primarily a C API which for most graphics applications today is actually used with C++ (or C#) in the industry. There are many good reasons for that: often the goal is to have the fastest possible code on the CPU side, since rendering for real-time visualization means that a frame needs to be produced onscreen every 10, 16 or 33 milliseconds (for 100Hz, 60Hz, 30Hz refresh rates) and no time can be wasted.
Our objective here is significantly different: we want to learn and understand the key concepts as efficiently as possible, more than achieve absolute highest framerates. C/C++ are powerful but cluttered, error-prone low-level languages, that get in the way of this learning efficiency.
Python code is more straightforward, easier to read, write, and debug
It is less verbose (typically by a factor of 5-10 on the code size), and benefits from an extensive and intuitive set of built-ins (tuples, lists, dictionaries, arrays…)
In particular Python constructs, like generators, list and dictionary comprehensions are a great way to reduce simple object construction loops to one readable line of code, or create iterators that unclutter the code. Keep those in mind when you write your application.
Well written Python code can be quite fast already, and most inner loop tasks of interest to these practicals happen on the GPU anyway, once properly initialized.
What’s more, Python has excellent wrappers to OpenGL and window libraries whose interface closely match their C counterpart. Which means anything you learn about writing code in Python directly maps to the C APIs.
What tools will we use?¶
PyOpenGL is the Python wrapper of reference to use OpenGL in this scripting language. OpenGL has known many revisions since its creation in 1992, to follow the evolving hardware capabilities. We will be learning version 4 of OpenGL, the most recent major version of the API with full hardware programming capabilities. For our purposes we will be focusing on a subset of OpenGL 4 that is compatible with version 3.3 of the API, which has the main advantage of widespread compability across platforms if you want to run your code on your own machine. Read the How do PyOpenGL / pyGLFW wrappers work? FAQ for a primer about how wrappers work.
GLSL is the OpenGL programming language that was introduced in 2004 with OpenGL 2.1, when GPUs started being programmable. The language, based on a C-like syntax, has had major revisions that are not backward compatible. We learn an up-to-date version 4.00 and version 3.30 compatible subset of instructions, with the combined advantage of most recent hardware expressibility and widespread compability. An OpenGL reference card is available for quick reference of OpenGL and GLSL commands which will become increasingly readable and useful with time. There are excellent references to GLSL 4, including full books, this GLSL 4 book is really nice and progressive. Beware that a lot of the tutorials and books out there concern prior versions of OpenGL with deprecated syntax, don’t waste time on those.
OpenGL needs a window and system context to execute. pyGLFW is a Python wrapper to the GLFW library, a simple, lean, and cross-platform library for OpenGL context and window creation, which completely abstracts system windows and events.
Numpy stands for the Numerical Python library. It revolves on a central datatype, Numpy arrays, which are basically flat C arrays wrapped as Python objects. It offers fast, powerful and expressive computations over this type, such as vectorized operations and functions (+, -, *, /, sin, cos… over the whole array in one call), and full linear algebra support. It also supports multi-dimensional arrays of any dimension. This is all we need for the mathematics involved in the practicals. It is also one of the main building blocks PyOpenGL uses for passing OpenGL arguments.
If you need to catch up with Numpy, here is a very good Numpy tutorial, from scratch, many others being of course available.
Python >= 3.5 introduces the nice @ binary operator which is used for matrix products.
Some of the material and figures in these practicals is based on the excellent modern OpenGL tutorials on the web, which make for good complementary reading. They are generally written with C or C++ examples but easily transposable both ways with Python:
This version of the practicals is also based on contributions and feedback from various Ensimag collaborators throughout the years: Matthieu Chabanas, Franck Hetroy, Julien Daval, Thomas Delame, Maguelonne Beaud de Brive, Mathieu Bailet, Guillaume Cordonnier, Maxime Garcia, Romain Vergne, Stefanie Wuhrer, Marie-Paule Cani, among others.