【问题标题】:PySide2 OpenGL error when using custom QSurfaceFormat使用自定义 QSurfaceFormat 时出现 PySide2 OpenGL 错误
【发布时间】:2020-12-09 19:02:05
【问题描述】:

我使用QSurfaceFormat 明确定义OpenGL 核心配置文件 并设置次要/主要版本。问题是,自定义表面格式的分配给了我以下错误:

Traceback (most recent call last):
  File "/home/artem/PycharmProjects/PolyEdit3D/PolyEdit3D/Widgets/PlyViewport.py", line 22, in initializeGL
    gl.glEnable(gl.GL_COLOR_BUFFER_BIT)
  File "/home/artem/.local/lib/python3.7/site-packages/OpenGL/platform/baseplatform.py", line 415, in __call__
    return self( *args, **named )
  File "src/errorchecker.pyx", line 58, in OpenGL_accelerate.errorchecker._ErrorChecker.glCheckError
OpenGL.error.GLError: GLError(
    err = 1280,
    description = b'invalid enumerant',
    baseOperation = glEnable,
    cArguments = (GL_COLOR_BUFFER_BIT,)
)
Traceback (most recent call last):
  File "/home/artem/PycharmProjects/PolyEdit3D/PolyEdit3D/Widgets/PlyViewport.py", line 69, in paintGL
    gl.glDrawElements(gl.GL_TRIANGLES, 6, gl.GL_UNSIGNED_INT, ctypes.c_void_p(0))
  File "src/latebind.pyx", line 39, in OpenGL_accelerate.latebind.LateBind.__call__
  File "src/wrapper.pyx", line 318, in OpenGL_accelerate.wrapper.Wrapper.__call__
  File "src/wrapper.pyx", line 311, in OpenGL_accelerate.wrapper.Wrapper.__call__
  File "/home/artem/.local/lib/python3.7/site-packages/OpenGL/platform/baseplatform.py", line 415, in __call__
    return self( *args, **named )
  File "src/errorchecker.pyx", line 58, in OpenGL_accelerate.errorchecker._ErrorChecker.glCheckError
OpenGL.error.GLError: GLError(
    err = 1282,
    description = b'invalid operation',
    baseOperation = glDrawElements,
    pyArgs = (
        GL_TRIANGLES,
        6,
        GL_UNSIGNED_INT,
        c_void_p(None),
    ),
    cArgs = (
        GL_TRIANGLES,
        6,
        GL_UNSIGNED_INT,
        c_void_p(None),
    ),
    cArguments = (
        GL_TRIANGLES,
        6,
        GL_UNSIGNED_INT,
        c_void_p(None),
    )
)

如您所见,gl.glEnable(gl.GL_COLOR_BUFFER_BIT) 和其他简单的事情有一个错误。如果不指定QSurfaceFormat,一切都会像魅力一样发挥作用。

这是我的表面格式类:

class GLSurfaceFormat(QtGui.QSurfaceFormat):
    def __init__(self):
        super(GLSurfaceFormat, self).__init__()
        self.__initSurface()

    def __initSurface(self):
        self.setRenderableType(QtGui.QSurfaceFormat.OpenGL)
        self.setMinorVersion(3)
        self.setMajorVersion(4)
        self.setProfile(QtGui.QSurfaceFormat.CoreProfile)
        self.setColorSpace(QtGui.QSurfaceFormat.sRGBColorSpace)
        self.setSwapBehavior(QtGui.QSurfaceFormat.DoubleBuffer)

我是这样分配的:

    QApplication.setAttribute(Qt.AA_UseDesktopOpenGL)
    QSurfaceFormat.setDefaultFormat(GLSurfaceFormat())

    app = QApplication(sys.argv)
    ...

您能告诉我,QSurfaceFormat 的用法有什么错误吗?还是有其他问题?

!更新! 这是一个简单的示例,您可以在其中重现相同的行为:

from PySide2 import QtCore, QtGui, QtWidgets
from OpenGL import GL as gl
from OpenGL.GL.shaders import compileProgram, compileShader
import numpy as np
import ctypes
import sys
import glm

class PlyViewportWidget(QtWidgets.QOpenGLWidget):
    def __init__(self):
        super(PlyViewportWidget, self).__init__(parent=None)
        self.vao = None
        self.vbo = None
        self.ebo = None
        self.shaderProg = None
        self.isWireframe = False

    def initializeGL(self):
        gl.glEnable(gl.GL_COLOR_BUFFER_BIT)
        gl.glClearColor(0.4, 0.4, 0.4, 1)

        with open("fragment.glsl", 'r') as f:
            fragment = compileShader(f.read(), gl.GL_FRAGMENT_SHADER)
        with open("vertex.glsl", "r") as f:
            vertex = compileShader(f.read(), gl.GL_VERTEX_SHADER)
        self.shaderProg = compileProgram(vertex, fragment)

        vertices = np.array(
            [
                0.5, 0.5, 0.0,
                0.5, -0.5, 0.0,
                -0.5, -0.5, 0.0,
                -0.5, 0.5, 0.0
            ], dtype=ctypes.c_float
        )
        indices = np.array(
            [
                0, 1, 3,
                1, 2, 3
            ], dtype=ctypes.c_uint
        )

        self.vbo = gl.glGenBuffers(1)
        self.ebo = gl.glGenBuffers(1)

        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vbo)
        gl.glBufferData(gl.GL_ARRAY_BUFFER, vertices.nbytes, vertices, gl.GL_STATIC_DRAW)

        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.ebo)
        gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, gl.GL_STATIC_DRAW)

        gl.glEnableVertexAttribArray(0)
        gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE, 3 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0))

        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
        gl.glBindVertexArray(0)

        gl.glUseProgram(self.shaderProg)

    def paintGL(self):
        gl.glClearColor(0.4, 0.4, 0.4, 1.0)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT)

        trans = self.getTransformMatrix()
        #u_transform = gl.glGetUniformLocation(self.shaderProg, "u_transform")
        #gl.glUniformMatrix4fv(u_transform, 1, gl.GL_FALSE, u_transform)

        gl.glBindVertexArray(self.vao)
        gl.glDrawElements(gl.GL_TRIANGLES, 6, gl.GL_UNSIGNED_INT, ctypes.c_void_p(0))

    def resizeGL(self, w:int, h:int):
        gl.glViewport(0, 0, w, h)

    def keyPressEvent(self, event:QtGui.QKeyEvent):
        self.makeCurrent()
        if event.key() == QtCore.Qt.Key_Z and not self.isWireframe:
            gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_LINE)
            self.isWireframe = True
            self.update()
        elif event.key() == QtCore.Qt.Key_Z and self.isWireframe:
            gl.glPolygonMode(gl.GL_FRONT_AND_BACK, gl.GL_FILL)
            self.isWireframe = False
            self.update()

        event.accept()

    def getTransformMatrix(self):
        return glm.rotate(glm.mat4(1.0), glm.radians(90.0), glm.vec3(1.0, 0.0, 0.0))


class GLSurfaceFormat(QtGui.QSurfaceFormat):
    def __init__(self):
        super(GLSurfaceFormat, self).__init__()
        self.__initSurface()

    def __initSurface(self):
        self.setRenderableType(QtGui.QSurfaceFormat.OpenGL)
        self.setMinorVersion(3)
        self.setMajorVersion(4)
        self.setProfile(QtGui.QSurfaceFormat.CoreProfile)
        self.setColorSpace(QtGui.QSurfaceFormat.sRGBColorSpace)
        self.setSwapBehavior(QtGui.QSurfaceFormat.DoubleBuffer)


if __name__ == '__main__':

    QtWidgets.QApplication.setAttribute(QtCore.Qt.AA_UseDesktopOpenGL)
    # Uncomment to get this damn error!!!
    #QtGui.QSurfaceFormat.setDefaultFormat(GLSurfaceFormat())

    app = QtWidgets.QApplication(sys.argv)
    window = PlyViewportWidget()
    window.show()
    sys.exit(app.exec_())

vertex.glsl

#version 330 core

layout (location = 0) in vec3 aPos;

void main()
{
    gl_Position = vec4(aPos, 1.0);
}

fragment.glsl

#version 330 core

out vec4 FragColor;

void main()
{
    FragColor = vec4(1.0f, 0.5f, 0.2f, 1.0f);
} 

【问题讨论】:

  • 我不确定该错误是否与显示的代码有关。相反,您似乎只是在 PlyViewport.py 某处使用无效枚举值 GL_COLOR_BUFFER_BIT 调用 glEnable
  • @G.M.,PlyViewport.pyQOpenGLWidget 的子类。我在 initializeGL 方法中使用 glEnableproper 枚举(由于 QT API 文档,这是正确的)。顺便说一句,我已经提到我的应用程序运行完美。我只有在指定 QSurfaceFormat 后才能看到这种行为
  • 为什么调用gl.glBindVertexArray(0)
  • @Rabbid76,这是来自 learnopengl.com 的代码 sn-p。作者在那里解除了 VAO 的绑定,我没有改变任何东西。看看第 136 行:github.com/JoeyDeVries/LearnOpenGL/blob/master/src/…
  • 但作者随后在第 157 行的渲染循环中重新绑定了 VAO。

标签: python opengl pyqt5 pyside2 pyopengl


【解决方案1】:

GL_COLOR_BUFFER_BIT 不是glEnable 的有效枚举常量,但它是glClear 的正确参数。
调用glClear,在glClearColor设置清除颜色后:

class PlyViewportWidget(QtWidgets.QOpenGLWidget):
    # [...]

    def initializeGL(self):
        
        #gl.glEnable(gl.GL_COLOR_BUFFER_BIT) <---- DELETE
        
        gl.glClearColor(0.4, 0.4, 0.4, 1)

        gl.glClear(gl.GL_COLOR_BUFFER_BIT) # <---- ADD

你错过了创建命名Vertex Array Object

class PlyViewportWidget(QtWidgets.QOpenGLWidget):
    # [...]

    def initializeGL(self):
        # [...]

        self.vao = gl.glGenVertexArrays(1) # <--- 
        gl.glBindVertexArray(self.vao)     # <--- 

        self.vbo = gl.glGenBuffers(1)
        self.ebo = gl.glGenBuffers(1)

        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, self.vbo)
        gl.glBufferData(gl.GL_ARRAY_BUFFER, vertices.nbytes, vertices, gl.GL_STATIC_DRAW)

        gl.glBindBuffer(gl.GL_ELEMENT_ARRAY_BUFFER, self.ebo)
        gl.glBufferData(gl.GL_ELEMENT_ARRAY_BUFFER, indices.nbytes, indices, gl.GL_STATIC_DRAW)

        gl.glEnableVertexAttribArray(0)
        gl.glVertexAttribPointer(0, 3, gl.GL_FLOAT, gl.GL_FALSE, 3 * ctypes.sizeof(ctypes.c_float), ctypes.c_void_p(0))

        gl.glBindBuffer(gl.GL_ARRAY_BUFFER, 0)
        gl.glBindVertexArray(0)

【讨论】:

  • 感谢您的注意,这次我在错误输出中没有看到任何提及 GL_COLOR_BUFFER_BITglEnable,但我仍然有很多错误指向 glDrawElementsglVertexAttribPointer所以我在屏幕上看不到矩形。里面不应该有任何错误,在其他情况下它不会在示例中起作用。
  • @Artem 你错过了self.vao = gl.glGenVertexArrays(1);gl.glBindVertexArray(self.vao)
  • 但是我可以问你一个问题,为什么在我指定 QSurfasceFormat 之前它可以工作并且没有抛出任何错误?
  • @Artem 对于兼容性 contexz,默认 VAO (0) 有效,但对于核心配置文件则无效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多