Проблемы с PyOpenGL и PyQt5 в OSX

В этом семестре я знакомлюсь с компьютерной графикой, в настоящее время изучаю использование PyOpenGL и PyQt5 для изучения барицентрических координат. Мои одноклассники, использующие компьютеры с Windows, могут запускать следующий код без проблем прямо из коробки, но все мы на OSX сталкиваемся с одними и теми же проблемами. Я надеюсь, что у кого-то еще, у кого больше опыта работы с такой средой, может быть идея, как мы можем решить эти проблемы; мы все уже много гуглили, но безрезультатно. Спасибо!

Код:


    import sys
    from array           import array
    from ctypes          import c_void_p
    from OpenGL.GL       import *
    from OpenGL.GLU      import *
    from PyQt5.QtGui     import QImage, qRgb
    from PyQt5.QtOpenGL  import QGLWidget
    from PyQt5.QtWidgets import QApplication
    from textwrap        import dedent


    # create a function that draws a triangle via software rasterization
    def softwareRasterization(width, height, vertices, colors):
        image = QImage(width, height, QImage.Format_RGB32)
        # TODO: compute the bounding box around the given vertices
        # TODO: compute the barycentric coordinates for each point in the box
        # TODO: color the points that are inside of the triangle
        if image.save("triangle.jpg", None, 100):
            print("Output triangle.jpg")
        else:
            print("Unable to save triangle.jpg")


    # extend QGLWidget to draw a triangle via hardware rasterization
    class HardwareRasterizationWidget(QGLWidget):

        def __init__(self, vertices, colors, *args, **kwargs):
            super().__init__(*args, **kwargs)
            self.vertices = array('f')
            # TODO: convert the input coordinate to normalized device coordinates
            self.colors = array('f', colors)


        def _sizeof(self, a):
            return a.itemsize * len(a)


        def initializeGL(self):

            verticesSize = self._sizeof(self.vertices)

            # create a new Vertex Array Object on the GPU which saves the attribute
            # layout of our vertices
            vao = glGenVertexArrays(1)
            glBindVertexArray(vao)

            # create a buffer on the GPU for position and color data
            dataBuffer = glGenBuffers(1)

            # upload the data to the GPU, storing it in the buffer we just created
            # TODO: upload the color data into the GPU buffer as well
            glBindBuffer(GL_ARRAY_BUFFER, dataBuffer)
            glBufferData(
                GL_ARRAY_BUFFER,
                verticesSize,
                None,
                GL_STATIC_DRAW
            )
            glBufferSubData(
                GL_ARRAY_BUFFER,
                0,
                verticesSize,
                self.vertices.tostring()
            )

            # load our vertex and fragment shaders into a program object on the GPU
            program = self.loadShaders()

            # bind the attribute "position" (defined in our vertex shader) to the
            # currently bound buffer object, which contains our position data
            # this information is stored in our vertex array object
            position = glGetAttribLocation(program, 'position')
            glEnableVertexAttribArray(position)
            glVertexAttribPointer(
                position,
                3,
                GL_FLOAT,
                GL_FALSE,
                0,
                c_void_p(0)
            )

            # TODO: bind the attribute "color" to the buffer object


        def loadShaders(self):
            # create a GL Program Object
            program = glCreateProgram()

            # vertex shader
            # TODO: add a color input and color output
            vs_source = dedent("""
                #version 330
                in vec3 position;
                void main()
                {
                   gl_Position = vec4(position, 1.0);
                }\
            """)
            vs = glCreateShader(GL_VERTEX_SHADER)
            glShaderSource(vs, vs_source)
            glCompileShader(vs)
            glAttachShader(program, vs)
            if glGetShaderiv(vs, GL_COMPILE_STATUS) != GL_TRUE:
                raise RuntimeError(glGetShaderInfoLog(vs))

            # fragment shader
            # TODO: add a color input with the same name as the vertex output
            fs_source = dedent("""
                #version 330
                void main()
                {
                   gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
                }\
            """)
            fs = glCreateShader(GL_FRAGMENT_SHADER)
            glShaderSource(fs, fs_source)
            glCompileShader(fs)
            glAttachShader(program, fs)
            if glGetShaderiv(fs, GL_COMPILE_STATUS) != GL_TRUE:
                raise RuntimeError(glGetShaderInfoLog(fs))

            # use the program
            glLinkProgram(program)
            glUseProgram(program)

            return program


        def paintGL(self):
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
            glDrawArrays(GL_TRIANGLES, 0, 3)


        def resizeGL(self, width, height):
            glViewport(0, 0, width, height)



    if __name__ == "__main__":

        width = 640
        height = 480

        # TODO: prompt the user for 3 points and colors separated by spaces
        # TODO: validate input and parse into the vertices and colors lists

        vertices = [
            50, 50, 0,    # vertice 1
            600, 20, 0,   # vertice 2
            300, 400, 0   # vertice 3
        ]
        colors = [
            1, 0, 0,  # color 1
            0, 1, 0,  # color 2
            0, 0, 1   # color 3
        ]

        softwareRasterization(width, height, vertices, colors)

        app = QApplication(sys.argv)
        w = HardwareRasterizationWidget(vertices, colors)
        pRatio = w.devicePixelRatio()
        w.resize(width/pRatio, height/pRatio)
        w.show()

        sys.exit(app.exec_())

Ошибки:


Traceback (most recent call last):
File "/Users/JesseRichmond/vEnvPyCharm/lib/python3.5/site-packages/OpenGL/latebind.py", line 41, in __call__
return self._finalCall( *args, **named )
TypeError: 'NoneType' object is not callable

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
File "/Users/JesseRichmond/Desktop/Spring 2017 Academics/Projects/310/rasterization.py", line 45, in initializeGL
vao = glGenVertexArrays(1)
File "/Users/JesseRichmond/vEnvPyCharm/lib/python3.5/site-packages/OpenGL/latebind.py", line 45, in __call__
return self._finalCall( *args, **named )
File "/Users/JesseRichmond/vEnvPyCharm/lib/python3.5/site-packages/OpenGL/wrapper.py", line 657, in wrapperCall
result = wrappedOperation( *cArguments )
File "/Users/JesseRichmond/vEnvPyCharm/lib/python3.5/site-packages/OpenGL/platform/baseplatform.py", line 407, in __call__
self.__name__, self.__name__,
OpenGL.error.NullFunctionError: Attempt to call an undefined function glGenVertexArrays, check for bool(glGenVertexArrays) before calling


person Jesse Richmond    schedule 29.03.2017    source источник
comment
Просто догадка, так как у меня нет Mac, но можете ли вы проверить версию OpenGL для контекста вашего приложения? Вы можете сделать это, распечатав содержимое файла glGetString(GL_VERSION);. Я знаю, что некоторые операционные системы, такие как OSX, могут быть придирчивыми и требовать, чтобы вы указали основную и дополнительную версии OpenGL для вашего приложения, чтобы создать соответствующий контекст, или они по умолчанию будут использовать устаревший контекст, такой как 2.1. Я думаю, что это может иметь место здесь, поскольку glGenVertexArrays в конце концов является функцией OpenGL 3.0...   -  person CodeSurgeon    schedule 30.03.2017
comment
Спасибо за ответ. Однако возникают проблемы даже с печатью результата glGetString(GL_VERSION). Я получаю ошибку Process finished with exit code 139 (interrupted by signal 11: SIGSEGV) даже в небольшой программе отладки, где я импортирую * из OpenGL.GL.   -  person Jesse Richmond    schedule 31.03.2017
comment
Куда вы помещаете вызов glGetString(GL_VERSION)? Вы пытались поместить его в свою функцию paintGL? Кроме того, что интересно, я наконец установил Qt и PyQt5, и когда я запускаю ваш код (в Windows 10), я просто получаю черный экран и пустой файл triangle.jpg, записанный на мой жесткий диск...   -  person CodeSurgeon    schedule 31.03.2017
comment
Да, это то, что должно происходить. Код отлично работает для всех моих одноклассников, использующих Windows, — он неполный, потому что это программа для начинающих, написанная проф. Я попробую добавить функцию getString в paintGL, когда вернусь к своему компьютеру.   -  person Jesse Richmond    schedule 01.04.2017
comment
Вы также можете проверить этот вопрос в stackoverflow (такая же/похожая проблема, с которой вы столкнулись), а также этот ответ на другой вопрос, где они показывают, как принудительно настроить основной профиль OpenGL в PyQT, если вы еще этого не видели. Я лично использовал PyOpenGL только через PyGame и PySDL2, поэтому, к сожалению, я не могу рассказать вам слишком много о PyQT. Это определенно проблема настройки контекста, а не OpenGL!   -  person CodeSurgeon    schedule 02.04.2017