前言: 解决 VTK 是如何工作的问题
参考资料:
《An Object-Oriented Approach to 3D Graphics》
《The VTK User’s Guide》
VTK (the Visualization Toolkit)是一个可视化工具包。可以用于计算机图形、图像的处理与可视化。
通过对于点、面、体等进行渲染,调节相机、光线和坐标,以及对模型着色、注释,最终显示出逼真模型。这些步骤在vtk中均对应着相应的类。
而我们手中的数据往往都是一串数字,vtk 的工作就是将我们导入的这些数字,最终渲染出一个可视图/体。
可用如下图简要概括整个 vtk 的工作过程
可将整个过程可以类比于我们在电脑上能够看到一个舞台剧视频过程来理解。
整个可视化流程,可以大致分为两个阶段。一个是数据准备阶段,另一个是渲染阶段。数据准备阶段主要就是读取数据、数据处理(过滤);渲染阶段就是将处理后的数据,生成对应实体,在设定的渲染场景展示,并能够实现交互。
而各部分实现的功能简单明了,目的明确,我们走完上述流程,就可以得到一个能被展示的模型。各部分间有着承上启下的关系,整个流程其实就是数据传递、处理的流程。因此用数据流来描述可能更加精确,而整个过程就可以看做数据流在管道中朝着一个方向流动的过程。整个流水线也被叫做 vtk 的可视化管线。
但值得说明的是,在 vtk 中有些类是上述一些部件的合成,例如最明显的图像显示类 vtkImageViewer
,因为图像显示较为常用,每次都进行相同的流程显然浪费时间,因此该类就对 vtkActor\vtkRenderer\vtkRenderWindow
等进行了集成,直接将读取的图片数据导入其中,便可完成最终的显示。当然这样的集成类在 vtk 中很常见。
上面提到整个过程就像是流水线,那各部分间数据传输是如何建立连接的呢 ? 即每段的管道如何连接起来的呢 ? 主要通过一下函数。
对于数据准备阶段 的数据传输连接主要有两个成对函数
SetInputConnection() <--------> GetOutputPort()
SetInputData() <----------> GetOutput()
// Example: mapper->SetInputConnection(reader->GetOutputPort)
注:在高版本中划分为了这两对,在低版本中仅有 SetInput() <----> GetOutput()
,而高版本 vtk 中SetInput() <----> GetOutput()
不再可用,而是划分了上面两种。
对于渲染阶段,各部连接分别用下述函数
actor -> SetMapper(mapper); // 演员的映射数据设定
renderer -> AddActor(actor); // 渲染的演员对象添加到场景
renderWindow ->AddRenderer(renderer); // 场景添加到显示窗口
renderWindowInteractor -> SetRenderWindow(renderWindow); // 窗口设定交互功能
./demo.cxx
语言:c++
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2); // VTK was built with vtkRenderingOpenGL2
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
int main(){
// vtkSource
vtkConeSource* cone = vtkConeSource::New();
cone->SetHeight(3);
cone->SetRadius(1);
cone->SetResolution(10);
// vtkMapper
vtkPolyDataMapper* mapper = vtkPolyDataMapper::New();
mapper->SetInputConnection(cone->GetOutputPort());
// vtkActor
vtkActor* actor1 = vtkActor::New();
actor1->SetMapper(mapper);
actor1->GetProperty()->SetColor(1,0,0);
vtkActor* actor2 = vtkActor::New();
actor2->SetMapper(mapper);
actor2->GetProperty()->SetColor(0,1,0);
vtkActor* actor3 = vtkActor::New();
actor3->SetMapper(mapper);
actor3->GetProperty()->SetColor(0,0,1);
vtkActor* actor4 = vtkActor::New();
actor4->SetMapper(mapper);
actor4->GetProperty()->SetColor(1,1,1);
// vtkCamera
vtkCamera* camera1 = vtkCamera::New();
camera1->SetClippingRange(-5,6);
camera1->SetFocalPoint(0,0,0);
camera1->SetPosition(-5,2,0);
camera1->ComputeViewPlaneNormal();
camera1->SetViewUp(0 ,1, 0);
// vtkRenderer
vtkRenderer* ren1 = vtkRenderer::New();
ren1->AddActor(actor1);
ren1->SetBackground(0.3,0.3,0.6);
ren1->SetViewport(0,0.5,0.5,1);
ren1->SetActiveCamera(camera1);
vtkRenderer* ren2 = vtkRenderer::New();
ren2->AddActor(actor2);
ren2->SetBackground(0.3,0.3,0.6);
ren2->SetViewport(0.5,0.5,1,1);
vtkRenderer* ren3 = vtkRenderer::New();
ren3->AddActor(actor3);
ren3->SetBackground(0.3,0.3,0.6);
ren3->SetViewport(0,0,0.5,0.5);
vtkRenderer* ren4 = vtkRenderer::New();
ren4->AddActor(actor4);
ren4->SetBackground(0.3,0.3,0.6);
ren4->SetViewport(0.5,0,1,0.5);
// vtkRenderWindow
vtkRenderWindow* renWin = vtkRenderWindow::New();
renWin->AddRenderer(ren1);
renWin->AddRenderer(ren2);
renWin->AddRenderer(ren3);
renWin->AddRenderer(ren4);
// vtkRenderWindowInteractor
vtkRenderWindowInteractor* iren = vtkRenderWindowInteractor::New();
iren->SetRenderWindow(renWin);
iren->Initialize();
iren->Start();
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(demo)
find_package(VTK REQUIRED)
add_executable(Demo demo.cxx)
target_link_libraries(Demo ${VTK_LIBRARIES})
结果
实例中展示生成四个 Actor ,放置在一个窗口
初始化设定:对显示所用引擎和显示交互风格初始化,否则可能会出错
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2); // VTK was built with vtkRenderingOpenGL2
VTK_MODULE_INIT(vtkInteractionStyle);
VTK_MODULE_INIT(vtkRenderingFreeType);
代码中在实例化对象使用了大量的指针,如果使用不当,很容易形成空指针、野指针等,代码很容易出现内存 bug。vtk 中为此有智能指针类,通过计数法,管理指针的申请释放。使用方法如下
//不使用智能指针:
vtkConeSource* cone = vtkConeSource::New();
//使用智能指针:
#include
vtkSmartPointer<vtkConeSOurce> cone = vtkSmartPointer<vtkConeSource>::New();
使用 智能指针vtkSmartPointer
和 集成类vtkImageViewer2
: 读取 *jpeg 图像,并用 VTK 显示
./demo.cxx
语言:c++
#include
#include
#include
#include
#include "vtkAutoInit.h"
VTK_MODULE_INIT(vtkRenderingOpenGL2);
int main(){
vtkSmartPointer<vtkJPEGReader> jpegReader = vtkSmartPointer<vtkJPEGReader>::New();
jpegReader->SetFileName("/home/zhangwei/Pictures/Totoro.jpeg");
vtkSmartPointer<vtkImageViewer2> imgViewer = vtkSmartPointer<vtkImageViewer2>::New();
imgViewer->SetInputConnection(jpegReader->GetOutputPort());
vtkSmartPointer<vtkRenderWindowInteractor> iren = vtkSmartPointer<vtkRenderWindowInteractor>::New();
imgViewer->SetupInteractor(iren);
imgViewer->Render();
iren->Start();
return 0;
}
CMakeLists.txt
cmake_minimum_required(VERSION 2.8)
project(demo)
find_package(VTK REQUIRED)
add_executable(Demo demo.cxx)
target_link_libraries(Demo ${VTK_LIBRARIES})
结果
在弄清 VTK 工作流程后,问题也逐个显现出来
vtkConeSource
中数据是什么样的? 什么样数据可以用 VTK 显示出来 ? 如何人为地设定这些数据 ? 参见 基本数据结构Filter, Mapper
有那些 ? 如何把自己编写的 Algorithm 应用到数据处理中 ?Camera,Light
的设定有那些参数?各有什么用处?RenderWindowInteractor
如何实现交互?可否人为设定?后接续 …