无法让 Pyvista 渲染与 Qt QML QQuickFramebufferObject

问题描述

我在 Qt 5.15.x Qt 小部件中渲染了多个 Pyvista 3d 可视化。这是使用 QtInteractor (https://github.com/pyvista/pyvistaqt) 完成的。现在,我正在从 Qt 小部件转向 Qt QML。

我的想法是从 PyVista 中获取渲染器并在 QML QQuickFrameBufferObject 中获取它。基于来自

的知识

我写了以下 python3 代码文件: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)
        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,"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_())

文件: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!")
        }
}

由于 PyVista 的渲染器已经有一个 Sphere 3d 对象,我的期望是,它在 QML 的帧缓冲对象中渲染,并且在 QML 窗口中可见。但是,我错了。没有崩溃,但我也没有在 QML 窗口中看到 Sphere 3d 对象。

QML QSG_VISUALIZE 调试显示创建了一个 FBO 对象,但无法让 PyVista 的渲染器与 QML 帧缓冲区一起工作。

输出qml_fbo_pyvista.py UI output qml_fbo_pyvista.py consoleoutput

环境:

                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

我错过了什么?

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...