I am building an application using PyOpenGL
and PyQt5
on Python3.5.2
The purpose of the application is to setup a window with QGLWidget
class and draw a sphere using glutWireSphere
function. The code works fine on my Ubuntu Linux 16.04 LTS
laptop but it crashes on my Windows 7
desktop with OSError: exception: access violation reading 0x00000000000000C1
in the line of glutWireSphere
. If I comment out this line, the program executes normally. I tried a different code example (sample below) that demonstrates how to draw a sphere with glut
and it did not crushed, but it manages the windowing with glut
.
My Code:
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
from PyQt5.QtOpenGL import *
from PyQt5 import QtGui
from PyQt5 import QtWidgets
from PyQt5 import QtCore
class MyWidget(QGLWidget):
def __init__(self, parent = None):
super(MyWidget, self).__init__(parent)
self.cameraDistanceZ = 10
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glColor3f(0.33, 0.33, 0.33)
glutSolidSphere(1, 20, 20)
def resizeGL(self, w, h):
glViewport(0, 0, w, h)
self.setOrthoProjection()
self.screenCenterX = w/2
self.screenCenterY = h/2
def setOrthoProjection(self):
glMatrixMode(GL_PROJECTION)
glLoadIdentity()
w = self.width()
h = self.height()
glOrtho(-10, 10, -10, 10, -5.0, 15.0)
gluLookAt(0,0,self.cameraDistanceZ, 0,0, -10, 0,1,0)
def initializeGL(self):
print("Start init process")
glutInit(sys.argv)
glClearColor(0.0, 0.0, 0.1, 0.0)
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glClearDepth(1.0)
self.updateGL()
def main():
app = QtWidgets.QApplication(["To parathyro"])
widget = MyWidget()
widget.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
Working example:
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
import sys
def main():
glutInit(sys.argv)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowSize(400,400)
glutCreateWindow(b"myWindow")
glClearColor(0.,0.,0.,1.)
glShadeModel(GL_SMOOTH)
glEnable(GL_CULL_FACE)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
lightZeroPosition = [10.,4.,10.,1.]
lightZeroColor = [0.8,1.0,0.8,1.0] #green tinged
glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition)
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor)
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1)
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05)
glEnable(GL_LIGHT0)
glutDisplayFunc(display)
glMatrixMode(GL_PROJECTION)
gluPerspective(40.,1.,1.,40.)
glMatrixMode(GL_MODELVIEW)
gluLookAt(0,0,10,
0,0,0,
0,1,0)
glPushMatrix()
glutMainLoop()
return
def display():
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
glPushMatrix()
color = [1.0,0.,0.,1.]
glMaterialfv(GL_FRONT,GL_DIFFUSE,color)
glutWireSphere(1,20,20)
glPopMatrix()
glutSwapBuffers()
return
if __name__ == '__main__': main()
If i try to draw something else, for example glutSolidSphere
I get the same error but on a different address. All access violation errors I have found online are application specific and they are mostly related to wrong input type in some function. There is not much room for such a mistake in my application since functions in my code do not take many arguments, or there is something that I have not noticed yet.
For my Windows 7
desktop system I downloaded Python 3.5.2
from the official website, I installed PyQt5
using pip
and PyOpenGL
through the Unofficial Windows Binaries for Python Extension Packages according to these instructions
I thought it was something related to problems in the freeglut
library but it works on a different example. I guess it has something to do with how I initialize freeglut
in my application, or it is related to PyQT5
Question
How can I track the problem and solve it without moving to different architecture for my application?
It seems the crash occurs because glutWireSphere requires you to call first glutCreateWindow
, check this little snippet for example:
from OpenGL.GLUT import *
from OpenGL.GLU import *
from OpenGL.GL import *
from PyQt5.Qt import * # noqa
class MyWidget(QGLWidget):
def __init__(self, parent=None):
super().__init__(parent)
def paintGL(self):
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
glPushMatrix()
color = [1.0, 0., 0., 1.]
glMaterialfv(GL_FRONT, GL_DIFFUSE, color)
glutWireSphere(1, 20, 20)
glPopMatrix()
glutSwapBuffers()
def glutInitialization(self):
glutInit(sys.argv)
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH)
glutInitWindowSize(400, 400)
glutCreateWindow(b"Glut Window")
def initializeGL(self):
glClearColor(0., 0., 0., 1.)
glShadeModel(GL_SMOOTH)
glEnable(GL_CULL_FACE)
glEnable(GL_DEPTH_TEST)
glEnable(GL_LIGHTING)
lightZeroPosition = [10., 4., 10., 1.]
lightZeroColor = [0.8, 1.0, 0.8, 1.0] # green tinged
glLightfv(GL_LIGHT0, GL_POSITION, lightZeroPosition)
glLightfv(GL_LIGHT0, GL_DIFFUSE, lightZeroColor)
glLightf(GL_LIGHT0, GL_CONSTANT_ATTENUATION, 0.1)
glLightf(GL_LIGHT0, GL_LINEAR_ATTENUATION, 0.05)
glEnable(GL_LIGHT0)
glMatrixMode(GL_PROJECTION)
gluPerspective(40., 1., 1., 40.)
glMatrixMode(GL_MODELVIEW)
gluLookAt(0, 0, 10,
0, 0, 0,
0, 1, 0)
glPushMatrix()
self.glutInitialization()
def main():
app = QApplication(["To parathyro"])
widget = MyWidget()
widget.setWindowTitle("Pyqt Widget")
widget.show()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
You can see how the sphere will appear in the pyqt window (active gl context). Then, comment glutCreateWindow(b"Glut Window")
and run it again, so you'll see the seg fault crash will appear back.
My suggestion? I wouldn't rely on glut geometric function when not using Glut as the opengl window management system.
Btw, generating a sphere isn't hard at all and is worth you give it a shot :)