Pyside6 does not render QOpenGLWidget window when using keypress and updating array using glBufferSubData
Unsolved
Qt for Python
-
I have been studying on how to draw OpenGL context, but I came across problem while updating the screen. Keypress invokes a rotation, but for some reason the window won't update the current render after using glBufferSubData. It should do this after invoking update() . Am I using keypressevent incorrectly or is the problem somewhere else. Python version 3.10
from GLWidget import GLWidget from PySide6.QtWidgets import QApplication, QMainWindow class Window(QMainWindow): def __init__(self): super().__init__() # set the title self.setWindowTitle("OpenGL Interface") # setting the geometry of window self.setGeometry(0, 0, 1024, 768) self.qlw = GLWidget() self.setCentralWidget(self.qlw) if __name__ == '__main__': app = QApplication([]) window = Window() window.show() app.exec()
import Shader from Math_3d import Vector3f from OpenGL.GL import * from PySide6.QtOpenGLWidgets import QOpenGLWidget from PySide6.QtCore import Qt class GLWidget(QOpenGLWidget): def __init__(self): super().__init__() # Vertex Buffer Object # Create point vertex data self.v3f = Vector3f([[0.5, 0.5, 0.0], [-0.5, -0.5, 0.0], [0.5, -0.5, 0.0], [-0.5, 0.5, 0.0]]) self.setFocusPolicy(Qt.FocusPolicy.StrongFocus) def initializeGL(self): program = glCreateProgram() buffer = glGenBuffers(1) # Request program and shader slots from the GPU vertex = glCreateShader(GL_VERTEX_SHADER) fragment = glCreateShader(GL_FRAGMENT_SHADER) # Set shader sources glShaderSource(vertex, Shader.vertex_code) glShaderSource(fragment, Shader.fragment_code) # Compile shaders and check that they have compiled glCompileShader(vertex) glCompileShader(fragment) if not glGetShaderiv(vertex, GL_COMPILE_STATUS): report_shader = glGetShaderInfoLog(vertex) print(report_shader) raise RuntimeError("Vertex shader compilation error") if not glGetShaderiv(fragment, GL_COMPILE_STATUS): report_frag = glGetShaderInfoLog(fragment) print(report_frag) raise RuntimeError("Fragment shader compilation error") # Link shaders to program glAttachShader(program, vertex) glAttachShader(program, fragment) glLinkProgram(program) if not glGetProgramiv(program, GL_LINK_STATUS): print(glGetProgramInfoLog(program)) raise RuntimeError('Linking error') # Get rid of shaders glDetachShader(program, vertex) glDetachShader(program, fragment) # Make default program to run glUseProgram(program) # Make this buffer the default one glBindBuffer(GL_ARRAY_BUFFER, buffer) # Vertex Array Buffer vao = glGenVertexArrays(1) glBindVertexArray(vao) strides = int(self.v3f.buffdata.nbytes/self.v3f.buffdata.itemsize) loc = glGetAttribLocation(program, 'position') glEnableVertexAttribArray(loc) glVertexAttribPointer(loc, 3, GL_FLOAT, False, strides, None) glBufferData(GL_ARRAY_BUFFER, self.v3f.buffdata.nbytes, self.v3f.buffdata, GL_DYNAMIC_DRAW) def paintGL(self): print(glGetError()) glClear(GL_COLOR_BUFFER_BIT) glPointSize(20) glDrawArrays(GL_POINTS, 0, self.v3f.buffdata.itemsize) def keyPressEvent(self, e): if e.key() == Qt.Key.Key_Left: self.v3f.Rotate(-0.1) elif e.key() == Qt.Key.Key_Right: self.v3f.Rotate(0.1) elif e.key() == Qt.Key.Key_Escape or Qt.Key.Key_Q: exit() self.update()
vertex_code = """ attribute vec3 position; void main() { gl_Position = vec4(position, 1.0); } """ fragment_code = """ void main() { gl_FragColor = vec4(0.5, 0.5, 0.5, 1.0); } """
Math_3d.py
from OpenGL.GL import * import numpy as np np.set_printoptions(precision=3, suppress=True) class Vector3f: def __init__(self, ndarray): self.data = np.array([ndarray], dtype=np.float32) # Convert n-dimension arrays to one long array self.buffdata = self.data.ravel() self.orig = self.data self.__rval = 0.0 self.__sval = 0.0 def Rotate(self, val): # Rotation Matrix self.__rval += val # Create a memory value and add to that value m1 = np.asmatrix(self.data) # Convert n-dimension array to matrix rot2 = np.matrix([[np.cos(self.__rval), np.sin(-self.__rval), 0.0], # Create rotation matrix [np.sin(self.__rval), np.cos(self.__rval), 0.0], [0.0, 0.0, 0.0]], dtype=np.float32) rotator = m1 * rot2 # Matrix multiplication self.buffdata = rotator.ravel() # Convert result to array to be used on GPU buffer glBufferSubData(GL_ARRAY_BUFFER, 0, self.buffdata.data.nbytes, self.buffdata.data) print(glGetError())
-
Hi and welcome to devnet,
If memory serves well, you should ensure that the context is current when calling OpenGL methods outside the various xxxGL methods of QOpenGLWidget.
One possible alternative is to use a dirty flag and you call glBufferSubData the next time paintGL is called.