Sunday, February 05, 2012

Proof of concept OpenGL program in python and Qt/PySide

Here is the output of my initial test program:




I am planning to test the performance of various ways of rendering lots of spheres using OpenGL. I will use python and Qt to run the tests. As a first step, I have created a very light hello program that renders the classic Utah teapot.


#!/usr/bin/python

# File teapot_test.py
# "hello world" type rendering of the classic Utah teapot
# Requires python modules PySide and PyOpenGL

from PySide.QtGui import QMainWindow, QApplication
from PySide.QtOpenGL import QGLWidget
from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *
import sys


def override(interface_class):
"""
Method to implement Java-like derived class method override annotation.
Courtesy of mkorpela's answer at
http://stackoverflow.com/questions/1167617/in-python-how-do-i-indicate-im-overriding-a-method
"""
def override(method):
assert(method.__name__ in dir(interface_class))
return method
return override


class SphereTestGLWidget(QGLWidget):
"GUI rectangle that displays a teapot"
@override(QGLWidget)
def initializeGL(self):
"runs once, after OpenGL context is created"
glEnable(GL_DEPTH_TEST)
glClearColor(1,1,1,0) # white background
glShadeModel(GL_SMOOTH)
glEnable(GL_COLOR_MATERIAL)
glMaterialfv(GL_FRONT, GL_SPECULAR, [1.0, 1.0, 1.0, 1.0])
glMaterialfv(GL_FRONT, GL_SHININESS, [50.0])
glLightfv(GL_LIGHT0, GL_POSITION, [1.0, 1.0, 1.0, 0.0])
glLightfv(GL_LIGHT0, GL_DIFFUSE, [1.0, 1.0, 1.0, 1.0])
glLightfv(GL_LIGHT0, GL_SPECULAR, [1.0, 1.0, 1.0, 1.0])
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [1.0, 1.0, 1.0, 0.0])
glEnable(GL_LIGHTING)
glEnable(GL_LIGHT0)
self.orientCamera()
gluLookAt(0, 0, -10, # camera
0, 0, 0, # focus
0, 1, 0) # up vector

@override(QGLWidget)
def paintGL(self):
"runs every time an image update is needed"
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
self.paintTeapot()

@override(QGLWidget)
def resizeGL(self, w, h):
"runs every time the window changes size"
glViewport(0, 0, w, h)
self.orientCamera()

def orientCamera(self):
"update projection matrix, especially when aspect ratio changes"
glPushAttrib(GL_TRANSFORM_BIT) # remember current GL_MATRIX_MODE
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
gluPerspective (60.0, self.width()/float(self.height()), 1.0, 10.0)
glPopAttrib() # restore GL_MATRIX_MODE

def paintTeapot(self):
glPushAttrib(GL_POLYGON_BIT) # remember current GL_FRONT_FACE indictor
glFrontFace(GL_CW) # teapot polygon vertex order is opposite to modern convention
glColor3f(0.2,0.2,0.5) # paint it blue
glutSolidTeapot(3.0) # thank you GLUT tool kit
glPopAttrib() # restore GL_FRONT_FACE


class SphereTestApp(QApplication):
"Simple application for testing OpenGL rendering"
def __init__(self):
QApplication.__init__(self, sys.argv)
self.setApplicationName("SphereTest")
self.mainWindow = QMainWindow()
self.gl_widget = SphereTestGLWidget()
self.mainWindow.setCentralWidget(self.gl_widget)
self.mainWindow.resize(1024, 768)
self.mainWindow.show()
sys.exit(self.exec_()) # Start Qt main loop


if __name__ == "__main__":
SphereTestApp()

2 comments:

Catalin George Festila said...

I got this errors ... I think is something with override or decorators :
Traceback (most recent call last):
File "opengl_test.py", line 53, in paintGL
self.paintTeapot()
File "opengl_test.py", line 73, in paintTeapot
glutSolidTeapot(3.0) # thank you GLUT tool kit
File "C:\Python34\lib\site-packages\OpenGL\platform\baseplatform.py", line 407
, in __call__
self.__name__, self.__name__,
OpenGL.error.NullFunctionError: Attempt to call an undefined function glutSolidT
eapot, check for bool(glutSolidTeapot) before calling

Biospud said...

@Catalan George Festila: I think you might need to install GLUT on your computer to get around a problem like that. There is something called FreeGLUT that might do the trick. http://www.transmissionzero.co.uk/software/freeglut-devel/