Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Изменение данных OpenGL Vertex Buffer Object через pyopengl OpenGL.arrays.vbo не имеет никакого эффекта

Автор вопроса: flonkОтветов: 1

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

Я настроил сцену с двумя примитивами Triangle, используя 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

pythonpyqt5pyqtopenglpyopengl

Ответы

Ответ 1 · рейтинг 2 · Rabbid76

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

Создайте 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)

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

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы