Search code examples
pythonpyqtaccess-violationpyopengl

PyOpenGL Access Violation Reading when calling glutWireSphere()


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?


Solution

  • 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 :)