在 pyqt5 中使用 QOpenGLWidget 时如何妥善销毁 opengl 资源

问题描述 投票:0回答:1

首先,我的代码如下:

from PyQt5.QtWidgets import QApplication, QOpenGLWidget, QMainWindow
from PyQt5.QtGui import QPainter, QOpenGLShader, QOpenGLShaderProgram, QMatrix4x4, QOpenGLBuffer, QOpenGLVertexArrayObject
from PyQt5.QtCore import Qt, QTimer

import numpy as np
import OpenGL.GL as gl
import sys

class OpenGLWidget(QOpenGLWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.frame_count = 0

    def initializeGL(self):
        self.program = QOpenGLShaderProgram()
        self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, """
            attribute highp vec4 aPos;
            void main() {
                gl_Position = aPos;
            }
        """)
        self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, """
            void main() {
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
            }
        """)

        self.program.link()
        self.program.bind()

        self.vertices = np.array([
            [-0.5, -0.5, 0.0, 1.0],
            [0.0, -0.5, 0.0, 1.0],
            [-0.25, 0.0, 0.0, 1.0],
            [-0.5, 0.5, 0.0, 1.0],
            [0.0, 0.5, 0.0, 1.0],
        ], dtype=np.float32)

        self.indices = np.array([
            0,1,2,2,3,4
        ], dtype=np.uint16)
        
        self.vao = QOpenGLVertexArrayObject()
        self.vbo = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer)
        self.ibo = QOpenGLBuffer(QOpenGLBuffer.IndexBuffer)
        self.vao.create()
        self.vbo.create()
        self.ibo.create()
        self.vao.bind()        
        self.vbo.bind()
        self.ibo.bind()
        self.vbo.allocate(self.vertices.nbytes)
        self.ibo.allocate(self.indices.nbytes)
        self.vbo.write(0, self.vertices.tobytes(), self.vertices.nbytes)        
        self.ibo.write(0, self.indices.tobytes(), self.indices.nbytes)
        posAttribLoc = self.program.attributeLocation("aPos")
        self.program.setAttributeBuffer(posAttribLoc, gl.GL_FLOAT, 0, 4, 0)
        self.program.enableAttributeArray(posAttribLoc) 
        self.vbo.release()
        self.vao.release()
    
    def paintGL(self):
        gl = self.context().versionFunctions() 
        gl.glClearColor(0.33,0.33,0.33, 1.0)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
        self.vao.bind()
        self.program.bind()

        gl.glDrawElements(gl.GL_TRIANGLES, len(self.indices), gl.GL_UNSIGNED_SHORT, None)
        self.frame_count += 1
    
    def resizeGL(self, width, height):
        gl.glViewport(0, 0, width, height)
    
    def __del__(self):
        self.vao.destroy()
        self.vbo.destroy()
        self.ibo.destroy()        
        self.program.removeAllShaders()
        pass

if __name__ == '__main__':
    app = QApplication(sys.argv)
    widget = OpenGLWidget()
    window = QMainWindow()    
    window.setCentralWidget(widget)
    window.setGeometry(0,0,640,480)
    window.show()
    sys.exit(app.exec_())

一切顺利,我可以按预期渲染。但是 python 抱怨:

in __del__
RuntimeError: wrapped C/C++ object of type QOpenGLVertexArrayObject has been deleted

当我关闭窗口时。猜想缓冲区被释放了两次,所以我将析构函数更改为

    def __del__(self):
        pass

口译员抱怨

QOpenGLVertexArrayObject::destroy() failed to restore current context

关闭后。我认为释放一定有问题,谁能想出释放这些缓冲区的正确方法?

python python-3.x opengl pyqt5 pyopengl
1个回答
0
投票

不建议依赖 del() 方法在 Python 中进行资源管理,因为它可能无法以可预测的方式调用或根本无法调用。相反,您应该使用 PyQt5 提供的 QObject 层次结构显式管理 OpenGL 资源的生命周期。

以下是如何修改代码以使用 QObject 层次结构来管理 OpenGL 资源的生命周期:

class OpenGLWidget(QOpenGLWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.frame_count = 0
        self.vao = None
        self.vbo = None
        self.ibo = None
        self.program = None

    def initializeGL(self):
        self.program = QOpenGLShaderProgram()
        self.program.addShaderFromSourceCode(QOpenGLShader.Vertex, """
            attribute highp vec4 aPos;
            void main() {
                gl_Position = aPos;
            }
        """)
        self.program.addShaderFromSourceCode(QOpenGLShader.Fragment, """
            void main() {
                gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
            }
        """)

        self.program.link()
        self.program.bind()

        self.vertices = np.array([
            [-0.5, -0.5, 0.0, 1.0],
            [0.0, -0.5, 0.0, 1.0],
            [-0.25, 0.0, 0.0, 1.0],
            [-0.5, 0.5, 0.0, 1.0],
            [0.0, 0.5, 0.0, 1.0],
        ], dtype=np.float32)

        self.indices = np.array([
            0,1,2,2,3,4
        ], dtype=np.uint16)
        
        self.vao = QOpenGLVertexArrayObject(self)
        self.vbo = QOpenGLBuffer(QOpenGLBuffer.VertexBuffer, self)
        self.ibo = QOpenGLBuffer(QOpenGLBuffer.IndexBuffer, self)
        
        self.vao.create()
        self.vbo.create()
        self.ibo.create()

        self.vao.bind()        
        self.vbo.bind()
        self.ibo.bind()

        self.vbo.allocate(self.vertices.nbytes)
        self.ibo.allocate(self.indices.nbytes)

        self.vbo.write(0, self.vertices.tobytes(), self.vertices.nbytes)        
        self.ibo.write(0, self.indices.tobytes(), self.indices.nbytes)

        posAttribLoc = self.program.attributeLocation("aPos")
        self.program.setAttributeBuffer(posAttribLoc, gl.GL_FLOAT, 0, 4, 0)
        self.program.enableAttributeArray(posAttribLoc) 

        self.vbo.release()
        self.vao.release()
    
    def paintGL(self):
        gl = self.context().versionFunctions() 
        gl.glClearColor(0.33,0.33,0.33, 1.0)
        gl.glClear(gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

        self.vao.bind()
        self.program.bind()

        gl.glDrawElements(gl.GL_TRIANGLES, len(self.indices), gl.GL_UNSIGNED_SHORT, None)
        self.frame_count += 1
    
    def resizeGL(self, width, height):
        gl.glViewport(0, 0, width, height)
    
    def cleanup(self):
        self.makeCurrent()
        self.vao.destroy()
        self.vbo.destroy()
        self.ibo.destroy()        
        self.program.removeAllShaders()

    def __del__(self):
        self
© www.soinside.com 2019 - 2024. All rights reserved.