首页 > 代码库 > 第05章-可视化技术(3)
第05章-可视化技术(3)
【译者:这个系列教程是以Kitware公司出版的《VTK User’s Guide -11th edition》一书作的中文翻译(出版时间2010年,ISBN: 978-1-930934-23-8),由于时间关系,我们不能保证每周都能更新本书内容,但尽量做到一周更新一篇到两篇内容。敬请期待^_^。欢迎转载,另请转载时注明本文出处,谢谢合作!同时,由于译者水平有限,出错之处在所难免,欢迎指出订正!】
【本小节内容对应原书的第105页至第112页】
【本小节内容对应原书的第105页至第112页】
5.2 多边形数据可视化
多边形数据(vtkPolyData)是一种重要的可视化数据类型。因为它是图像硬件或者渲染引擎的几何接口。其他的数据必须转换为多边形数据才能被渲染,除了vtkImageData外。VtkImageData使用的时特别图像或者体绘制技术。可以参考104页“以多边形数据类型为输出提取单元”来了解怎样转换数据类型。
多边形数据主要由点和点集,直线和直线组合,三角形,四边形,多边形和三角形带组合而成。大部分接收vtkPolyData的Filter都会处理这些数据组合。当然也有一些Filter如vtkDecimatePro和vtkTubeFilter会只处理部分数据类型(三角网格和直线)。
手动创建vtkPolyData数据
多边形数据可以通过多种方式构造。通常需要创建一个vtkPoints来存储点集,然后创建4个vtkCellArrays来分别表示点,线,多边形和三角带连接。下面例子取自VTK/Examples/DataManipulation/Tcl/CreateStrip.tcl。它创建了一个具有一个三角形带的vtkPolyData数据。
vtkPoints points points InsertPoint 0 0.0 0.0 0.0 points InsertPoint 1 0.0 1.0 0.0 points InsertPoint 2 1.0 0.0 0.0 points InsertPoint 3 1.0 1.0 0.0 points InsertPoint 4 2.0 0.0 0.0 points InsertPoint 5 2.0 1.0 0.0 points InsertPoint 6 3.0 0.0 0.0 points InsertPoint 7 3.0 1.0 0.0 vtkCellArray strips strips InsertNextCell 8;#number of points strips InsertCellPoint 0 strips InsertCellPoint 1 strips InsertCellPoint 2 strips InsertCellPoint 3 strips InsertCellPoint 4 strips InsertCellPoint 5 strips InsertCellPoint 6 strips InsertCellPoint 7 vtkPolyData profile profile SetPoints points profile SetStrips strips vtkPolyDataMapper map map SetInput profile vtkActor strip strip SetMapper map [strip GetProperty] SetColor 0.3800 0.7000 0.1600
这里有另外一个C++例子来演示怎样创建一个立方体(VTK/Examples/DataManipulation/Cxx/Cube.cxx)。这次我们创建6个四边形和每个顶点对应的标量值。
int i; staticfloat x[8][3]={{0,0,0}, {1,0,0}, {1,1,0}, {0,1,0}, {0,0,1}, {1,0,1},{1,1,1}, {0,1,1}}; staticvtkIdType pts[6][4]={{0,1,2,3}, {4,5,6,7}, {0,1,5,4}, {1,2,6,5}, {2,3,7,6},{3,0,4,7}}; vtkPolyData *cube = vtkPolyData::New(); vtkPoints *points = vtkPoints::New(); vtkCellArray *polys = vtkCellArray::New(); vtkFloatArray *scalars = vtkFloatArray::New(); // Load the point, cell, and data attributes. for (i=0;i<8; i++) points->InsertPoint(i,x[i]); for (i=0; i<6;i++) polys->InsertNextCell(4,pts[i]); for (i=0;i<8; i++) scalars->InsertTuple1(i,i); // We now assign the pieces to the vtkPolyData. cube->SetPoints(points); points->Delete(); cube->SetPolys(polys); polys->Delete(); cube->GetPointData()->SetScalars(scalars); scalars->Delete();
vtkPolyData可以由点,线,多边形和三角形带的任意组合构建。同时,vtkPolyData支持一系列扩展的操作来对数据结构进行编辑和修改。参考345页“多边形数据”。
计算表面法向量
当你渲染多边形网格时,你可能会发现渲染图像中清晰的显示了网格面片(图5-10)。采用Gouraud着色技术可以提高渲染结果(见53页“Actor属性”)。然而Gouraud着色技术依赖于网格每个顶点的法向量。因此需要利用vtkPolyDataNoramals filter来计算网格顶点法向量。217页“Extrusion”、94页“Glyphing”和102页“用其他标量着色等值面”都是用了该类计算法向量。
图5-10 使用和不使用表面法向量的网格面片对比
该Filter有两个重要的参数,splitting和FeatureAngle。如果splitting开启,那么特征边被分裂(如果一条边任意一端的顶点法向与该边所成夹角大于或者等于特征角FeatureAngle的话,那么该边定义为特征边)。也就是沿着该条边复制顶点,网格在特征边的任意一边被分割。这样虽然产生了新的顶点,但是能够清晰的渲染尖锐角处。另外一个重要的参数是FlipNormals。调用函数FlipNormalsOn()将使法向量反向(同时多边形连接表也会反向)。
抽取(Decimation)
多边形数据,特别是三角形网格是很常用的图形数据格式。比如vtkContourFilter产生的结果就是三角形网格。但是这些三角形网格往往会比较大,因此在一些交互应用中难以快速的处理。抽取技术常被用来解决这个问题。抽取也被称作多边形消减,网格简化或者多分辨率建模。其在保持近似原始网格条件下对三角网格中的三角形数量进行消减。
VTK支持三种消减方法,vtkDecimatePro,vtkQuadricClustering和vtkQuadricDecimation。虽然每一种都有各自的优缺点,但在应用上基本都一致。
- vtkDecimatePro相对来说速度比较快,而且在消减过程中可以修改拓扑结构。它采用边塌陷方法来去除顶点和三角形。它的误差度量是基于到平面或者边的距离。该方法的一个优点是可以完成任意程度的消减,因为该算法一开始就将网格分裂为小的碎片来完成消减目的(如果允许拓扑修改的话)。
- vtkQuadricDecimation采用的Siggraph97论文“SurfaceSimplification Using Quadric Error Metrics”中提出的二次误差度量。它采用边塌陷方法来剔除顶点和三角面片。二次误差度量通常被认为是比较好的误差度量。
- vtkQuadricClustering是最快的方法。它的思想基于Siggraph2000中的论文“Out-of-Core Simplification of Large Polygonal Models”。它能够快速的消减大网格模型,并且支持网格片段消减(利用StartAppend(), Append()和EndAppend()方法)。这样可以避免读取整个模型到内存中。对于大网格模型,该方法有较好的效果;但是当网格变小时,三角化过程效果不是很好(需要结合其他的算法会有较理想的效果)。
下面是关于类vtkDecimatePro的一个应用实例。代码取自VTK/Examples/VisualizationAlgorithms/Tcl/deciFram.tcl(如图5-11)。
vtkDecimatePro deci deci SetInputConnection [fran GetOutputPort] deci SetTargetReduction 0.9 deci PreserveTopologyOn vtkPolyDataNormals normals normals SetInputConnection [deci GetOutputPort] normals FlipNormalsOn vtkPolyDataMapper franMapper franMapper SetInputConnection [normals GetOutputPort] vtkActor franActor franActor SetMapper franMapper eval [franActor GetProperty] SetColor 1.0 0.49 0.25
图5-11 三角网格面片经90%抽取后的效果对比(左为原始图,右为抽取后的图)
vtkDecimatePro有两个重要的参数:TargetReduction和PreserveTopology。TargetReduction是用户的消减量(例如0.9意味着我们希望减少网格中90%的面片。)根据你是否允许修改拓扑结构(PreserveTopologyOn/Off())来得到相应的消减结果。
最后注意的是消减filter的输入为三角形数据。如果你的是多边形数据,那么需要利用vtkTriangleFilter 来进行转换。
网格平滑(SmoothMesh)
多边形网格往往由于噪声或者过于粗糙,从而影响渲染的结果。例如,低分辨率数据的等值面会有走样的效果。数据平滑是处理这种问题的方法之一。平滑是通过改变顶点位置来减少曲面噪声数据的的过程。
VTK中提供了两种平滑对象:vtkSmoothPolyDataFilter和vtkWindowSincPolyDataFilter。两者中,vtkWindowSincPolyDataFilter处理效果最好,而且处理速度也较快。下面例子(代码来自VTK/Examples/VisualizationAlgorithms/Tcl/smoothFran.tcl)演示了怎样利用该平滑filter。该例与上节例子内容相同,只是多了一个平滑filter处理。图5-12显示了简化模型的平滑效果。
vtkDecimatePro deci deci SetInputConnection [fran GetOutputPort] deci SetTargetReduction 0.9 deci PreserveTopologyOn vtkSmoothPolyDataFilter smoother smoother SetInputConnection [deci GetOutputPort] smoother SetNumberOfIterations 50 vtkPolyDataNormals normals normals SetInputConnection [smoother GetOutputPort] normals FlipNormalsOn vtkPolyDataMapper franMapper franMapper SetInputConnection [normals GetOutputPort] vtkActor franActor franActorSetMapper franMapper eval [franActor GetProperty] SetColor 1.0 0.49 0.25
图5-12 多边形网格平滑(右图为平滑后的效果)
两种平滑Filter的使用方法类似。他们提供了一些函数来控制特征边或者边界处的平滑效果。可查阅在线文档或者*.h头文件了解相关信息。
数据裁剪(ClipData)
裁剪类似于切割(98页“切割”)利用一个隐函数来定义裁剪面。裁剪将多边形模型分解为片段,如图5-13所示。裁剪在裁剪面的任意一边将多边形几何体分解为单独的部分。如切割一样,裁剪可以设置一个裁剪值来定义隐式裁剪函数的值。
下例中利用一个平面来裁剪一个牛的三维多边形模型。切割值用来定义切割平面沿着法向量移动距离的大小,这样便可以在不同的位置对模型进行裁剪。代码取自(VTK/Examples/VisualizationAlgorithms/Tcl/ClipCow.tcl)。
vtkBYUReader cow cow SetGeometryFileName "$VTK_DATA_ROOT/Data/Viewpoint/cow.g" vtkPolyDataNormals cowNormals cowNormals SetInputConnection [cow GetOutputPort] vtkPlane plane plane SetOrigin 0.25 0 0 plane SetNormal -1 -1 0 vtkClipPolyData clipper clipper SetInputConnection [cowNormals GetOutputPort] clipper SetClipFunction plane clipper GenerateClipScalarsOn clipper GenerateClippedOutputOn clipper SetValue 0.5 vtkPolyDataMapper clipMapper clipMapper SetInputConnection [clipper GetOutputPort] clipMapper ScalarVisibilityOff vtkProperty backProp evalbackProp SetDiffuseColor $tomato vtkActor clipActor clipActorSetMapper clipMapper eval [clipActor GetProperty] SetColor $peacock clipActor SetBackfaceProperty backProp vtkPolyDataMapper restMapper restMapper SetInputConnection [clipper GetClippedOutputPort] restMapper ScalarVisibilityOff vtkActor restActor restActor SetMapper restMapper [restActor GetProperty] SetRepresentationToWireframe
图5-13 模型裁剪
GenerateClippedOutputOn()函数计算裁剪过程中被裁剪掉得数据。在该例中这部分数据采用线框方式显示。如果通过SetValue()函数改变了裁剪值,那么裁剪面将移动至初始裁剪面前或者后并且平行与初始裁剪面的位置。(同样改变vtkPlane的定义也可实现同样的效果。)
计算纹理坐标
常用的计算纹理坐标的Filter是vtkTextureMapToPlane,vtkTextureMapToCylinder和vtkTextureMapToSphere。他们分别基于平面,圆柱和球面坐标系计算纹理坐标。另外,vtkTransformTextureCoordinates通过平移和缩放纹理坐标在曲面上定义纹理映射。下例中演示了利用vtkTextureMapToCylinder来为一个由vtkDelaunay3D计算产生的不规则网格数据计算纹理坐标(参考218页“Delaunay Triangulation”)。完整代码可以参考VTK/Examples/VisualizationAlgorithms/Tcl/GenerateTextureCoords.tcl。
vtkPointSource sphere sphere SetNumberOfPoints 25 vtkDelaunay3D del del SetInputConnection [sphere GetOutputPort] del SetTolerance 0.01 vtkTextureMapToCylinder tmapper tmapper SetInputConnection [del GetOutputPort] tmapper PreventSeamOn vtkTransformTextureCoords xform xform SetInputConnection [tmapper GetOutputPort] xform SetScale 4 4 1 vtkDataSetMapper mapper mapper SetInputConnection [xform GetOutputPort] vtkBMPReader bmpReader bmpReaderSetFileName "$VTK_DATA_ROOT/Data/masonry.bmp" vtkTexture atext atext SetInputConnection [bmpReader GetOutputPort] atext InterpolateOn vtkActor triangulation triangulation SetMapper mapper triangulation SetTexture atext
该例中首先对一个单位球上的随机点进行三角剖分,并为三角网格计算纹理坐标。接着在纹理坐标i-j方向上对纹理坐标进行缩放以便使纹理能够重复。最后读入纹理图像并指定到Actor上。
(注意,vtkDataSetMapper可以接收任意数据类型的输入。其内部vtkGeometryfilter对象将数据转换为多边形数据然后再传入到渲染引擎中。参考104页“以多边形数据为输出提取单元”)
如果需要深入学习纹理坐标,可以运行VTK/Examples/VisualizationAlgorithms/Tcl/TransformTexturecoords.tcl实例(如图5-14所示)。该例GUI可以选择多边形模型,纹理图像,纹理计算方法和纹理变换方法。
图5-14 变换以及应用不同的纹理