[Python] How to use PySide6 QOpenGLWidget with OpenGL4

Discussão em 'Python' iniciado por Stack, Maio 30, 2025.

  1. Stack

    Stack Membro Participativo

    Let's assume I've got a minimal example of an QOpenGLWidget:

    import os.path
    from logging import getLogger

    import numpy as np
    from OpenGL import GL
    from PySide6.QtCore import Signal
    from PySide6.QtOpenGL import QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram, QOpenGLVertexArrayObject
    from PySide6.QtOpenGLWidgets import QOpenGLWidget
    from PySide6.QtWidgets import QWidget

    logger = getLogger(__file__)

    class TColorPickerWidget(QOpenGLWidget):
    def __init__(self, parent: QWidget | None):
    super().__init__(parent)
    self._gl_program: QOpenGLShaderProgram = QOpenGLShaderProgram()
    self._gl_vbo_color_quad = QOpenGLBuffer()
    self.setMinimumHeight(600)
    self.setMinimumWidth(800)

    def initializeGL(self):
    self.setBackgroundColor(5, 5, 5, 255)
    f = self.context().functions()
    f.initializeOpenGLFunctions()
    f.glClearColor(0.0, 0.0, 0.50, 1)
    # f.glEnable(GL.GL_DEPTH_TEST)
    f.glDisable(GL.GL_DEPTH_TEST)
    f.glEnable(GL.GL_LIGHT0)
    f.glEnable(GL.GL_LIGHTING)
    # GL_COLOR_MATERIAL missing
    self._compile_shaders()
    self._allocate_quad()

    def _allocate_quad(self):
    self._gl_vbo_color_quad.create()
    self._gl_vbo_color_quad.bind()
    cords = np.array([
    0, 1, # top left # 0 ~= -1
    1, 1, # top right
    0, 0, # bottom left
    0, 1, # top left
    1, 0, # bottom right
    0, 0 # bottom left
    ], dtype=np.float32)
    self._gl_vbo_color_quad.allocate(cords.nbytes)
    self._gl_vbo_color_quad.write(0, cords.data, cords.nbytes)
    self._gl_vbo_color_quad.release()

    def _compile_shaders(self):
    self._gl_program.create()
    shader_source = os.path.dirname(__file__) + "/test_frag_shader.glsl"
    self._frag_shader = QOpenGLShader(QOpenGLShader.ShaderTypeBit.Fragment)
    if not self._frag_shader.compileSourceFile(shader_source):
    logger.error("Failed to compile fragment shader.\nSource file: %s\nLog: %s\n",
    self._frag_shader.log(), shader_source)
    else:
    logger.debug("Successfully compiled fragment shader from %s.", shader_source)

    self._vert_shader = QOpenGLShader(QOpenGLShader.ShaderTypeBit.Vertex)
    shader_source = os.path.dirname(__file__) + "/test_vert_shader.glsl"
    if not self._vert_shader.compileSourceFile(shader_source):
    logger.error("Failed to compile vertex shader.\nSource File: %s\nLog: %s\n",
    self._vert_shader.log(), shader_source)
    else:
    logger.debug("Successfully compiled vertex shader from %s.", shader_source)

    self._gl_program.bind()
    self._gl_program.addShader(self._frag_shader)
    self._gl_program.addShader(self._vert_shader)
    self._gl_program.bindAttributeLocation("position", 0)
    if not self._gl_program.link():
    raise RuntimeError("Failed to link shaders. Log={}".format(self._gl_program.log()))
    else:
    logger.debug("Successfully linked test GL program")
    self._gl_program.release()

    def paintGL(self):
    f = self.context().functions()
    f.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
    self._gl_program.bind()
    self._gl_vbo_color_quad.bind()
    print("Previous Error:", f.glGetError())
    print(self._gl_vbo_color_quad.size() / (3 * 2 * 4))
    trig_count = 2
    f.glDrawArrays(GL.GL_TRIANGLES, 0, trig_count)
    print("Draw Error:", f.glGetError())
    self._gl_vbo_color_quad.release()
    self._gl_program.release()



    With the associated shaders:

    #version 410 core

    layout(location = 0) in vec2 position;

    void main() {
    gl_Position = vec4(position.xy, 0.0, 1.0);
    }


    #version 410 core

    layout(location = 0) out vec4 fragColor;

    void main() {
    fragColor = vec4(1.0, 0.0, 0.0, 1.0);
    }


    In theory this code should draw a red rectangle over the blue clear color. In fact, having this code implemented in C (without Qt) works fine. This example however does not work as the glDrawArrays call fails with GL_INVALID_OPERATION. Typically, this means that I forgot to bind the buffer but that's happening 2 lines above the function call.

    I also tried using glVertexAttribPointer(0, 2, GL.GL_FLOAT, GL.GL_FALSE, 0, 0) prior to the draw call but that did not work either.

    I'd welcome any hint by now...

    Continue reading...

Compartilhe esta Página