Wednesday 28 May 2014

Intro to pyglet and OpenGL

After taking a look at this awesome Minecraft demo written in Python, I decided to do a little digging and playing with the library it uses to use the OpenGL graphics renderer with the ultimate goal of making a 3D game from scratch as an outreach project. Predictably 'having a play' took quite a while to get working because I'd never seen much OpenGL before so I thought I would put together a step by step guide to getting started for those NOT familiar with OpenGL but with some experience of Python.

Here's a minimum working example of a pyglet window using the openGL commands to draw something simple:

Looking at this step by step, we're importing our library as per usual, creating a window, defining an method called 'on_draw' and then initialising the entire program using the line: pyglet.app.run()

You may notice that the one method we have defined isn't actually called anywhere - that's because it's called automatically within the pyglet.app.run() method. There are other functions that are automatically called as well; update() and on_resize() which we will come back to - but they're there to make things easier for the programmer. They trigger at particular time intervals and when the window is resized (or created) respectively.

Looking at the OpenGL commands, we first declare what shape of object we're going to draw with glBegin(GL_TRIANGLES) (we could also pick GL_POINTS, GL_LINES, GL_QUADS and more)
then we specify the location of the vertices, and then we declare the glEnd() so our program knows we're finished drawing and can start rendering for us.

So what's a vertex? It's a point or a corner. If you're drawing points then the 'vertex' is just the location of the point. If you're drawing more complicated shapes then the vertices are the locations of the corners (so a triangle will have 3, a quad [a shape with 4 sides] will have 4 and a polygon can have as many as you want). Pyglet then 'fills' in the rest of the shape for you by filling in the locations between the corners. So what's with the '2i' bit? That's how many dimensions your drawing in. In this tutorial (for simplicity's sake) we will stick to making and moving things in 2D but the next tut will show you how to generalise into 3D.

Challenge!
Using only what I've used above, a couple of other commands below, the power of google (and educated guesses!) try making something impressive out of ONLY the simple shapes described above.
One point to know is that the location (0,0) corresponds to the lower left-hand corner of your window, hence if your window is 400 x 400 pixels, the then upper-right corner is going to be at location (400,400), the upper-left at (0,400) and the lower-right at (400, 0).



Colours
Everything is more impressive with colours, and our image is sorely lacking them. Adding colours in is simple - just add in the commands, and play with the numbers to change the colours:

That said, if you have overlapping triangles then colouring can be a real pain - so if you want to just display outlines of your triangles (to start with anyway) just put in this command and then comment it out when you don't need it.



Challenge!
What happens if you give different corners of the same triangle different colours?

Shortcuts
Ok, defining every point by trial and error quickly gets really tiresome. Conveniently there's a few shortcut commands to speed up the process thanks to pyglet:

This command cuts out the need for the glBegin and glEnd and the individual vertex commands and just gives pyglet a list of locations to connect into a triangle. Here's a working example of its use:
Methods
To do really cool stuff with pyglet (and programming in general!) we're going to have to wrap our code up into nice little chunks called 'methods' which we can call again and again rather than copy-pasting our code all the time. The on_draw bit from the code above is a method that is run every time the program loops. We're going to define another one for making triangles:
Try including this in your code (Hint: put the method BEFORE the on_draw function and call the method INSIDE the on_draw function instead of the current code we have in there).

Extension Challenge!
Given your experience with these shapes now - what's the most complicated design/shape/image you can represent using only triangles? Here's a clue - the below image is called a Voronoi tessellation (google it - there's some amazing art out there based on this technique).

Next tutorial we will use the OpenGL rotation and motion tools in 2D

References:
http://www.pyglet.org/doc/api/pyglet.graphics-module.html
https://github.com/fogleman/Minecraft
http://stackoverflow.com/questions/7681899/moving-an-image-around-in-3d-space
http://stackoverflow.com/questions/4269079/mixing-2d-and-3d-in-opengl-using-pyglet






No comments:

Post a Comment