通过 pyopengl OpenGL.arrays.vbo 更改 OpenGL 顶点缓冲区对象数据无效

Changing OpenGL Vertex Buffer Object data via pyopengl OpenGL.arrays.vbo has no effect

我无法更改 VBO 中的数据。

我通过 python OpenGL.arrays.vbo 助手 class 使用 VBO 使用 2 个三角形图元设置了一个场景。成功了。

然后我想更改我无法使用的数据(在下面的最小示例中,只需在单击按钮时移动一个顶点)。我不确定我是否错误地使用了 VBO,或者是否有一些琐碎的事情阻止了 PyQt5 端的重绘。

下面是完整的最小示例,重要的东西在成员函数 initializeGLpaintGLshift.

中发挥作用

Inside GLWidget.shift 我按照文档尝试了不同的方法,但 this answer 没有成功。感谢任何帮助。

#!/usr/bin/env python

import ctypes
import sys
import numpy as np
import OpenGL.arrays.vbo as glvbo

from PyQt5.QtCore import QSize
from PyQt5.QtWidgets import (QApplication, QHBoxLayout, QOpenGLWidget,
                             QWidget, QPushButton)

import OpenGL.GL as gl

class Window(QWidget):

    def __init__(self):
        super(Window, self).__init__()

        self.glWidget = GLWidget()
        button = QPushButton('shift', self)
        button.clicked.connect(self.glWidget.shift)

        layout = QHBoxLayout()
        layout.addWidget(self.glWidget)
        layout.addWidget(button)

        self.setLayout(layout)

class GLWidget(QOpenGLWidget):

    def __init__(self, parent=None):
        super().__init__(parent)
        self.object = None

    def minimumSizeHint(self):
        return QSize(400, 400)

    def initializeGL(self):
        gl.glClearColor(0., 0., 0., 0.)

        # a red and a green triangle
        self.vertices = np.array([
            # <- x,y,z ----->  <- r,g,b -->
            -0.5, -0.2, 0.0, 1.0, 0.0, 0.0,
             0.5, -0.5, 0.0, 1.0, 0.0, 0.0,
             0.5, 0.5,  0.0, 1.0, 0.0, 0.0,
             0.4, -0.2, 0.0, 0.0, 1.0, 0.0,
             1.4, -0.5, 0.0, 0.0, 1.0, 0.0,
             1.4, 0.5,  0.0, 0.0, 1.0, 0.0,
        ], 'f')

        self.vbo = glvbo.VBO(self.vertices)
        self.vbo.bind()

        self.object = gl.glGenLists(1)

        gl.glNewList(self.object, gl.GL_COMPILE)

        gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
        gl.glEnableClientState(gl.GL_COLOR_ARRAY)

        buffer_offset = ctypes.c_void_p
        stride = (3+3)*self.vertices.itemsize

        gl.glVertexPointer(3, gl.GL_FLOAT, stride, None)
        gl.glColorPointer(3, gl.GL_FLOAT, stride, buffer_offset(12))

        gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6)
        gl.glDisableClientState(gl.GL_VERTEX_ARRAY)
        gl.glDisableClientState(gl.GL_COLOR_ARRAY)

        gl.glEndList()
        gl.glShadeModel(gl.GL_FLAT)

    def paintGL(self):
        gl.glClear(
            gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)
        gl.glLoadIdentity()
        gl.glRotated(50.0, 0.0, 1.0, 0.0)
        gl.glCallList(self.object)

    def resizeGL(self, width, height):
        side = min(width, height)
        if side < 0:
            return

        gl.glViewport((width - side) // 2, (height - side) // 2, side,
                           side)

        gl.glMatrixMode(gl.GL_PROJECTION)
        gl.glLoadIdentity()
        gl.glOrtho(-1., +1., -1., +1., -100.0, 100.0)
        gl.glMatrixMode(gl.GL_MODELVIEW)

    def shift(self):
        # shift y-position of one vertex
        self.vertices[1] += 10.3
        assert self.vertices is self.vbo.data

        # version 1
        # self.vbo.implementation.glBufferSubData(self.vbo.target, 0, self.vbo.data)

        # version 2
        # self.vbo[:] = self.vertices[:]
        # self.vbo.bind()
        # self.vbo.copy_data()

        # version 2b (use slice)
        # self.vbo[1:2] = self.vertices[1:2]
        # self.vbo.bind()
        # self.vbo.copy_data()

        # version 3
        self.vbo.set_array(self.vertices)
        self.vbo.bind()
        self.vbo.copy_data()

        self.update()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())

代码在 python 3.6 下的 Ubuntu 18.04 机器上运行

  Vendor: Intel Open Source Technology Center
  Renderer: Mesa DRI Intel(R) HD Graphics 5500 (Broadwell GT2)
  OpenGL Version: 3.0 Mesa 19.2.8
  Shader Version: 1.30

Sisplay 列表 (glGenList) are deprecated. What you try to encode in the list is the Vertex Specification.
我建议改用 Vertex Array Object

在指定通用顶点属性数据数组之前创建 VAO:

class GLWidget(QOpenGLWidget):
    # [...]

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

        self.vbo = glvbo.VBO(self.vertices)
        self.vbo.bind()

        self.vao = gl.glGenVertexArrays(1)
        gl.glBindVertexArray(self.vao)

        gl.glEnableClientState(gl.GL_VERTEX_ARRAY)
        gl.glEnableClientState(gl.GL_COLOR_ARRAY)

        buffer_offset = ctypes.c_void_p
        stride = (3+3)*self.vertices.itemsize
        gl.glVertexPointer(3, gl.GL_FLOAT, stride, None)
        gl.glColorPointer(3, gl.GL_FLOAT, stride, buffer_offset(12))

        gl.glBindVertexArray(0)

当你要绘制对象时,绑定VAO即可:

class GLWidget(QOpenGLWidget):
    # [...]

    def paintGL(self):
        gl.glClear(
            gl.GL_COLOR_BUFFER_BIT | gl.GL_DEPTH_BUFFER_BIT)

        gl.glLoadIdentity()
        gl.glRotated(50.0, 0.0, 1.0, 0.0)

        gl.glBindVertexArray(self.vao)
        gl.glDrawArrays(gl.GL_TRIANGLES, 0, 6)
        gl.glBindVertexArray(0)

注意,显示列表不起作用,因为某些命令没有编译到显示列表中而是立即执行,包括glVertexPointerglColorPointer。参见 glNewList