第05章-可视化技术(3)

作者:www_doling_net

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

【本小节内容对应原书的第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 变换以及应用不同的纹理

发表评论

0个评论

我要留言×

技术领域:

我要留言×

留言成功,我们将在审核后加至投票列表中!

提示x

知识工程知识库已成功保存至我的图谱现在你可以用它来管理自己的知识内容了

删除图谱提示×

你保存在该图谱下的知识内容也会被删除,建议你先将内容移到其他图谱中。你确定要删除知识图谱及其内容吗?

删除节点提示×

无法删除该知识节点,因该节点下仍保存有相关知识内容!

删除节点提示×

你确定要删除该知识节点吗?