1. 什么是vtk可视化管线?
定义: 可视化管线是指用于获取或创建数据、处理数据以及把数据写入文件或者把数据传递给渲染引擎进行显示,这样的一种结构在VTK里就称为可视化管线。数据对象(Data Object) ,处理对象(Process Object)和数据流方向(Direction of Data Flow)是可视化管线的三个基本要素。—《VTK图形图像开发进阶》
分析: 根据上述定义,可见vtk可视化管线可基本分为三部分(缺一不可):
- 数据源或数据集
- 数据处理
- 数据写入文件或进入渲染引擎渲染
因此,vtk可视化管线其流程为:
2. 数据集准备
数据对象是数据的集合(数据集),数据对象表现的数据是可以被可视化管线处理的数据,只有当数据对象被组织成一种结构后,才能被VTK提供的可视化。而数据集必须具有的结构包括:① 组织结构;② 属性数据。
其中,组织结构包括几何结构与拓扑结构两部分,其中几何结构可理解为物体特征点的坐标分布,如三角形的三个顶点坐标构成了其几何结构,而三个顶点之间的连接关系构成了其拓扑结构;属性数据可表示物体组织结构的信息,如三维激光点云各点的能量值、我国各市GDP,可用颜色赋予其高低的概念,当然能量与GDP只是标量,属性数据海包括向量与张量等几大类。
3. 数据处理
有时通过文件读入的数据并非我们想要的数据集形式,例如我们需要显示三角网,而读入的是点云,因此需要对输入的点云进行一定的处理,构建点云数据集新的拓扑结构。这个过程称之为Filter,即过滤或处理。
上图中,Source是指用于创建数据或读取数据,Filter的输出可以直接写入文件,或者经 Mapper变换后传入渲染引擎进行渲染、显示,结束可视化管线。Source、Filter与Mapper共同组成数据对象处理。
4. 渲染引擎
《VTK图形图像开发进阶》一书中对渲染引擎有以下比喻:整个剧院就好比 vtk程序的渲染窗口(vtkRenderWindow)舞台就相当于渲染场景( vtkRenderer);而那些演员就是程序中的 Actor(vtkActor)。
vtkActor:该类派生自 vtkProp类。数据要在场景中渲染时,不是直接把数据加入渲染场景,而是以 vtkProp的形式存在于渲染场景中,Prop依赖于两个对象:一个是 Mapper ( vtkMapper)对象,负责存放数据,另一个是属性((vtkProperty)对象,负责控制颜色、不透明度等参数。
vtkRenderer:负责管理场景的渲染过程。组成场景的对象包括 Prop,照相机(vtkCamera)和光照(vtkLight)。
vtkRenderWindow:将操作系统与VTK 渲染引擎连接到一起。
5. 案例(点云与柱体显示)
5.1 点云数据读取
参照文章:https://blog.csdn.net/weixin_42261213/article/details/102054922
vtkSmartPointer<vtkPoints> m_Points = vtkSmartPointer<vtkPoints>::New(); //点集几何结构
vtkSmartPointer<vtkCellArray> vertices = vtkSmartPointer<vtkCellArray>::New(); //点集拓扑结构
vtkSmartPointer<vtkPolyData> polyData = vtkSmartPointer<vtkPolyData>::New();//点集(组织结构完整)
vtkSmartPointer<vtkPolyDataMapper> pointMapper = vtkSmartPointer<vtkPolyDataMapper>::New();//点集转为图元
vtkSmartPointer<vtkActor> pointActor = vtkSmartPointer<vtkActor>::New();//演员
vtkSmartPointer<vtkRenderer> ren1 = vtkSmartPointer< vtkRenderer>::New();//渲染场景
vtkSmartPointer<vtkRenderWindow> renWin = vtkSmartPointer<vtkRenderWindow>::New();//渲染窗口
//---1. 读入点集
FILE*fp = NULL; fp = fopen("Test2.txt", "r");
if (!fp)
{
printf("Open file failed!!\n");
int m;
cin >> m;
exit(0);
}
double x = 0, y = 0, z = 0;
int i = 0;
while (!feof(fp))
{
fscanf(fp, "%lf %lf %lf", &x, &y, &z);
m_Points->InsertPoint(i, x, y, z); // 加入点信息,构建几何结构
vertices->InsertNextCell(1);
vertices->InsertCellPoint(i); // 表示点云索引顺序,构建拓扑结构
i++;
}
fclose(fp);
//---2.点集转换为图元并加入渲染引擎显示
polyData->SetPoints(m_Points); // 设置点集
polyData->SetVerts(vertices); // 设置渲染顶点
pointMapper->SetInputData(polyData);
pointActor->SetMapper(pointMapper);
pointActor->GetProperty()->SetColor(1, 0, 0);
pointActor->GetProperty()->SetAmbient(0.5);
pointActor->GetProperty()->SetPointSize(8);
ren1->AddActor(pointActor);
ren1->SetBackground(0, 0, 0);
renWin->AddRenderer(ren1);
renWin->SetSize(800, 800);
renWin->Render();
该方法读取与显示点云,构件了polyData,然后转换为pointMapper(数据对象处理),然后经渲染引擎进行显示。
5.2 柱体模型
参考: https://gitlab.kitware.com/vtk/vtk/blob/73465690278158b9e89661cd6aed26bead781378/Examples/Rendering/Cxx/Cylinder.cxx
// ---1.准备柱体数据
vtkCylinderSource *cylinder = vtkCylinderSource::New();
cylinder->SetResolution(8);
// ---2.构建图元
vtkPolyDataMapper *cylinderMapper = vtkPolyDataMapper::New();
cylinderMapper->SetInputConnection(cylinder->GetOutputPort());
// ---3.加入渲染引擎与交互
vtkActor *cylinderActor = vtkActor::New();
cylinderActor->SetMapper(cylinderMapper);
cylinderActor->GetProperty()->SetColor(1.0000, 0.3882, 0.2784);
cylinderActor->RotateX(30.0);
cylinderActor->RotateY(-45.0);
vtkRenderer *ren1 = vtkRenderer::New();
vtkRenderWindow *renWin = vtkRenderWindow::New();
renWin->AddRenderer(ren1);
vtkRenderWindowInteractor *iren = vtkRenderWindowInteractor::New();
iren->SetRenderWindow(renWin);
ren1->AddActor(cylinderActor);
ren1->SetBackground(0.1, 0.2, 0.4);
renWin->SetSize(200, 200);
ren1->ResetCamera();
ren1->GetActiveCamera()->Zoom(1.5);
renWin->Render();
iren->Start();
// ---4.内存释放
cylinder->Delete();
cylinderMapper->Delete();
cylinderActor->Delete();
ren1->Delete();
renWin->Delete();
iren->Delete();
根据https://vtk.org/doc/nightly/html/classvtkCylinderSource.html中继承关系,可见类vtkCylinderSource继承于类vtkAlgorithm,vtkCylinderSource->vtkPolyDataAlgorithm->vtkAlgorithm->vtkObject,如下图。而vtkAlgorithm 是 VTK 中所有源、过滤器和接收器的超类。 它定义了一个用于执行数据处理算法的通用接口。 管道连接与输入和输出端口相关联,输入和输出端口与通过连接的数据类型无关。
由官方类继承查询:https://vtk.org/doc/nightly/html/classes.html,可见类vtkPolyDataMapper的Function SetInputConnection()参数与类vtkCylinderSource的Function GetOutputPort()返回值一致,因此可直接构建图元。构建完图元即可进入渲染引擎并进行显示。
6. 总结
最后,以流程图形式回顾一下三步过程,也算最后总结。