Изменение данных объекта буфера вершин OpenGL через pyopengl OpenGL.arrays.vbo не имеет никакого эффекта - PullRequest
1 голос
/ 09 апреля 2020

Я застрял, пытаясь изменить данные в VBO.

Я установил сцену с двумя примитивами треугольника, используя VBO через вспомогательный класс python OpenGL.arrays.vbo. Это сработало.

Затем я хочу изменить данные (в приведенном ниже минимальном примере просто сдвинуть одну вершину при нажатии кнопки), которую я не могу заставить работать. Я не уверен, правильно ли я использую VBO или есть какая-то тривиальность, блокирующая перерисовку на стороне PyQt5.

Ниже приведен полный минимальный пример, важные вещи играют роль в функциях-членах initializeGL paintGL и shift.

Внутри GLWidget.shift Я испробовал разные подходы, следуя документам, и этот ответ безуспешно. Любая помощь приветствуется.

#!/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_())

Код работает на Ubuntu 18.04 машине под python 3.6 с

  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

1 Ответ

2 голосов
/ 09 апреля 2020

Списки сообщений (glGenList) устарели. В списке вы пытаетесь закодировать спецификацию вершин .
. Вместо этого я рекомендую использовать объект массива вершин .

Создайте VAO, прежде чем указывать массив обобщенных c данных атрибута вершины:

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)

Примечание, список отображения не работает, поскольку некоторые команды не компилируются в список отображения, а выполняются немедленно, включая glVertexPointer и glColorPointer. См glNewList.

...