VTK 图形基本操作进阶_法向量计算

1.点法向量和单元法向量

三维平面的法向量是指垂直于该平面的三维向量。曲面在某点P处的法向量为垂直于该点切平面的向量。对于一个网格模型,其每一个点和单元都可以计算一个法向量,在三维计算机图形学中法向量一个重要应用是光照和阴影计算。对于网格模型,模型是有一定数量的面片(单元)来逼近的,面片越多,则模型越精细;反之,则越粗糙。在计算网格模型的法向量时,单元法向量计算比较简单,可以通过组成每个单元的任意两条边的叉乘向量并归一化来表示。而,对于点的法向量,则是由所有使用该点的单元法向量的平均值来表示。
VTK中计算法向量的Filter是vtkPolyDataNormals()。该类针对单元为 三角形或者多边形类型的vtkPolyData数据进行计算。由于法向量分为点法向量和单元法向量,可以通过函数SetComputeCellNormals()和SetComputePointNormals()来设置需要计算的法向量类型。
默认情况下计算点法向量,关闭单元法向量计算。
示例演示了一个vtkPolyData模型的点法向量和单位法向量的计算:
  1 #include <vtkAutoInit.h>
  2 VTK_MODULE_INIT(vtkRenderingOpenGL);
  3 VTK_MODULE_INIT(vtkInteractionStyle);
  4  
  5 #include <vtkSmartPointer.h>
  6 #include <vtkPolyDataReader.h> 
  7 #include <vtkPolyDataNormals.h> //计算法向量
  8 #include <vtkMaskPoints.h>
  9 #include <vtkArrowSource.h>
 10 #include <vtkGlyph3D.h>
 11 #include <vtkPointData.h>
 12 #include <vtkProperty.h>
 13 //
 14 #include <vtkPolyDataMapper.h>
 15 #include <vtkActor.h>
 16 #include <vtkRenderer.h>
 17 #include <vtkRenderWindow.h>
 18 #include <vtkRenderWindowInteractor.h>
 19  
 20 int main()
 21 {
 22     vtkSmartPointer<vtkPolyDataReader> plyReader =
 23         vtkSmartPointer<vtkPolyDataReader>::New();
 24     plyReader->SetFileName("fran_cut.vtk");
 25     plyReader->Update();
 26  
 27     vtkSmartPointer<vtkPolyDataNormals> normFilter =
 28         vtkSmartPointer<vtkPolyDataNormals>::New();
 29     normFilter->SetInputData(plyReader->GetOutput());
 30     normFilter->SetComputePointNormals(1);//开启点法向量计算
 31     normFilter->SetComputeCellNormals(0); //关闭单元法向量计算
 32     normFilter->SetAutoOrientNormals(1);
 33     normFilter->SetSplitting(0);
 34     normFilter->Update();
 35  
 36     vtkSmartPointer<vtkMaskPoints> mask =
 37         vtkSmartPointer<vtkMaskPoints>::New();
 38     mask->SetInputData(normFilter->GetOutput());
 39     mask->SetMaximumNumberOfPoints(300);
 40     mask->RandomModeOn();
 41     mask->Update();
 42  
 43     vtkSmartPointer<vtkArrowSource> arrow =
 44         vtkSmartPointer<vtkArrowSource>::New();
 45     arrow->Update(); //一定要更新 否则数据没有添加进来,程序会报错
 46  
 47     vtkSmartPointer<vtkGlyph3D> glyph =
 48         vtkSmartPointer<vtkGlyph3D>::New();
 49     glyph->SetInputData(mask->GetOutput());
 50     glyph->SetSourceData(arrow->GetOutput());//每一点用箭头代替
 51     glyph->SetVectorModeToUseNormal();//设置向量显示模式和法向量一致
 52     glyph->SetScaleFactor(0.01); //设置伸缩比例
 53     glyph->Update();
 54     
 55     vtkSmartPointer<vtkPolyDataMapper> mapper =
 56         vtkSmartPointer<vtkPolyDataMapper>::New();
 57     mapper->SetInputData(plyReader->GetOutput());
 58     vtkSmartPointer<vtkPolyDataMapper> normMapper =
 59         vtkSmartPointer<vtkPolyDataMapper>::New();
 60     normMapper->SetInputData(normFilter->GetOutput());
 61     vtkSmartPointer<vtkPolyDataMapper> glyphMapper =
 62         vtkSmartPointer<vtkPolyDataMapper>::New();
 63     glyphMapper->SetInputData(glyph->GetOutput());
 64  
 65     vtkSmartPointer<vtkActor> actor =
 66         vtkSmartPointer<vtkActor>::New();
 67     actor->SetMapper(mapper);
 68     vtkSmartPointer<vtkActor> normActor =
 69         vtkSmartPointer<vtkActor>::New();
 70     normActor->SetMapper(normMapper);
 71     vtkSmartPointer<vtkActor> glyphActor =
 72         vtkSmartPointer<vtkActor>::New();
 73     glyphActor->SetMapper(glyphMapper);
 74     glyphActor->GetProperty()->SetColor(1, 0, 0);
 75     
 76     double origView[4] = { 0, 0, 0.33, 1 };
 77     double normView[4] = { 0.33, 0, 0.66, 1 };
 78     double glyphView[4] = { 0.66, 0, 1, 1 };
 79     vtkSmartPointer<vtkRenderer> origRender =
 80         vtkSmartPointer<vtkRenderer>::New();
 81     origRender->SetViewport(origView);
 82     origRender->AddActor(actor);
 83     origRender->SetBackground(1, 0, 0);
 84     vtkSmartPointer<vtkRenderer> normRender =
 85         vtkSmartPointer<vtkRenderer>::New();
 86     normRender->SetViewport(normView);
 87     normRender->AddActor(normActor);
 88     normRender->SetBackground(0, 1, 0);
 89     vtkSmartPointer<vtkRenderer> glyphRender =
 90         vtkSmartPointer<vtkRenderer>::New();
 91     glyphRender->SetViewport(glyphView);
 92     glyphRender->AddActor(glyphActor);
 93     glyphRender->AddActor(normActor);
 94     glyphRender->SetBackground(0, 0, 1);
 95     
 96     vtkSmartPointer<vtkRenderWindow> rw =
 97         vtkSmartPointer<vtkRenderWindow>::New();
 98     rw->AddRenderer(origRender);
 99     rw->AddRenderer(normRender);
100     rw->AddRenderer(glyphRender);
101     rw->SetWindowName("Calculating Point Norm & Cell Norm");
102     rw->SetSize(960, 320);
103     rw->Render();
104     
105     vtkSmartPointer<vtkRenderWindowInteractor> rwi =
106         vtkSmartPointer<vtkRenderWindowInteractor>::New();
107     rwi->SetRenderWindow(rw);
108     rwi->Initialize();
109     rwi->Start();
110  
111     return 0;
112 }
输出结果如下图所示:

在计算法向量时需要注意一个问题,即法向量的方向。因为对于同一个平面来讲,可以有两个方向完全相反的法向量。一般是根据单元的点的顺序确定,采用右手定则来定义一个平面的法向量方向。因此计算平面方向量的时候, 法向量的方向与单元的点的顺序密切相关。必须保持单元的点顺序一致,才会得到合理的法向量。当然,函数SetConsistency()可以设置自动调整模型的单元法向量。SetAutoOrientNormals()可以设置自动调整法线的方向。

2.关于类vtkGlyph3D

详细描述:为每个输入点拷贝相应方向和伸缩比例的轮廓几何体
vtkGlyph3d是一个过滤器,当拷贝几何体到每个输入点时,它起到滤波作用.glyph从过滤输入源中以多边形数据形式定义,glyph根据输入的矢量和法向量来确定方向,根据伸缩数据和矢量大小来确定伸缩比例.当glyph较多时,可能通过对象源与其相应的定义信息来创建glyph表.glyph表可以通过伸缩值或矢量大小来索引相应的gpyph对象.
要使用vtkGlyph3D对象, 我们首先需要提供一个输入集和一个对象源来定义ghyph.然后决定是否对ghyph进行伸缩,以及怎样对其进行伸缩,接下来决定是否对glyph设置方向,以及如何根据矢量及法向量来设置它,最终决定我们是用glyph表还是仅仅是单一的ghyph.如果使用了glyph表,我们还需要考虑相应的索引值.
 
vtkGlyph3D 实际上是一种符号化的算法工具,可以使用一个源(如球体)为输入数据集的每一个点生成一个符号,并且可以设置符号的方向以及缩放比例, 简单点说就是对于你想关注的数据点添加符号标注,符号的样式由自己指定。比如你有一个曲面数据,希望将曲面数据的每个点都用锥体标注出来并且锥体的方向表示该点的法向量方向,这个时候就可以使用vtkGlyph3D。

3.本例的注意事项与经验谈

注意算法执行之后,要注意及时更新,Update()一下!!!
原文地址:https://www.cnblogs.com/ybqjymy/p/14241802.html