Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. PySide6, OpenGL, Context Info Example but separate classes for objects
QtWS25 Last Chance

PySide6, OpenGL, Context Info Example but separate classes for objects

Scheduled Pinned Locked Moved Unsolved Qt for Python
3 Posts 2 Posters 234 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • K Offline
    K Offline
    kamran78nasirizad
    wrote on last edited by
    #1

    I am currently undertaking a project to learn OpenGL and have encountered some challenges. My objective is to create a window utilizing PySide6 as the window manager, within which I aim to render various graphical objects. To facilitate this, I am developing a class for spheres, enabling me to instantiate multiple sphere objects.
    At present, I am working on a class for triangles to establish a foundational framework, with the intention of later extending it to spheres. However, I have encountered a segmentation fault and am uncertain of the source of the error or how to resolve it.
    I would greatly appreciate any guidance or assistance you could provide regarding this matter.

    Here is my current code, which has been modified from the "Context Info Example":

    import sys
    import numpy as np
    from PySide6.support import VoidPtr
    from PySide6.QtCore import QObject, QTimer, Qt, QRect
    from PySide6.QtWidgets import QApplication, QHBoxLayout, QWidget
    from PySide6.QtGui import QMatrix4x4, QOpenGLContext, QSurfaceFormat, QWindow
    from PySide6.QtOpenGL import QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram, QOpenGLVertexArrayObject
    from OpenGL import GL
    
    
    class Triangle(QObject):
        vertices = np.array([0, 0.707, -0.5, -0.5, 0.5, -0.5], dtype=np.float32)
        colors = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1], dtype=np.float32)
    
        def __init__(self):
            super().__init__()
            self.angle = 0
            self.shader_program = QOpenGLShaderProgram(self)
            if not self.shader_program.addShaderFromSourceFile(
                QOpenGLShader.ShaderTypeBit.Vertex, "shaders/vertex.shader"
            ):
                raise Exception(f"Vertex shader could not be added: {self.shader_program.log()}")
            if not self.shader_program.addShaderFromSourceFile(
                QOpenGLShader.ShaderTypeBit.Fragment, "shaders/fragment.shader"
            ):
                raise Exception(f"Fragment shader could not be added: {self.shader_program.log()}")
            if not self.shader_program.link():
                log = self.shader_program.log()
                raise Exception(f"Could not link shaders: {log}")
            self._pos_attr = self.shader_program.attributeLocation("posAttr")
            self._col_attr = self.shader_program.attributeLocation("colAttr")
            self._matrix_uniform = self.shader_program.uniformLocation("matrix")
            self.vbo = QOpenGLBuffer()
            self.vbo.create()
            self.vbo.bind()
            self._vertices_data = self.vertices.tobytes()
            self._colors_data = self.colors.tobytes()
            vertices_size = 4 * self.vertices.size
            colors_size = 4 * self.colors.size
            self.vbo.allocate(VoidPtr(self._vertices_data), vertices_size + colors_size)
            self.vbo.write(vertices_size, VoidPtr(self._colors_data), colors_size)
            self.vbo.release()
    
        def setup_vertex_attribs(self):
            self.vbo.bind()
            self.shader_program.setAttributeBuffer(self._pos_attr, GL.GL_FLOAT, 0, 2)
            self.shader_program.setAttributeBuffer(
                self._col_attr, GL.GL_FLOAT, 4 * self.vertices.size, 3
            )
            self.shader_program.enableAttributeArray(self._pos_attr)
            self.shader_program.enableAttributeArray(self._col_attr)
            self.vbo.release()
    
        def render(self, context_functions):
            self.shader_program.bind()
            matrix = QMatrix4x4()
            matrix.perspective(60, 4 / 3, 0.1, 100)
            matrix.translate(0, 0, -2)
            matrix.rotate(self.angle, 0, 1, 0)
            self.shader_program.setUniformValue(self._matrix_uniform, matrix)
            context_functions.glDrawArrays(GL.GL_TRIANGLES, 0, 3)
    
    
    class RenderWindow(QWindow):
        def __init__(self, fmt):
            super().__init__()
            self.setSurfaceType(QWindow.SurfaceType.OpenGLSurface)
            self.setFormat(fmt)
            self.context = QOpenGLContext(self)
            self.context.setFormat(self.requestedFormat())
            if not self.context.create():
                raise Exception("Unable to create GL context")
            self.timer = QTimer(self)
            self.timer.timeout.connect(self.render)
            self.context_functions = self.context.functions()
            self.vao = QOpenGLVertexArrayObject()
    
        def init_gl(self):
            if not self.context.makeCurrent(self):
                raise Exception("makeCurrent() failed")
            self.context_functions.glEnable(GL.GL_DEPTH_TEST)
            self.context_functions.glClearColor(0, 0, 0, 1)
            self.triangle = Triangle()
            with QOpenGLVertexArrayObject.Binder(self.vao):
                if self.vao.isCreated():
                    self.triangle.setup_vertex_attribs()
    
        def render(self):
            if not self.context.makeCurrent(self):
                raise Exception("context.makeCurrent() failed!")
            context_functions = self.context.functions()
            retina_scale = self.devicePixelRatio()
            context_functions.glViewport(
                0, 0, self.width() * retina_scale, self.height() * retina_scale
            )
            context_functions.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
            if self.vao.isCreated():
                self.vao.bind()
            else:
                self.triangle.setup_vertex_attribs()
            self.triangle.render(self.context_functions)
            self.vao.release()
            self.context.swapBuffers(self)
            self.context.doneCurrent()
    
        def exposeEvent(self, event):
            if self.isExposed():
                self.init_gl()
                if not self.timer.isActive():
                    self.timer.start(10)
            else:
                if self.timer.isActive():
                    self.timer.stop()
    
    
    class MainWindow(QWidget):
        def __init__(
            self,
            area: QRect | None = None,
            title: str = "",
            parent: QWidget | None = None,
            flags: Qt.WindowType = Qt.WindowType.Window,
        ):
            super().__init__(parent, flags)
            h_box_layout = QHBoxLayout(self)
            h_box_layout.setContentsMargins(0, 0, 0, 0)
            self._render_window = RenderWindow(QSurfaceFormat())
            container = QWidget.createWindowContainer(self._render_window)
            h_box_layout.addWidget(container)
            self.setWindowTitle(title)
            self.setGeometry(area)
    
    
    if __name__ == "__main__":
        application = QApplication(sys.argv)
        main_window = MainWindow(QRect(0, 0, 1920, 1080), title="test")
        main_window.showFullScreen()
        sys.exit(application.exec())
    

    The vertex.shader file:

    #version 330 core
    
    in vec4 posAttr;
    in vec4 colAttr;
    out vec4 col;
    uniform mat4 matrix;
    
    void main()
    {
        col = colAttr;
        gl_Position = matrix * posAttr;
    };
    

    The fragment.shader file:

    #version 330 core
    
    in vec4 col;
    out vec4 pix_color;
    
    void main()
    {
        pix_color = col;
    };
    

    Thank you for your attention.
    Best regards

    jsulmJ 1 Reply Last reply
    0
    • K kamran78nasirizad

      I am currently undertaking a project to learn OpenGL and have encountered some challenges. My objective is to create a window utilizing PySide6 as the window manager, within which I aim to render various graphical objects. To facilitate this, I am developing a class for spheres, enabling me to instantiate multiple sphere objects.
      At present, I am working on a class for triangles to establish a foundational framework, with the intention of later extending it to spheres. However, I have encountered a segmentation fault and am uncertain of the source of the error or how to resolve it.
      I would greatly appreciate any guidance or assistance you could provide regarding this matter.

      Here is my current code, which has been modified from the "Context Info Example":

      import sys
      import numpy as np
      from PySide6.support import VoidPtr
      from PySide6.QtCore import QObject, QTimer, Qt, QRect
      from PySide6.QtWidgets import QApplication, QHBoxLayout, QWidget
      from PySide6.QtGui import QMatrix4x4, QOpenGLContext, QSurfaceFormat, QWindow
      from PySide6.QtOpenGL import QOpenGLBuffer, QOpenGLShader, QOpenGLShaderProgram, QOpenGLVertexArrayObject
      from OpenGL import GL
      
      
      class Triangle(QObject):
          vertices = np.array([0, 0.707, -0.5, -0.5, 0.5, -0.5], dtype=np.float32)
          colors = np.array([1, 0, 0, 0, 1, 0, 0, 0, 1], dtype=np.float32)
      
          def __init__(self):
              super().__init__()
              self.angle = 0
              self.shader_program = QOpenGLShaderProgram(self)
              if not self.shader_program.addShaderFromSourceFile(
                  QOpenGLShader.ShaderTypeBit.Vertex, "shaders/vertex.shader"
              ):
                  raise Exception(f"Vertex shader could not be added: {self.shader_program.log()}")
              if not self.shader_program.addShaderFromSourceFile(
                  QOpenGLShader.ShaderTypeBit.Fragment, "shaders/fragment.shader"
              ):
                  raise Exception(f"Fragment shader could not be added: {self.shader_program.log()}")
              if not self.shader_program.link():
                  log = self.shader_program.log()
                  raise Exception(f"Could not link shaders: {log}")
              self._pos_attr = self.shader_program.attributeLocation("posAttr")
              self._col_attr = self.shader_program.attributeLocation("colAttr")
              self._matrix_uniform = self.shader_program.uniformLocation("matrix")
              self.vbo = QOpenGLBuffer()
              self.vbo.create()
              self.vbo.bind()
              self._vertices_data = self.vertices.tobytes()
              self._colors_data = self.colors.tobytes()
              vertices_size = 4 * self.vertices.size
              colors_size = 4 * self.colors.size
              self.vbo.allocate(VoidPtr(self._vertices_data), vertices_size + colors_size)
              self.vbo.write(vertices_size, VoidPtr(self._colors_data), colors_size)
              self.vbo.release()
      
          def setup_vertex_attribs(self):
              self.vbo.bind()
              self.shader_program.setAttributeBuffer(self._pos_attr, GL.GL_FLOAT, 0, 2)
              self.shader_program.setAttributeBuffer(
                  self._col_attr, GL.GL_FLOAT, 4 * self.vertices.size, 3
              )
              self.shader_program.enableAttributeArray(self._pos_attr)
              self.shader_program.enableAttributeArray(self._col_attr)
              self.vbo.release()
      
          def render(self, context_functions):
              self.shader_program.bind()
              matrix = QMatrix4x4()
              matrix.perspective(60, 4 / 3, 0.1, 100)
              matrix.translate(0, 0, -2)
              matrix.rotate(self.angle, 0, 1, 0)
              self.shader_program.setUniformValue(self._matrix_uniform, matrix)
              context_functions.glDrawArrays(GL.GL_TRIANGLES, 0, 3)
      
      
      class RenderWindow(QWindow):
          def __init__(self, fmt):
              super().__init__()
              self.setSurfaceType(QWindow.SurfaceType.OpenGLSurface)
              self.setFormat(fmt)
              self.context = QOpenGLContext(self)
              self.context.setFormat(self.requestedFormat())
              if not self.context.create():
                  raise Exception("Unable to create GL context")
              self.timer = QTimer(self)
              self.timer.timeout.connect(self.render)
              self.context_functions = self.context.functions()
              self.vao = QOpenGLVertexArrayObject()
      
          def init_gl(self):
              if not self.context.makeCurrent(self):
                  raise Exception("makeCurrent() failed")
              self.context_functions.glEnable(GL.GL_DEPTH_TEST)
              self.context_functions.glClearColor(0, 0, 0, 1)
              self.triangle = Triangle()
              with QOpenGLVertexArrayObject.Binder(self.vao):
                  if self.vao.isCreated():
                      self.triangle.setup_vertex_attribs()
      
          def render(self):
              if not self.context.makeCurrent(self):
                  raise Exception("context.makeCurrent() failed!")
              context_functions = self.context.functions()
              retina_scale = self.devicePixelRatio()
              context_functions.glViewport(
                  0, 0, self.width() * retina_scale, self.height() * retina_scale
              )
              context_functions.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
              if self.vao.isCreated():
                  self.vao.bind()
              else:
                  self.triangle.setup_vertex_attribs()
              self.triangle.render(self.context_functions)
              self.vao.release()
              self.context.swapBuffers(self)
              self.context.doneCurrent()
      
          def exposeEvent(self, event):
              if self.isExposed():
                  self.init_gl()
                  if not self.timer.isActive():
                      self.timer.start(10)
              else:
                  if self.timer.isActive():
                      self.timer.stop()
      
      
      class MainWindow(QWidget):
          def __init__(
              self,
              area: QRect | None = None,
              title: str = "",
              parent: QWidget | None = None,
              flags: Qt.WindowType = Qt.WindowType.Window,
          ):
              super().__init__(parent, flags)
              h_box_layout = QHBoxLayout(self)
              h_box_layout.setContentsMargins(0, 0, 0, 0)
              self._render_window = RenderWindow(QSurfaceFormat())
              container = QWidget.createWindowContainer(self._render_window)
              h_box_layout.addWidget(container)
              self.setWindowTitle(title)
              self.setGeometry(area)
      
      
      if __name__ == "__main__":
          application = QApplication(sys.argv)
          main_window = MainWindow(QRect(0, 0, 1920, 1080), title="test")
          main_window.showFullScreen()
          sys.exit(application.exec())
      

      The vertex.shader file:

      #version 330 core
      
      in vec4 posAttr;
      in vec4 colAttr;
      out vec4 col;
      uniform mat4 matrix;
      
      void main()
      {
          col = colAttr;
          gl_Position = matrix * posAttr;
      };
      

      The fragment.shader file:

      #version 330 core
      
      in vec4 col;
      out vec4 pix_color;
      
      void main()
      {
          pix_color = col;
      };
      

      Thank you for your attention.
      Best regards

      jsulmJ Offline
      jsulmJ Offline
      jsulm
      Lifetime Qt Champion
      wrote on last edited by
      #2

      @kamran78nasirizad said in PySide6, OpenGL, Context Info Example but separate classes for objects:

      am uncertain of the source of the error

      Please run your app in debugger to see where that happens

      https://forum.qt.io/topic/113070/qt-code-of-conduct

      K 1 Reply Last reply
      0
      • jsulmJ jsulm

        @kamran78nasirizad said in PySide6, OpenGL, Context Info Example but separate classes for objects:

        am uncertain of the source of the error

        Please run your app in debugger to see where that happens

        K Offline
        K Offline
        kamran78nasirizad
        wrote on last edited by
        #3

        Please run your app in debugger to see where that happens

        Dear @jsulm,
        Thank you for your suggestion. I did execute the application using the debugger; however, it encountered an issue at the first line of the init_gl function, displaying a message indicating "disconnected unexpectedly." Unfortunately, no further information was provided.

        1 Reply Last reply
        0

        • Login

        • Login or register to search.
        • First post
          Last post
        0
        • Categories
        • Recent
        • Tags
        • Popular
        • Users
        • Groups
        • Search
        • Get Qt Extensions
        • Unsolved