Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. Can not get Pyvista render to work with Qt QML QQuickFramebufferObject
Forum Updated to NodeBB v4.3 + New Features

Can not get Pyvista render to work with Qt QML QQuickFramebufferObject

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
1 Posts 1 Posters 355 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.
  • B Offline
    B Offline
    Bakkiaraj
    wrote on last edited by
    #1

    I have multiple Pyvista 3d visualizations render in the Qt 5.15.x Qt Widgets. This was done using QtInteractor (https://github.com/pyvista/pyvistaqt). Now, I am moving away from Qt widgets to Qt QML.

    My idea is to get the renderer from PyVista and get it render in QML QQuickFrameBufferObject. Based on knowledge from

    • https://stackoverflow.com/questions/61950058/qquickframebufferobject-causes-crash-in-pyside2
    • https://github.com/nicanor-romero/QtVtk/blob/master/src/QVTKFramebufferObjectRenderer.cpp

    I wrote a following Python3 code.
    File: qml_fbo_pyvista.py

    from __future__ import annotations
    
    import os
    import sys
    
    import pyvista as pv
    from PySide2.QtCore import QSize
    from PySide2.QtGui import QOpenGLFramebufferObject, QOpenGLFramebufferObjectFormat, QOpenGLFunctions
    from PySide2.QtQml import QQmlApplicationEngine, qmlRegisterType
    from PySide2.QtQuick import QQuickWindow, QQuickFramebufferObject
    from PySide2.QtWidgets import QApplication
    # https://doc.qt.io/qt-5/qquickframebufferobject-renderer.html
    from pyvista import PolyData, BasePlotter
    from vtkmodules.vtkInteractionStyle import vtkInteractorStyleTrackballCamera
    from vtkmodules.vtkRenderingCore import vtkRenderWindowInteractor, vtkRenderer
    from vtkmodules.vtkRenderingExternal import vtkExternalOpenGLRenderWindow
    from vtkmodules.vtkRenderingOpenGL2 import vtkOpenGLActor
    from vtkmodules.vtkRenderingUI import vtkGenericRenderWindowInteractor
    
    
    class PyvistaFBORenderer(QQuickFramebufferObject.Renderer, BasePlotter):
        _fbo: QOpenGLFramebufferObject
        _m_fboItem: QQuickFramebufferObject
    
        def __init__(self) -> None:
            super().__init__()
            print("* init renderer")
    
            # surfaceFormat: QSurfaceFormat = QSurfaceFormat()
            # surfaceFormat.setRenderableType(QSurfaceFormat.OpenGL)
            # # surfaceFormat.setVersion(3, 2)
            # # surfaceFormat.setProfile(QSurfaceFormat.CoreProfile)
            # # surfaceFormat.setSwapBehavior(QSurfaceFormat.DoubleBuffer)
            # # surfaceFormat.setRedBufferSize(8)
            # # surfaceFormat.setGreenBufferSize(8)
            # # surfaceFormat.setBlueBufferSize(8)
            # # surfaceFormat.setDepthBufferSize(24)
            # # surfaceFormat.setStencilBufferSize(8)
            # # surfaceFormat.setAlphaBufferSize(0)
            # # surfaceFormat.setStereo(False)
            # QSurfaceFormat.setDefaultFormat(surfaceFormat)
    
            self.plotter = pv.Plotter(off_screen=True,
                                      polygon_smoothing=True,
                                      line_smoothing=True,
                                      point_smoothing=True)
    
            self.geom: PolyData = pv.Sphere()
            self.m_actor: vtkOpenGLActor = self.plotter.add_mesh(self.geom)
            self.m_renderer: vtkRenderer = self.plotter.renderer
    
            self.m_interactor: vtkRenderWindowInteractor = vtkGenericRenderWindowInteractor()
            self.m_renderWindow: vtkExternalOpenGLRenderWindow = vtkExternalOpenGLRenderWindow()
    
            self.m_renderWindow.SetInteractor(self.m_interactor)
    
            self.m_renderer.SetBackground(0,0,0)
            self.m_renderWindow.AddRenderer(self.m_renderer)
    
            interactor_style = vtkInteractorStyleTrackballCamera()
            self.m_interactor.SetInteractorStyle(interactor_style)
    
            self.m_interactor.Initialize()
    
            self.update()
    
    
        def createFramebufferObject(self, size: QSize) -> QOpenGLFramebufferObject:
            print("* createFramebufferObject called")
            fmt = QOpenGLFramebufferObjectFormat()
            fmt.setAttachment(QOpenGLFramebufferObject.Depth)
            self._fbo = QOpenGLFramebufferObject(size, fmt)
    
            self.m_renderWindow.SetBackLeftBuffer(0x8CE0)
            self.m_renderWindow.SetFrontLeftBuffer(0x8CE0)
    
            self.m_renderWindow.SetSize(size.width(), size.height())
            self.m_renderWindow.SetOffScreenRendering(True)
            self.m_renderWindow.Modified()
    
            return self._fbo
    
        def synchronize(self, item: QQuickFramebufferObject) -> None:
            print("* Sync")
            self._m_fboItem = item
            globj = QOpenGLFunctions()
            globj.initializeOpenGLFunctions()
    
            size = (item.size() * item.window().devicePixelRatio()).toSize()
            self.m_renderWindow.SetSize(size.width(), size.height())
    
        def render(self) -> None:
            print(" * Rendering")
            self.m_renderWindow.PushState()
            self.m_renderWindow.OpenGLInitState()
            self.m_renderWindow.MakeCurrent()
    
            globj = QOpenGLFunctions()
            globj.initializeOpenGLFunctions()
            globj.glEnable(0x809D)
            globj.glUseProgram(0)
    
            self.m_renderWindow.Start()
    
            self.m_renderWindow.Render()
            self.m_renderWindow.PopState()
            self._m_fboItem.window().resetOpenGLState()
    
    
    
    # https://doc.qt.io/qt-5/qquickframebufferobject.html
    class QMLPyvistaOpenGLItem(QQuickFramebufferObject):
        __renderer_obj: PyvistaFBORenderer
    
        def __init__(self) -> None:
            super().__init__()
            print("* created new PyvistaFBORenderer")
    
        def createRenderer(self) -> QQuickFramebufferObject.Renderer:
            self.__renderer_obj = PyvistaFBORenderer()
            print("* return PyvistaFBORenderer")
            return self.__renderer_obj
    
    
    if __name__ == '__main__':
    
        os.environ['QSG_VISUALIZE'] = 'overdraw'
    
    
        app = QApplication(sys.argv)
    
        qmlRegisterType(QMLPyvistaOpenGLItem, "QMLPyvistaOpenGLItem", 1, 0, "QMLPyvistaOpenGLItem")
    
        engine = QQmlApplicationEngine()
    
        engine.load("./qml_view/pyvista3d_view.qml")
        if not engine.rootObjects():
            print("ERROR loading pyvista3d_view.qml")
            sys.exit(-1)
    
        mainWin: QQuickWindow = engine.rootObjects()[0]
        mainWin.show()
        sys.exit(app.exec_())
    
    

    File: qml_view/pyvista3d_view.qml

    import QtQuick 2.12
    import QtQuick.Window 2.12
    import QtQuick.Controls 2.13
    import QtQuick.Layouts 1.12
    import QtQuick.Controls.Material 2.12
    import QMLPyvistaOpenGLItem 1.0
    
    ApplicationWindow {
        id: mainapp
        width: 800
        height: 600
        title: "Hello Pyvista!!"
        visible: true
        color: "#2e03eb"
        Material.theme: Material.Dark
        Material.accent: Material.Indigo
    
        Button{
            text: "Hello"
            width: 100
            height: 100
        }
    
        QMLPyvistaOpenGLItem{
                anchors.fill: parent
                visible: true
                Component.onCompleted: console.log(" *********** Completed QMLPyvistaOpenGLItem!")
            }
    }
    
    

    Since PyVista's renderer already have a Sphere 3d object, My expectation is that, It gets render in the QML's framebuffer object and will be visible in the QML window. But, I am wrong. There is no crash but I also do not see Sphere 3d object in the QML window.

    QML QSG_VISUALIZE debugging shows there is a FBO object is created but could not get PyVista's renderer to work with QML framebuffer.

    Output:
    qml_fbo_pyvista.py UI output
    qml_fbo_pyvista.py consoleoutput

    Environment:

                    OS : Windows
                CPU(s) : 12
               Machine : AMD64
          Architecture : 64bit
           Environment : Python
            GPU Vendor : Intel
          GPU Renderer : Intel(R) UHD Graphics
           GPU Version : 4.5.0 - Build 27.20.100.8681
    
      Python 3.9.5 (tags/v3.9.5:0a7dcbd, May  3 2021, 17:27:52) [MSC v.1928 64 bit
      (AMD64)]
    
               pyvista : 0.31.1
                   vtk : 9.0.20210612
                 numpy : 1.21.0
               imageio : 2.9.0
               appdirs : 1.4.4
                scooby : 0.5.7
                meshio : 4.4.6
            matplotlib : 3.4.2
             pyvistaqt : 0.5.0
               IPython : 7.25.0
                 scipy : 1.7.0
               Pyvista2 : 5.15.4
    
                Qt:  5.15.4
    
    

    What am I missing?

    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