gr_3d_fft_time - A 3D OpenGL FFT display in time
Questions, comments: j c o o l e y (at) m e d i a (dot) m i t (dot) e d u
Gnuradio has some GUIs built using wx and its python extension - specifically an oscilloscope, an fft, and a waterfall display. For my thesis, I'm devising ways to display ffts over time... well, that's what the waterfall display already does. I decided to see about using openGL because I thought we might get some performance improvement out of it, and can make a combined 3D waterfall-fft display.
So that's exactly what I ended up with. Performance is surprisingly good (esp. considering my PC and video card are not the fastest and there's lots of calculations done IN PYTHON). I'll bet an openGL 2D display would really cook.
Below are some pics (click for a larger version). What you are seeing is the last 20 ffts (in this case, taken from a repeating file of gnuradio samples), each displayed as "ribbons" and colorized according to amplitude. The display is NOT static. The ribbons move forward as new ffts are added at the back.
And, here are two movies. When the display is running, you have the ability to fly around the model using the mouse. These movies were made by doing that.
movie 1 and movie 2
My PC can barely draw the OpenGL frames and do the screen captures at the same time. That is why these movies appear so jerky. The movie framerate is NOT as fast in real life as appears in these movies.
OK, so how does it work?
You must install opengl, and have it enabled under linux in your xconfig. Many of the xscreensavers use openGL, so if they all work, you're probably good to go.
You also need pyOpenGL 2.0 installed. Like wxpython, (and gnuradio, for that matter), this abstracts openGL code so it can be used in python. You get to use GL, GLU, GLUT, GLE.
Finally, you need a package called OpenGLContext installed. It provides cross product and normalization routines needed to calculate surface normals.
So here's the code. WARNING: it is kind of a mess, I'm gradually cleaning it up and improving it, though I did put some good comments in there. There's a lot of places where I could probably speed things up, improve the threading arrangement, etc.
OK, so, openGL is kind of tricky to learn. I am hardly an expert, especially with the lighting stuff. There are lots of examples on the web, and you can do very well indeed by starting off drawing something simple like a:
(run ./gr_gl.py by itself to see a demo program of this!)
The trickiest stuff was to get the colorization and shading working properly. In order to ask openGL to smooth shade from one vertex to another (that is, to smoothly transition the color from one to the other), you have to tell it what the normal at each vertex is. In order to do that, you need to calculate and average the normals from surrounding polygons. What a pain in the neck.
The definitive guides to OpenGL are without question known as the "Red Book" and the "Blue Book".
There are many other source and examples on the web. Even examples written in C or C++ are fairly easily portable to pyOpenGL