Opengl and pyglet basics

A pyglet micro-tutorial.

Opengl and pyglet basics

A pyglet micro-tutorial.

I’ve been learning to program graphics with pyglet, a python binding for opengl. I’ve noticed that there aren’t any really great or clear tutorials that actually explain things. Most of the tutorials add code without explaining what each line of code is responsible for doing. The last point is particularly problematic in graphics because there are so many little settings and options. It’s also worth noting that many settings don’t really do much of anything in isolation and only work with other settings.

In this tutorial we are going to go over some basics to get your going and some little quirks. Eventually we will render 3D objects and structures in a later tutorials. By the end of this tutorial we’ll make an animation that looks like plane propellers!

Propeller animation freeze frame!

Before we do anything else in pyglet we’ll want to make a window. A window is literally an empty box that appears on the screen:

This should show a black window like so:

In the next section we will be taking this window and overriding an event method. These events are functions that trigger when a certain thing happens to/in this window. We will be overriding the on_draw function on the window object we created. This event is triggered once at the beginning when the window is loaded. There are ways to update and redraw things in the window but we’ll get to that later in the post. We override this function by using a decorator, @win.event, that is builtin to the window object we created. Let’s override the function and see what happens…

If you run this it should produce a black window like before and also output a printed Draw triggered! on the command line or jupyter notebook output. This confirms for us that on_draw is triggered once on the window load. Next we will draw a line in our window. The way drawing lines works in pyglet is that you grab an opengl context and then create vertices in this context, the vertices then get connected, in the order you declared them, in the way the context specifies. As you can see below glBegin(GL_LINES) creates a context where we can draw, you guessed it, lines and glEnd ends this context. Every two vertices we create in this context will be linked together as a line. We will use the glVertex3f function to make a vertex in 3 dimensions taking 3 floats. The first 2 floats are x,y coordinates on the scale of the size of the window (if your window is 400x400 and example for the first 2 values could be 100.0, 100.0, the z value is a value between -1 and 1 that represents depth. Let’s see what this looks like:

Should output a window like this:

Believe it or not this line is a 3D structure! There’s some caveats though; if you put a number outside the range [-1,1] for z the vertex and thus the line will not appear. Another caveat is that this z value isn’t always in [-1,1] but for now it is (I know that’s a bit dumb). This line is admittedly boring. Let’s spuce things up by making it an animation; we will make the line spin.

It should output an animation like a spinning wheel like so:

Let’s explain the code a bit. The PointsInCircum method (which I poached from stack overflow) gets all the points in a circle centered around 0. We will use it to generate the points which will connect with the center of the circle with a line. We get 20 of these points and convert them to a numpy array. This numpy array is now of the shape 20x2 where the 2 elements are y and x in that order. Ok so how did we get the window to redraw continuously? We used the pyglet.clock.schedule(update_frame, 1/10) function call. It calls the update_frame function every 1/10th of a second and then calls the on_draw event as well (this is done under the hood). We are going to use the scheduler to increment and grab the next point in the circle and store it in a variable called frame, then we are going to tell on_draw to draw whatever point currently referenced by frame. This works because both update_frame and on_draw can see the frame variable. glClear(GL_COLOR_BUFFER_BIT) clears the ‘color buffer’ everytime the on_draw method is called. What is that? It’s an array that stores all the color pixels you see on your screen; glClear says to empty out a thing and GL_COLOR_BUFFER_BIT tells opengl which thing to empty. The bit is literally an index into a data structure which stores the list with all the colors on screen.

I went made a double for loop and plastered this wheel across the screen which ended up pretty cool. The quality is a bit bad at first but improves near the end:

You can also make the rotation smoother by increasing n=100 in PointsInCircum:

This animation is pretty basic and if you were going to really do it you’d probably use something with a more friendly interface, like a sprite. Here’s some examples for how you would probably make a real animation. If you are interested in learning about opengl you should checkout my other post where I annotate a tutorial series on the basics.

That’s it for this micro-tutorial! In the next one we will make 3D objects so that should be a lot more fun. Stay tuned! If you like machine learning, games, and graphics you should subscribe to my newsletter: Generation Machine! Also follow me on twitter. I’m always available for questions there so please ask them!