在不同的语境下,VTK (Visualization ToolKit) 可能表示:
VTK 中的所有类名都是以 vtk
起始的。为节省空间以突出继承关系,下图中省去了该字段(即 DataSet
应补全为 vtkDataSet
)。
在 VTK 中,几乎所有的类都是 vtkObject
的派生类。
所有对象 (object) 都是动态的,在 C++ 中,它们都必须由所属类的 New()
方法创建,并由所属类的 ` Delete()` 方法销毁:
vtkObjectBase* obj = vtkExampleClass::New(); // 创建
otherObject->SetExample(obj); // 使用
obj->Delete(); // 销毁
New()
方法返回指向动态数据的原始指针 (raw pointer)。 如果(在离开创建它的作用域前)忘记调用 Delete()
,则会造成内存泄漏 (memory leak)。 VTK 提供了一种基于引用计数 (reference count) 的智能指针 (smart pointer) 来管理动态对象:
auto obj = vtkSmartPointer<vtkExampleClass>::New(); // 创建
otherObject->SetExample(obj); // 使用
// obj->Delete(); // 销毁(自动完成)
在线文档只给出了 C++ 版的 API。 解释型 (interpreted) 语言(如 Python)的语法机制没有 C++ 丰 (fan) 富 (suo),获 (cai) 得 (ce) 相应的 API 需要对 C++ 版作适当的压缩。
计算机图形学借用了一些电影行业的术语。场景 (scene) 由以下要素构成:
在 VTK 中,上述概念由以下类实现:
vtkRenderWindow
对象负责管理render window (渲染窗口) 及渲染器 (renderer)。 vtkRender
对象负责协调演员、光源、镜头以生成图像。 vtkRender
对象都必须关联到一个 vtkRenderWindow
对象,且对应于其中的一个由归一化坐标定义的长方形视窗 (viewport)。vtkRenderWindow
对象只关联了一个 vtkRender
对象,则相应视窗的归一化坐标为 (0,0,1,1)
,即占据整个渲染窗口。vtkLight
对象用于照亮其所处的场景。 vtkCamera
对象用于摄取场景。 vtkActor
对象表示场景中的演员,即被显示的数据或对象。vtkMapper
对象是数据的内部表示与显示模块之间的接口。示例:
${VTK_EXAMPLES}/src/GeometricObjects/Cone.py
:几何源、渲染器、互动器。${VTK_EXAMPLES}/src/Interaction/CallBack.py
:坐标轴、事件、观察者、回调函数。${VTK_EXAMPLES}/src/Renderings/Cone3.py
:在一个 vtkRenderWindow
对象中并排显式两个 vtkRender
对象。${VTK_EXAMPLES}/src/Renderings/Cone4.py
:属性对象、变换。数据可视化 (data visualization) 包括以下两部分:
可视化管道 (visualization pipeline) 或可视化网络 (visualization network) 由以下对象构成:
详见《VTK User’s Guide》的《VTK File Formats》一节,及《The Visualization Toolkit》的《Basic Data Representation》一章。
这种格式的定义较为简单,对于简单的应用,可以独立于 VTK 程序库实现一套 IO 模块。
这是一种支持随机访问 (random access) 和并行读写 (parallel IO) 的文件格式,以 .vt[irsupm]
为扩展名:
扩展名 | 数据集类型 |
---|---|
vti | vtkImageData |
vtr | vtkRectlinearGrid |
vts | vtkStructuredGrid |
vtu | vtkUnstructuredGrid |
vtp | vtkPolyData |
vtm | vtkMultiBlockDataSet |
这种格式的定义比传统 VTK 格式复杂,建议直接调用 VTK 程序库提供的 API。
如果在本地部署 VTK 程序库有困难(无网络、无权限),可以考虑使用 PyEVTK。 它完全用 Python & Cython 实现,因此不依赖于 VTK 程序库。 安装后即可在本地 Python 程序中 import
该模块,具体用法可以参照 src/examples
目录下的示例。
read.py
和 write.py
演示了如何用 vtk
模块提供的 API 读写 vtkUnstructuredGrid
。 ⚠️ 要运行该示例,必须先在本地部署 VTK 模块(可直接运行 pip install vtk
安装)。
运行以下命令
mkdir build # 在 write.py 所属目录下,创建 build 目录
cd build
python3 ../write.py
会在 build
目录下生成四个文件:
ugrid_demo_ascii.vtk
ugrid_demo_ascii.vtu
ugrid_demo_binary.vtk
ugrid_demo_binary.vtu
读取其中的两个文件:
python3 ../read.py
源代码仓库的 Examples
目录下有各个 VTK 模块的示例。
这里将 Examples/IO/Cxx/DumpXMLFile.cxx
简化为 read.cpp
。
/usr/local/include/vtk-8.2
,库文件位于 /usr/local/lib
)及版本号:mkdir build # 在 read.cpp 所属目录下,创建 build 目录
cd build
c++ -c ../read.cpp -I/usr/local/include/vtk-8.2 -std=c++17
c++ -o read read.o -L/usr/local/lib -lvtkCommonDataModel-8.2 \
-lvtkCommonCore-8.2 \
-lvtkIOLegacy-8.2 \
-lvtkIOXML-8.2 \
-lvtkIOGeometry-8.2 \
-lvtkIOImport-8.2 \
-lvtksys-8.2
CMakeLists.txt
中,CMake 会自动查找头文件及库文件位置:mkdir build # 在 read.cpp 所属目录下,创建 build 目录
cd build
cmake -S .. -B .
cmake --build .
./read *.vtk *.vtu # 读取在《Python 示例》中生成的文件
VTK 中的算法 (algorithm) 是指对数据作变换(以改变数据的表示形式或生成其他数据)的对象。
算法可以按被处理的数据类型来分类:
颜色映射 (color mapping) 是一种常用的标量算法。它将标量值(如:温度值、压力值)映射为颜色值(如:RGB 数组)。该映射通常由以下方式实现:
[s_min, s_max]
及 RGB 数组的长度 n
,则标量值 s
映射到 (r[i], g[i], b[i])
,其中 i
由以下线性分布关系确定i = 0
if s_min < s:
if s_max < s:
i = n - 1
else:
i = n * (s - s_min) // (s - s_max)
s
都可以被唯一地映射到某个 i
,可视为查询表的推广。from vtk import *
# 创建默认查询表(由红到蓝)
lookup_table = vtkLookupTable()
lookup_table.SetHueRange(0.6667, 0.0)
lookup_table.Build()
ParaView 是基于 VTK 的 GUI 前端。
启动后,在 Help
列表中有各种本地或在线文档的链接,其中《Getting Started》可用于快速入门,《ParaView Guide》用于系统学习。
paraview
paraview
是基于 Qt 的 GUI 程序。
pvpython
pvpython
是封装了 ParaView 程序库的 Python shell —— 在其中可以使用 Python 自带的功能,也可以像调用其他 Python 模块(包)一样加载 ParaView 模块:
from paraview.simple import *
在 paraview
(GUI) 中的所有操作,几乎都可以在 pvpython
(CLI) 中以 Python 指令的形式来完成。这些指令可以被同步记录到 .py
文件中,只需在 paraview
(GUI) 中以 Tools → Start Trace 开启记录、以 Tools → Stop Trace 停止记录。
完整 API 列表参见《ParaView’s Python documentation》。
pvbatch
pvbatch
是由 .py
文件驱动的 CLI 程序。
pvserver
pvserver
是运行在远程主机上的 CLI 程序。
使用 ParaView 主要分三个基本步骤:
对于同一个数据文件,第 1 步只需执行 1 次,而第 2、3 步可以执行多次。
最简单(最通用)的动态数据显示方式,是将每一时间步的数据写入一个对应于该时刻的文件,这样的一个文件对应于动画中的一帧。ParaView 在加载按以下任意一种风格命名的一组 (group) 文件时,会自动将它们识别为一个文件序列 (file series):
fooN.vtk
Nfoo.vtk
foo.vtk.N
foo_N.vtk
foo.N.vtk
N.foo.vtk
foo.vtksN
其中 foo
可以是任意非空字符串,N
为整数编号,扩展名 .vtk
可以替换为任意 VTK 文件格式所对应的扩展名。
pvserver
。paraview
。Add Server
),如果 Pipeline Browser
中的 builtin
被替换为远程主机的标识符,则表明连接成功。# 构造矢量
Velocity = (MomentumX*iHat + MomentumY*jHat + MomentumZ*kHat) / Density
# 构造标量(三维空间)
Pressure = 0.4 * (EnergyStagnationDensity - dot(Velocity, Velocity) * Density / 2)
# 构造标量(一维空间)
Pressure = 0.4 * (EnergyStagnationDensity - MomentumX * MomentumX / Density / 2)