首先,新建一个GaussianSplat.cpp文件并将以下代码复制进去:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(int, char *[])
{
// Create points on a sphere
vtkSmartPointer sphereSource =
vtkSmartPointer::New();
sphereSource->Update();
vtkSmartPointer polydata =
vtkSmartPointer::New();
polydata->SetPoints(sphereSource->GetOutput()->GetPoints());
vtkSmartPointer splatter =
vtkSmartPointer::New();
#if VTK_MAJOR_VERSION <= 5
splatter->SetInput(polydata);
#else
splatter->SetInputData(polydata);
#endif
splatter->SetSampleDimensions(50, 50, 50);
splatter->SetRadius(0.5);
splatter->ScalarWarpingOff();
vtkSmartPointer surface =
vtkSmartPointer::New();
surface->SetInputConnection(splatter->GetOutputPort());
surface->SetValue(0, 0.01);
// Create a mapper and actor
vtkSmartPointer mapper =
vtkSmartPointer::New();
mapper->SetInputConnection(surface->GetOutputPort());
vtkSmartPointer actor =
vtkSmartPointer::New();
actor->SetMapper(mapper);
// Visualize
vtkSmartPointer renderer =
vtkSmartPointer::New();
vtkSmartPointer renderWindow =
vtkSmartPointer::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer renderWindowInteractor =
vtkSmartPointer::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(actor);
renderer->SetBackground(1, 1, 1); // Background color white
renderWindow->Render();
renderWindowInteractor->Start();
return EXIT_SUCCESS;
}
现在,让我们来一步一步地分析代码。
vtkSmartPointer<vtkSphereSource> sphereSource =
vtkSmartPointer<vtkSphereSource>::New();
智能指针会自动管理引用计数(引用计数是个简单的垃圾回收体系,它允许多个有相同值的对象共享这个值,因此不需要构造和析构这个值的副本,从而达到节省内存的目的)的增加与减少,若检测到某对象的引用计数值减少为0,则会自动释放该对象的资源,从而达到自动管理内存的目的。
vtkSmartPointer是一个模板类,所需要的模板参数就是待创建的对象的类名,如:
vtkSmartPointer<vtkImageData> image = vtkSmartPointer<vtkImageData>::New();
不能把对象的原始指针赋值给智能指针,下面代码编译时可以通过,但程序退出时会有内存泄漏,因为智能指针无法自动释放该对象的内存:
vtkSmartPointer image = vtkImageData::New();
该类派生于vtkPolyDataAlgorithm,生成的数据类型就是vtkPolyData,它主要是生成一个中心在渲染场景原点的球体,球体的半径、面数(resolution)都可以任意指定。
vtkSphereSource::SetRadius() // 默认为0.5
vtkSphereSource::SetResolution() // 默认为8
vtkSmartPointer polydata =
vtkSmartPointer::New();
polydata->SetPoints(sphereSource->GetOutput()->GetPoints());
多边形数据集主要由几何结构数据、拓扑结构数据和属性数据组成,由顶点(Vertex)、多顶点(Polyvertex)、线(Line)、折线(Polyline)和三角形条带(Triange Strip)等单元构成的VTK中常用的数据结构之一,可以表示小到一个点、一条线,大到一个模型、一个场景等。
用户可以显示地定义vtkPolyData,首先需要定义一个点集合(vtkPoints)和一个单元(vtkCellArray)集合,点集合定义了vtkPolyData的几何结构,而单元集合则定义了点的拓扑结构。点集合由坐标来定义(InsertNextPoint()
),单元集合则由点的索引而非坐标来定义(GetPointIds()->SetId()
),这样能够减少数据的存储空间。点数据和单元数据都定义完毕,通过void SetPoints(vtkPoints*)
和void SetPolys(vtkCellArray*)
将其添加至vtkPolyData中。
// Create a mapper and actor
vtkSmartPointer<vtkPolyDataMapper> mapper =
vtkSmartPointer<vtkPolyDataMapper>::New();
mapper->SetInputConnection(surface->GetOutputPort());
vtkSmartPointer<vtkActor> actor =
vtkSmartPointer<vtkActor>::New();
actor->SetMapper(mapper);
该类用于渲染多边形几何数据(vtkPolyData),派生自类vtkMapper,将输入的数据转换为几何图元(点、线、多边形)进行渲染。
vtkPolyDataMapper::SetInputConnection()
:VTK可视化管线的输入数据接口,对应的可视化管线的输出数据接口为GetOutputPort()
;VTK 5.0之前的版本使用SetInput()
和GetOutput()
作为输入输出接口,VTK 5.X版本保留了对这两个接口的支持。
该类派生自vtkProp类,渲染场景中数据的可视化表达(包括对象的位置、大小和方向等信息)通过vtkProp的子类负责。比如本例中要渲染一个球体,球体的数据类型是vtkPolyData,数据要在场景中渲染时,不是直接把数据加入渲染场景,而是以vtkProp的形式存在于渲染场景中。三维空间中渲染对象最常用的vtkProp子类有vtkActor(表达场景中的几何数据)和vtkVolume(表达场景中的体数据);二维空间中的数据则是用vtkActor2D表达。
Prop依赖于两个对象:一个是Mapper(vtkMapper)对象,负责存放数据和渲染信息;另一个是属性(vtkProperty)对象,负责控制颜色、不透明度等参数。
vtkActor::SetMapper()
:用于设置生成几何图元的Mapper,即连接一个Actor到可视化管线的末端(Mapper是可视化管线的末端)。
// Visualize
vtkSmartPointer<vtkRenderer> renderer =
vtkSmartPointer<vtkRenderer>::New();
vtkSmartPointer<vtkRenderWindow> renderWindow =
vtkSmartPointer<vtkRenderWindow>::New();
renderWindow->AddRenderer(renderer);
vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =
vtkSmartPointer<vtkRenderWindowInteractor>::New();
renderWindowInteractor->SetRenderWindow(renderWindow);
renderer->AddActor(actor);
renderer->SetBackground(1, 1, 1); // Background color white
renderWindow->Render();
renderWindowInteractor->Start();
将操作系统与VTK渲染引擎连接到一起。vtkRenderWindow中包含了vtkRenderer集合、渲染参数等。
vtkRenderWindow->AddRenderer()
:用于加入vtkRenderer对象。
vtkRenderWindow->SetSize()
:用于设置窗口的大小,以像素为单位。
负责管理场景的渲染过程。组成场景的对象包括Prop,照相机(vtkCamera)和光照(vtkLight)都被整合到一个vtkRenderer对象中。一个vtkRenderWindow中可以有多个vtkRenderer对象,而这些vtkRenderer可以渲染在窗口不同的矩形区域中(即视口)或者覆盖整个窗口区域。
vtkRenderer::AddActor()
:用于将vtkProp类型的对象添加到渲染场景中。
vtkRenderer::SetBackground()
:用于设置渲染场景的背景颜色,用RGB的格式设置,三个分量的取值为0.0~1.0。(0.0,0.0,0.0)为黑色,(1.0,1.0,1.0)为白色。
提供平台独立的响应鼠标、键盘和时钟事件的交互机制,通过VTK的观察者/命令模式将监听到的特定平台的鼠标、键盘和时钟事件交由vtkInteractorObserve或其子类(如vtkInteractorStyle)进行处理。vtkInteractorStyle等监听这些消息并进行处理以完成旋转、拉伸和缩放等运动控制。
vtkRenderWindowInteractor::SetRenderWindow()
:用于设置渲染窗口,消息是通过渲染窗口捕获到的,所以必须给交互器对象设置渲染窗口。
vtkRenderWindowInteractor::SetInteractorStyle()
:用于定义交互器样式,默认为vtkInteractorStyleSwitch。
vtkRenderWindowInteractor::Initialize()
:为处理窗口事件做准备,交互器工作之前必须先调用这个方法进行初始化,但是官网上的例子代码(本例)并没有做这一步。
vtkRenderWindowInteractor::Start()
:开始进入事件响应循环,交互器处于等待状态,等待用户交互事件的发生。
可以将以上示例看作一个舞台剧演出。整个剧院就好比VTK程序的渲染窗口(vtkRenderWindow);舞台就相当于渲染场景(vtkRenderer);而演员就是程序中的Actor,台上演员与台下观众的互动可以看作与应用程序的交互(vtkRenderWindowInteractor);演员与观众的互动方式有很多种,就好比程序中的交互器样式(vtkInteractorStyle);对于舞台上的演员,观众可以通过他们的容貌打扮辨认,就相当于程序中vtkActor的不同属性(vtkProperty);每一个vtkActor的数据和渲染信息存储在一个vtkMapper对象中,负责将原始数据转换为渲染所需的图元数据。
复制如下语句到你的 CMakeLists.txt 文件中:
cmake_minimum_required(VERSION 2.6)
PROJECT(GaussianSplat)
FIND_PACKAGE(VTK REQUIRED)
INCLUDE(${VTK_USE_FILE})
ADD_EXECUTABLE(GaussianSplat GaussianSplat.cxx)
TARGET_LINK_LIBRARIES(GaussianSplat ${VTK_LIBRARIES})
完成后即可用CMake进行编译,生成相应的可执行文件后就可以运行了。