接前面Qt与Python的绑定历史回顾与PySide6下Matplotlib小记,继续梳理一点点...
vtk 是什么
VTK(Visualization Toolkit) 是一个开源的跨平台库,用于 3D 计算机图形学、图像处理 和 科学数据可视化。它由 Kitware 开发和维护,支持从简单的 2D/3D 图形渲染到复杂的可视化算法应用。它支持多种格式文件:
格式 |
文件扩展名 |
用途 |
VTK 支持的类 |
特点 |
VTK |
*.vtk |
VTK 原生格式,用于网格和几何数据 |
vtkDataSetReader / vtkDataSetWriter |
支持结构化、非结构化网格及几何;ASCII 和二进制两种模式。 |
VTU |
*.vtu |
XML 格式的非结构化网格 |
vtkXMLUnstructuredGridReader / vtkXMLUnstructuredGridWriter |
XML 格式,支持大数据和并行处理。 |
STL |
*.stl |
表面几何模型,常用于 3D 打印 |
vtkSTLReader / vtkSTLWriter |
支持 ASCII 和二进制格式。 |
PLY |
*.ply |
多边形网格和点云 |
vtkPLYReader / vtkPLYWriter |
支持点、边、面以及附加属性(如颜色、法线)。 |
OBJ |
*.obj |
表面几何和纹理数据 |
vtkOBJReader / vtkOBJExporter |
可存储顶点、面、法线和纹理数据,与 MTL 文件结合支持材质。 |
3DS |
*.3ds |
3D Studio 模型 |
vtk3DSImporter |
早期的三维模型格式,支持材质和几何。 |
GLTF/GLB |
*.gltf , *.glb |
高效传输和渲染的现代格式 |
外部库支持(如 PyVista 或 vtk.js) |
支持几何、材质、纹理和动画;GLB 为二进制格式。 |
ExodusII |
*.exo |
有限元分析的科学数据 |
vtkExodusIIReader |
存储网格、模拟结果和元数据,常用于工程仿真。 |
XDMF |
*.xdmf |
高性能科学数据格式 |
vtkXdmfReader |
通常与 HDF5 结合使用,支持大规模并行处理。 |
NetCDF |
*.nc |
气象和海洋科学网格数据 |
vtkNetCDFReader |
存储多维数组数据,支持高效存储和访问。 |
Ensight |
*.case |
流体力学和有限元分析数据 |
vtkEnsightReader |
支持科学可视化,专为流体仿真设计。 |
HDF5 |
*.h5 |
高性能科学数据格式 |
vtkHDFReader |
支持多维数据,提供快速存储和访问。 |
ParaView State |
*.pvd , *.pvtu |
并行科学数据可视化 |
vtkPVDReader |
ParaView 支持的格式,适用于并行处理的网格数据。 |
LAS/LAZ |
*.las , *.laz |
激光雷达点云数据 |
外部工具转换后支持 |
存储点云数据,包含高度、颜色和反射强度等信息。 |
东西太多,找个最简单的例子,先看看python下如何使用,找找感觉
例子1:使用 vtk
传统方式,直接导入 vtk
模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31 | import vtk
cone = vtk.vtkConeSource()
cone.SetResolution(50)
# 创建一个 Mapper,将几何数据映射到图形
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(cone.GetOutputPort())
# 创建一个 Actor,表示绘制到屏幕上的对象
actor = vtk.vtkActor()
actor.SetMapper(mapper)
# 创建一个 Renderer,负责渲染场景
renderer = vtk.vtkRenderer()
renderer.SetBackground(0.1, 0.2, 0.4) # 设置背景色
# 创建一个 RenderWindow 和 RenderWindowInteractor
render_window = vtk.vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetSize(800, 600)
interactor = vtk.vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# 将 Actor 添加到 Renderer 中
renderer.AddActor(actor)
# 开始渲染
render_window.Render()
interactor.Start()
|
注,vtk.py
文件内部长这样:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 | """This is the vtk module"""
# this module has the same contents as vtkmodules.all
from vtkmodules.vtkCommonCore import *
from vtkmodules.vtkWebCore import *
from vtkmodules.vtkCommonMath import *
from vtkmodules.vtkCommonTransforms import *
from vtkmodules.vtkCommonDataModel import *
from vtkmodules.vtkCommonExecutionModel import *
from vtkmodules.vtkIOCore import *
from vtkmodules.vtkImagingCore import *
from vtkmodules.vtkIOImage import *
from vtkmodules.vtkIOXMLParser import *
from vtkmodules.vtkIOXML import *
from vtkmodules.vtkCommonMisc import *
from vtkmodules.vtkFiltersCore import *
from vtkmodules.vtkRenderingCore import *
from vtkmodules.vtkRenderingContext2D import *
from vtkmodules.vtkRenderingFreeType import *
...
|
例子2:使用 vtkmodules
使用 模块化导入方式,理论上更快,但是细节...
例子中前两行代码中没有直接用到,但是必须导入,否则窗口中没有任何内容!??
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 | import vtkmodules.vtkInteractionStyle # 渲染交互器
import vtkmodules.vtkRenderingOpenGL2 # 渲染窗口
from vtkmodules.vtkFiltersSources import vtkConeSource # 圆锥体源
from vtkmodules.vtkRenderingCore import (
vtkActor,
vtkPolyDataMapper,
vtkRenderer,
vtkRenderWindow,
vtkRenderWindowInteractor
)# 渲染相关类
# 创建一个圆锥体
cone = vtkConeSource()
cone.SetResolution(50)
# 创建一个 Mapper,将几何数据映射到图形
mapper = vtkPolyDataMapper()
mapper.SetInputConnection(cone.GetOutputPort())
# 创建一个 Actor,表示绘制到屏幕上的对象
actor = vtkActor()
actor.SetMapper(mapper)r
# 创建一个 Renderer,负责渲染场景
renderer = vtkRenderer()
renderer.AddActor(actor)
renderer.SetBackground(0.1, 0.2, 0.4)
# 创建一个 RenderWindow 和 RenderWindowInteractor
render_window = vtkRenderWindow()
render_window.AddRenderer(renderer)
render_window.SetSize(800, 600)
interactor = vtkRenderWindowInteractor()
interactor.SetRenderWindow(render_window)
# 开始渲染
render_window.Render()
interactor.Start()
|
vtk类
和渲染直接相关的类:
- vtkRenderer 渲染器,负责绘制一个场景。
- vtkRenderWindow 渲染窗口,负责在屏幕上显示内容。
- vtkRenderWindowInteractor 提供与用户的交互功能(缩放、旋转、平移等)。
vtkRenderer 和 vtkRenderWindow都很复杂。
vtkWindow
vtkWindow 类有点多,特别关注:
- vtkXOpenGLRenderWindow (Linux默认)
- vtkWin32OpenGLRenderWindow (Windows默认)
- vtkEGLRenderWindow (
VTK_OPENGL_HAS_EGL
启用时的默认)
详细的类继承关系:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 | vtkWindow
├── vtkRenderWindow
│ ├── vtkOpenGLRenderWindow
│ │ ├── vtkCocoaOpenGLRenderWindow
│ │ ├── vtkEGLRenderWindow
│ │ ├── vtkGenericOpenGLRenderWindow
│ │ │ ├── vtkExternalOpenGLRenderWindow
│ │ │ ├── vtkZSpaceGenericRenderWindow
│ │ ├── vtkIOSRenderWindow
│ │ ├── vtkOSOpenGLRenderWindow
│ │ ├── vtkSDL2OpenGLRenderWindow
│ │ ├── vtkVRRenderWindow
│ │ │ ├── vtkOpenVRRenderWindow
│ │ │ ├── vtkOpenXRRenderWindow
│ │ ├── vtkWebAssemblyOpenGLRenderWindow
│ │ ├── vtkWin32OpenGLRenderWindow
│ │ │ ├── vtkWin32OpenGLDXRenderWindo
│ │ │ ├── vtkZSpaceWin32RenderWindo
│ │ ├── vtkXOpenGLRenderWindow
│ ├── vtkWebGPURenderWindow
│ │ ├── vtkSDL2WebGPURenderWindow
│ │ ├── vtkWebAssemblyWebGPURenderWindow
│ │ ├── vtkXWebGPURenderWindow
|
vtkRender
| vtkViewport
├── vtkRender
│ ├── vtkOpenGLRender
│ │ ├── vtkExternalOpenGLRender
│ │ ├── vtkVRRender
│ │ │ ├── vtkOpenVRRender
│ │ │ ├── vtkOpenXRRender
│ │ ├── vtkZSpaceRender
│ ├── vtkWebGPURender
|
Qt控件?
尽管这部分和PySide无关,但由于其对C++ Qt有用,简单列一下
源码目录vtk/GUISupport/Qt
中有一些C++的类,用于提供和Qt的集成。其中有几个和QWidget/QWindow直接相关。
QVTKOpenGLNativeWidget
- 别名:QVTKRenderWidget
- 派生自:QOpenGLWidget
- 内部使用 vtkGenericOpenGLRenderWindow
QVTKOpenGLStereoWidget
- 派生自:QWidget
- 内部使用 vtkGenericOpenGLRenderWindow 或 vtkRenderWindow
QVTKOpenGLWindow
- 派生自:QOpenGLWindow
- 内部使用 vtkGenericOpenGLRenderWindow 或 vtkRenderWindow
手册中说,一般来说,QVTKOpenGLNativeWidget 可能是更好的选择,但对于需要四缓冲(quad-buffer)立体显示的应用程序,基于 QVTKOpenGLWindow 的 QVTKOpenGLStereoWidget 可能是更好的选择。需要注意,QVTKOpenGLStereoWidget 有所有 Qt 中 QWidget::createWindowContainer 造成的缺陷。
PySide等绑定的支持?
vtk是一个C++的库,它并没有使用sip或shiboken创建PyQt或PySide的绑定。而是直接尝试找到并使用(这个顺序比matplotlib采用的顺序更符合我的认知/喜好):
- PySide6
- PyQt6
- PyQt5
- PySide2
- PyQt4
- PySide
其 Python/vtkmodules/qt/__init__.py
源码:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 | import importlib
import sys
# PyQtImpl can be set by the user
PyQtImpl = None
# Has an implementation has been imported yet?
for impl in ["PySide6", "PyQt6", "PyQt5", "PySide2", "PyQt4", "PySide"]:
if impl in sys.modules:
# Sometimes an attempted import can be crufty (e.g., unclean
# uninstalls of PyQt5), so let's try to import the actual functionality
try:
importlib.import_module(impl + '.QtCore')
except Exception:
pass
else:
PyQtImpl = impl
break
|
Qt控件 QVTKRenderWindowInteractor
vtk提供了一个 名为 QVTKRenderWindowInteractor 的类:
| class QVTKRenderWindowInteractor(QVTKRWIBaseClass):
|
它是从QWidget(或者QOpenGLWidget,或者QGLWidet)派生出来的:
| # Define types for base class, based on string
if QVTKRWIBase == "QWidget":
QVTKRWIBaseClass = QWidget
elif QVTKRWIBase == "QGLWidget":
QVTKRWIBaseClass = QGLWidget
elif QVTKRWIBase == "QOpenGLWidget":
QVTKRWIBaseClass = QOpenGLWidget
else:
raise ImportError("Unknown base class for QVTKRenderWindowInteractor " + QVTKRWIBase)
|
有了这个Widget,和Qt程序集成就不是问题了
PySide6下使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55 | import sys
from PySide6.QtCore import Qt
from PySide6.QtWidgets import QApplication, QMainWindow
from vtkmodules.vtkFiltersSources import vtkConeSource
from vtkmodules.vtkRenderingCore import vtkActor, vtkPolyDataMapper, vtkRenderer
from vtkmodules.qt.QVTKRenderWindowInteractor import QVTKRenderWindowInteractor
# load implementations for rendering and interaction factory classes
import vtkmodules.vtkInteractionStyle
import vtkmodules.vtkRenderingOpenGL2
class VTKWindow(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("VTK in PySide6 from 1+1=10")
self.setGeometry(100, 100, 800, 600)
# 创建VTK对应的 QWidget 控件
widget = QVTKRenderWindowInteractor(self)
self.setCentralWidget(widget)
# 应用渲染器
ren = vtkRenderer()
widget.GetRenderWindow().AddRenderer(ren)
# 创建 3D 锥体
cone = vtkConeSource()
cone.SetResolution(8)
# 创建映射器并设置输入
coneMapper = vtkPolyDataMapper()
coneMapper.SetInputConnection(cone.GetOutputPort())
# 创建演员并设置映射器
coneActor = vtkActor()
coneActor.SetMapper(coneMapper)
# 将演员添加到渲染器
ren.AddActor(coneActor)
# 设置渲染器背景颜色
ren.SetBackground(0.1, 0.2, 0.4) # 深蓝色背景
# 显示窗口
self.show()
# 初始化并开始交互
widget.Initialize()
if __name__ == "__main__":
app = QApplication(sys.argv)
window = VTKWindow()
sys.exit(app.exec())
|
参考
- https://gitlab.kitware.com/vtk/vtk/-/blob/master/Wrapping/Python/vtkmodules/qt/QVTKRenderWindowInteractor.py
- https://gitlab.kitware.com/vtk/vtk/-/blob/master/Examples/GUI/Qt/MinimalQtVTKApp/
- https://examples.vtk.org/site/Python/
- https://docs.vtk.org/en/latest/build_instructions/index.html