问题描述
我在 Qt 5.15.x Qt 小部件中渲染了多个 Pyvista 3d 可视化。这是使用 QtInteractor (https://github.com/pyvista/pyvistaqt) 完成的。现在,我正在从 Qt 小部件转向 Qt QML。
我的想法是从 PyVista 中获取渲染器并在 QML QQuickFrameBufferObject 中获取它。基于来自
的知识- QQuickFrameBufferObject causes crash in PySide2
- https://github.com/nicanor-romero/QtVtk/blob/master/src/QVTKFramebufferObjectRenderer.cpp
我写了以下 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 (将#修改为@)