第03章-VTK系统概述(1)

【译者:这个系列教程是以Kitware公司出版的《VTK User’s Guide -11th edition》一书作的中文翻译(出版时间2010年,ISBN: 978-1-930934-23-8),由于时间关系,我们不能保证每周都能更新本书内容,但尽量做到一周更新一篇到两篇内容。敬请期待^_^。欢迎转载,另请转载时注明本文出处,谢谢合作!同时,由于译者水平有限,出错之处在所难免,欢迎指出订正!】


【本节对应原书中的第19页至第25页】

本章旨在介绍VTK系统的总体概述,并讲解运用C++、Java、Tcl和Python等语言进行VTK应用程序开发时所需掌握的基本知识。首先我们从VTK系统的基本概念和对象模型抽象开始进行介绍,并在本章最后通过例子演示这些概念以及介绍一下在构建VTK工程时所需要掌握的知识。

3.1系统结构

VTK系统由两个子系统组成:一个是编译的C++类库,另一个是解释性语言的封装层,以供Java、Tcl和Python等语言来操作该C++类库,系统结构如图3-1所示。


图3-1VTK系统由C++类库内核以及解释性语言(Java、Tcl、Python)封装层所组成。

该结构的优点在于保持解释性语言快速开发特性(避免编译、链接流程,工具简单而强大,同时又易于使用的GUI工具)的同时,用户可以利用编译的C++语言开发高效的算法(无论是CPU利用还是内存的利用)。当然,对于熟练掌握C++语言或者使用相应开发工具的用户来说,VTK应用程序可以完全采用C++语言进行开发。

由于VTK系统采用了面向对象的思想,因此利用VTK进行高效开发的关键在于深入理解系统内部的对象模型,以便消除用户在使用大量的VTK系统对象时的迷惑,并能更有效的对这些对象进行组合创建应用程序。此外,还需要了解系统中许多对象的功能,而这只能通过阅读例子代码和在线文档来获得。这本《VTK用户指南》中,我们将尽力介绍一些有用的VTK对象的组合以便用户可以将其应用到自己的应用程序中。

本章接下来将介绍VTK中的两个重要组件:可视化管线【译者:Visualization Pipeline,有些翻译成“可视化管道”,本书我们翻译成“可视化管线”】和渲染引擎。可视化管线主要负责数据获取或者创建,数据处理,然后将数据写入文件或者传递至渲染引擎中进行显示。而渲染引擎负责创建传递过来的数据的一个可视表达。注意这里所提到的组件并非VTK系统结构中具体的组件,而是一个抽象的概念组件。本章是在比较高的层次上进行阐述,但是当你将本章的内容和下一章节中具体的例子或者是VTK源文件中所提供的大量的示例程序结合在一起时,你将会对本章所介绍的概念有更深刻的理解。

底层对象模型

vtkObject是VTK对象继承关系树的根结点,几乎所有的VTK对象都继承自该类,除了一部分特殊对象继承自vtkObject的父类vtkObjectBase。所有的VTK对象都必须由对象的New()方法创建,并由对象的Delete()方法销毁。由于VTK对象中的构造函数被声明为受保护类型,因此VTK对象不能够在栈中分配空间。另外,VTK对象采用了共同基类和统一的创建、销毁方法,可以实现许多基本的面向对象操作。

引用计数。VTK对象内部显式地记录了引用本身的指针的个数。当一个对象通过静态的New()函数创建时,该对象内部的初始引用计数即为1,因为所创建的对象会有一个原始指针(Raw Pointer)指向该对象。

vtkObjectBase*obj = vtkExampleClass::New();

当指向某个对象的其他对象创建或者销毁时,引用计数会通过Register()和Unregister()函数进行相应的增加和减少。通常情况下系统会通过对象的API函数“Set()”自动完成。

otherObject->SetExample(obj);

这时对象obj的引用计数值为2。因为除了原始指针之外,还有另外一个对象otherObject内部的指针指向它。当原始存储对象的指针不再需要时,通过Delete()函数可以删除该引用,即:

obj->Delete();

这样再利用原始指针去访问该对象时将不再是安全的,因为该指针已经不再拥有对象的引用。因此为了保证对对象引用的有效管理,每次调用New()后都要进行Delete(),确保没有泄漏引用。

另外一种避免引用泄漏的方法是通过类模板vtkSmartPointer<>提供的智能指针来简化对象的管理操作,上述例子可以重写为如下代码:

vtkSmartPointer<vtkObjectBase>obj = vtkSmartPointer<vtkObjectBase>::New();

otherOject->SetExample(obj);

该例中,智能指针会自动管理对象的引用。当智能指针变量超出其作用域并且不再使用时,例如当其为函数内部局部变量,函数返回时,智能指针会自动通知对象减少引用计数。由于智能指针提供了内部静态New()函数,因此不需要原始指针来保存对象的引用,因此也不需要再调用Delete()函数。

运行时类型信息。在C++中对象的实际类型可能与该对象的索引指针的类型不一致。VTK中所有的类都有一个接口函数提供类名标识符,因此一个string类型足以标识这些类。运行时对象的实际类型可以通过GetClassName()函数获得:

constchar* type = obj->GetClassName();

通过IsA()函数可以判断一个对象是否是某一个类的实例,或者是该类的某个子类的实例:

if(obj->IsA(“vtkExampleClass”)) { … }

父类类型的指针可以通过静态函数SafeDownCast()安全地强制转换为子类类型的指针:

vtkExampleClass*example = vtkExampleClass::SafeDownCast(obj);

上述代码只有当对象example是obj的子类实例时,类型转换才成功;否则返回空指针。

对象状态显示。容易理解的对象的当前状态信息对于程序的调试是十分有用的。VTK对象的状态可以通过输出函数Print()获得:

obj->Print(cout);

渲染引擎

组成VTK渲染引擎的类主要负责接收可视化管线(Visualization Pipeline)的输出数据并将结果渲染到窗口中。该过程主要涉及到下述一些组件。注意,这些只是VTK渲染系统中比较常用的组件,并非全部。而每个子标题仅仅是代表一个对象类型的最高层VTK超类【译者:或者称为“父类”】,在许多情况下,这些超类只是定义了基本API函数的抽象类,而真正的实现则由其子类来完成。

vtkProp。渲染场景中数据的可视表达(Visible Depictions)是由vtkProp的子类负责。三维空间中渲染对象最常用的vtkProp子类是vtkActor和vtkVolume,其中vtkActor用于表示场景中的几何数据(Geometry Data),vtkVolume表示场景中的体数据(Volumetric Data)。vtkActor2D常用来表示二维空间中的数据。vtkProp的子类负责确定场景中对象的位置、大小和方向信息。控制Prop【译者:Prop,Actor, Mapper, Property等词,本书不作翻译。】位置信息的参数依赖于对象是否在渲染场景中,比如一个三维物体或者二维注释,它们的位置信息控制方式是有所区别的。三维的Prop如vtkActor和vtkVolume(vtkActor和vtkVolume都是vtkProp3D的子类,而vtkProp3D继承自vtkProp),既可以直接控制对象的位置、方向和放缩信息,也可以通过一个4×4的变换矩阵来实现。而对于二维注释功能的Props如vtkScalarBarActor,其大小和位置有许多的定义方式,其中包括指定相对于视口的位置、宽度和高度。Prop除了提供对象的位置信息控制之外,Prop内部通常还有两个对象,一个是Mapper对象,负责存放数据和渲染信息,另一个是Property(属性)对象,负责控制颜色、不透明度等参数。

VTK中定义了大量的功能细化的Prop(超过50个),如vtkImageActor(负责图像显示)和vtkPieChartActor(用于创建数组数据的饼图可视表示)。其中的有些Props内部直接包括了控制显示的参数和待渲染数据的索引,因此并不需要额外的Property和Mapper对象。vtkActor的子类vtkFollower可以自动的更新方向信息保持自身始终面向一个特定的相机,这样无论如何旋转渲染场景中的对象,vtkFellower对象都是可见的,适用于三维场景中的广告板(Billboards)或者是文本。vtkActor的子类vtkLodActor可以自动改变自身的几何表示来实现所要求的交互帧率,vtkProp3D的子类vtkLODProp3D则是通过从许多Mapper中进行选择来实现不同的交互性(可以是Volumetric Mapper和GeometricMapper的集合)。vtkAssembly建立了Actor的等级结构以便在整个结构平移、旋转或者放缩时能够更合理的控制变换。

vtkAbsractMapper。许多Props如vtkActor和vtkVolume利用vtkAbstractMapper的子类来保存输入数据的引用以及提供真正的渲染功能。vtkPolyDataMapper是渲染多边形几何数据主要的Mapper类。而对于体数据,VTK提供了多种渲染技术。例如,vtkFixedPointVolumeRayCastMapper用来渲染vtkImageData类型的数据,vtkProjectedTetrahedraMapper则是用来渲染vtkUnstructuredGrid类型的数据。

vtkProperty和vtkVolumeProperty。某些Props采用单独的属性对象来存储控制数据外观显示的参数,这样不同的对象可以轻松的实现外观参数的共享。vtkActor利用vtkProperty对象存储外观(属性)参数,如颜色、不透明度、材质的环境光(Ambient)系数、散射光(Diffuse)系数和反射光(Specular)系数等。而vtkVolume则是采用vtkVolumeProperty对象来获取体对象的绘制参数,如将标量值映射为颜色和不透明度的传输函数(Transfer Function)【译者:也有译成“传递函数”】。另外,一些vtkMapper提供相应的函数设置裁剪面以便显示对象的内部结构。

vtkCamera。vtkCamera存储了场景中的摄像机参数,换言之,如何来“看”渲染场景里的对象,主要参数是摄像机的位置、焦点、和场景中的上方向向量。其他参数可以控制视图变换,如平行投影或者透视投影,图像的尺度或者视角,以及视景体的远近裁剪平面等。

vtkLight。vtkLight对象主要用于场景中的光照计算。vtkLight对象中存储了光源的位置和方向,以及颜色和强度等。另外,还需要一个类型来描述光源相对于摄像机的运动。例如,HeadLight始终位于摄像机处,并照向焦点方向;而SceneLight则始终固定在场景中的某个位置。

vtkRenderer。组成场景的对象包括Prop,Camara和Light都被集中在一个vtkRenderer对象中。vtkRenderer负责管理场景的渲染过程。一个vtkRenderWindow中可以有多个vtkRenderer对象,而这些vtkRenderer可以渲染在窗口中不同的矩形区域中(视口),甚至可以是覆盖的区域。

vtkRendererWindow。vtkRendererWindow将操作系统与VTK渲染引擎连接到一起。不同平台下的vtkRendererWindow子类负责本地计算机系统中窗口创建和渲染过程的管理。当使用VTK开发应用程序时,只需要使用平台无关的vtkRendererWindow类,程序运行时,系统会自动替换为平台相关的vtkRendererWindow子类。vtkRendererWindow中包含了vtkRenderer的集合,以及控制渲染的参数,如立体显示(Stereo)、反走样、运动模糊(Motion Blur)和焦点深度(FocalDepth)。

vtkRenderWindowInteractor。vtkRenderWindowInteractor负责监听鼠标、键盘和时钟消息,并通过VTK中的Command/Observer设计模式进行相应的处理。vtkInteractorStyle监听这些消息并进行处理以完成旋转、拉伸和放缩等运动控制。vtkRenderWindowInteractor自动建立一个默认的3D场景交互器样式(InteractorStyle),当然你也可以选择一个二维图像浏览的交互器样式,或者是创建自定义的交互器样式。

vtkTransform。场景中的许多对象,如Prop、光源Light、照相机Camera等都需要在场景中合理的放置,它们通过vtkTransform参数可以方便的控制对象的位置和方向。vtkTransform能够描述三维空间中的线性坐标变换,其内部表示为一个4×4的齐次变换矩阵。vtkTransform对象初始化为一个单位矩阵,你可以通过管线连接的方式将变换进行组合来完成复杂的变换。管线方式能够确保当其中任一个变换被修改时,其后续的变换都会相应的进行更新。

vtkLookupTable,vtkColorTransferFunction和vtkPiecewiseFunction。标量数据可视化经常需要定义一个标量数据到颜色和不透明度的映射。在几何面绘制中用不透明度定义表面的透明程度,而体绘制中不透明度表示光线穿透物体时不透明度沿着光线的累积效果,两者都需要定义不透明度的映射。对于几何渲染可以使用vtkLookupTable来创建映射,体绘制中需要使用vtkColorTransferFunction和vtkPiecewiseFunction来建立映射。

一个简单的例子。下面的例子(摘自./VTK/Examples/Rendering/CXX/Cylinder.cxx)演示了怎样利用上述对象来指定和渲染场景。

vtkCylinderSource*cylinder = vtkCylinderSource::New();
 
vtkPolyDataMapper*cylinderMapper = vtkPolyDataMapper::New();
cylinderMapper->SetInputConnection(cylinder->GetOutputPort());
 
vtkActor*cylinderActor = vtkActor::New();
cylinderActor->SetMapper(cylinderMapper);
 
vtkRenderer*ren1 = vtkRenderer::New();
ren1->AddActor(cylinderActor);
 
vtkRenderWindow*renWin = vtkRenderWindow::New();
renWin->AddRenderer(ren1);
 
vtkRenderWindowInteractor*iren = vtkRenderWindowInteractor::New();
iren->SetRenderWindow(renWin);
 
renWin->Render();
iren->Start();

例子中我们直接创建了一个vtkActor,vtkPolyDataMapper,vtkRenderer,vtkRendererWindow和vtkRendererWindowInteractor。注意,vtkProperty会由vtkActor自动创建,而vtkLight和vtkCamera会由vtkRenderer自动创建。


VTK用户指南 版本4.0 William J. Schroeder 1998-2000 第一部分 VTK 介绍 第1 欢迎 机构-----------------------------------------------------------------------------------------------8 怎样使用VTK----------------------------------------------------------------------------------8 附加资源-----------------------------------------------------------------------------------------8 第2 安装 2.1 概述-----------------------------------------------------------------------------------------------9 2.2 安装VTK到Windows9x/NT/ME/2000/XP------------------------------------------------9 二进制安装-------------------------------------------------------------------------------------9 源代码安装-------------------------------------------------------------------------------------9 2.3 安装VTK到Unix操作系统 源代码安装------------------------------------------------------------------------------------10 运行CMake------------------------------------------------------------------------------------11 编译源代码 建立VTK多平台 安装VTK 第3 系统概述 3.1 系统设计---------------------------------------------------------------------------------------12 图形模型--------------------------------------------------------------------------------------13 可视化模型-----------------------------------------------------------------------------------15 3.2 创建一个应用---------------------------------------------------------------------------------19 用户方法、对象和命令--------------------------------------------------------------------19 Tcl----------------------------------------------------------------------------------------------19 C++---------------------------------------------------------------------------------------------20 Java Phthon Visual Basic/COM/ActiveX 3.3 在两种语言间转换 第二部分 通过例子学习VTK 第4 基础 4.1 创建1个简单的模型-------------------------------------------------------------------------24 程序化源对象---------------------------------------------------------------------------------24 读取源对象------------------------------------------------------------------------------------26 4.2 使用VTK交互器-----------------------------------------------------------------------------27 vtk绘制窗口交互器 交互风格 4.3 滤波数据---------------------------------------------------------------------------------------29 4.4 控制相机---------------------------------------------------------------------------------------30 安装相机 简单操作方法 控制视角方向 透视与正交视 保存与恢复相机状态 4.5 控制光线---------------------------------------------------------------------------------------32 位置光 4.6 控制3D道具-----------------------------------------------------------------------------------32 指定vtk道具3D位置 演员 演员的详细级 装配 体 vtk装载3D道具 4.7 作用纹理---------------------------------------------------------------------------------------37 4.8 拾取---------------------------------------------------------------------------------------------38 vtk装配路线 例子 4.9 vtk坐标和坐标系---------------------------------------------------------------------------40 4.10 控制vtk演员2D----------------------------------------------------------------------------41 4.11 注释--------------------------------------------------------------------------------------------41 2D注释 3D注释和vtk跟踪 4.12 特殊绘图类-----------------------------------------------------------------------------------44 尺度棒 X-Y绘制 边界盒轴 标记数据 4.13 变换数据--------------------------------------------------------------------------------------48 高级变换 第5 可视化技术 5.1 可视化VTK数据集vtkDataSet(和子类) -------------------------------------------------50 使用数据属性进行工作 颜色映射 轮廓化 浮雕化 流线图 流线表面 剪裁 融合数据 附加数据 用另外一个尺度给等值面赋颜色 抽取单元格子集 抽取单元格作为多边形数据 5.2 可视化多边形数据---------------------------------------------------------------------------67 手工产生多边形数据 产生表面当量 十比一抽取 平滑网格 粘贴数据 产生纹理坐标 5.3 可视化结构网格-----------------------------------------------------------------------------74 手工产生结构化网格 抽取计算平面 结构网格子样化 5.4 可视化直线网格-----------------------------------------------------------------------------76 手工产生VTK直线网格 抽取计算平面 5.5 可视化非结构网格--------------------------------------------------------------------------77 手工产生VTK非结构网格 抽取部分网格 非结构网格轮廓化 第6 可视化图像和体数据 6.1 VTK结构化点的历史表示-----------------------------------------------------------------80 6.2 手工产生VTK图像数据-------------------------------------------------------------------80 6.3 抽取图像数据子样--------------------------------------------------------------------------81 6.4 基于尺度值的弯曲--------------------------------------------------------------------------83 6.5 图像显示--------------------------------------------------------------------------------------83 图像观察者 图像演员 6.6 图像源-----------------------------------------------------------------------------------------85 2D帆布图像源 3D椭圆体图像源 高斯图像源 网格图像源 噪声图像源 正弦曲线源 6.7 图像处理--------------------------------------------------------------------------------------88 梯度化 高斯平滑 直方图 图像逻辑 重新切片 6.8 体绘制-----------------------------------------------------------------------------------------92 一个简单的例子 为什么会有多种体绘制技术? 产生一个VTK体 使用片层化函数 使用颜色变换函数 在一个体属性中控制颜色和透明度 在一个体属性中控制阴影 产生一个体映射 裁剪一个体 粘贴一个体 对一个体应用3D纹理 控制标准编码 体素光线计算 2D纹理映射 VolumePro绘制硬件 速度和精确度交替使用 使用vtkLODProp3D改善性能 可行性/局限性技术 第7 建立模型 7.1 隐模型----------------------------------------------------------------------------------------114 定义隐函数 对隐函数进行抽样 7.2 挤压-------------------------------------------------------------------------------------------117 7.3 构建表面-------------------------------------------------------------------------------------119 Delaunay三角形化 高斯油彩 无组织点产生表面 第三部分 VTK研发者指南 第8 数据接口和其他 8.1 读入器----------------------------------------------------------------------------------------130 多边形数据读入器 图像和体素读入器 数据集读入器 结构化网格读入器 线性网格读入器 非结构化网格读入器 8.2 写入器----------------------------------------------------------------------------------------131 多边形数据读入器 图像和体素读入器 结构化网格读入器 线性网格读入器 非结构化网格读入器 8.3 输入者----------------------------------------------------------------------------------------132 8.4 输出者----------------------------------------------------------------------------------------132 8.5 创建硬拷贝----------------------------------------------------------------------------------132 保存图像 保存大(高分辨率)图像 8.6 产生动画(使用样条) -----------------------------------------------------------------------134 8.7 使用现场数据工作--------------------------------------------------------------------------136 第9 贡献编码 9.1 编码补偿--------------------------------------------------------------------------------------141 为VTK贡献编码的条件 编码风格 如何贡献编码 9.2 标准方法: 创建和消除对象---------------------------------------------------------------142 9.3 拷贝对象和受保护的方法------------------------------------------------------------------143 9.4 写一个VTK类: 综述-----------------------------------------------------------------------144 找到一个相似类 识别一个超类 单个类Per.h 文件 必需的方法 文档编码 使用SetGet宏 向VTK中添加类 9.5 对象工厂--------------------------------------------------------------------------------------145 综述 如何写一个工厂 如何安装一个工厂 例子工厂 第10 流水线执行管理 10.1 执行过程--------------------------------------------------------------------------------------151 概述和术语 更新信息通道 传播更新扩展通道 触发异步更新通道 更新数据通道 10.2 使用流---------------------------------------------------------------------------------------162 第11 VTK数据对象接口 11.1 数据组---------------------------------------------------------------------------------------166 方法 11.2 数据集---------------------------------------------------------------------------------------169 11.3 VTK数据集接口---------------------------------------------------------------------------170 方法 例子 11.4 VTK图像数据接口-----------------------------------------------------------------------174 方法 例子 11.5 VTK点集接口-----------------------------------------------------------------------------176 方法 例子 11.6 VTK结构化网格接口---------------------------------------------------------------------178 方法 例子 11.7 VTK线性网格接口-----------------------------------------------------------------------178 方法 例子 11.8 VTK多边形数据接口---------------------------------------------------------------------179 方法 例子 11.9 VTK非结构化网格接口-----------------------------------------------------------------184 方法 例子 11.10 单元格接口(VTK单元格子类) ------------------------------------------------------185 11.11 其他接口----------------------------------------------------------------------------------187 点 单元格数组 单元格类型 单元格连接 11.12 现场和属性数据接口------------------------------------------------------------------193 现场数据方法 数据集属性方法 第12 如何写一个过程方法 12.1 概述----------------------------------------------------------------------------------------196 永远不要修改输入数据 参考计数数据 使用Debug宏 回收/删除截入的内在 修改时间 过程事件和异常终止执行 12.2 如何写一个绘图过滤器---------------------------------------------------------------199 概述 简单过滤器 复杂过滤器和流水线执行 抽取绘图过滤器 程序过滤器 重载流水执行方法 12.3 如何写一个图像过滤器---------------------------------------------------------------210 实现一个图像过滤器 第13 用窗口系统集成 13.1 绘制窗口交互风格--------------------------------------------------------------------------216 13.2 GUI交互的总指导线------------------------------------------------------------------------217 13.3 X Window, Xt, and Motif--------------------------------------------------------------------221 13.4 MS Windows/Microsoft Foundation Classes---------------------------------------------226 13.5 Tcl/Tk-------------------------------------------------------------------------------------------227 13.6 Java 第14 编码资源 14.1 对象图表--------------------------------------------------------------------------------------230 基础 单元格 数据集 流水线 源 过滤器 映射器 图形 体绘制 成像 OpenGL绘制器 拾取 变换塔形结构 14.2 过滤器总结-----------------------------------------------------------------------------------237 可视化过滤器 映射者对象 演员对象 14.3 VTK文件格式--------------------------------------------------------------------------------244 二进制文件 数据集属性格式 例子 第15 光盘 15.1 源代码 15.2 例子代码 15.3 Window 9x/NT/ME/2000/XP 预编译二进制 15.4 数据 15.5 文档 15.6 退化测试图像 15.7 Kitware 应用
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值