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

  • Post author:
  • Post category:其他




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

  1. 三维平面是指垂直有该平面的三维向量。曲面在某点P处的法向量为垂直于点切面的向量。对于一个网格模型,其每一个点和单元都可以计算一个法向量,在三维计算机图形学中法向量一个重要的应用是光照和阴影的计算。对于网格模型,模型是有一定的面片(单元来逼近的),面片越多,则模型越精细;反之,越粗糙。在计算网络模型的法向量时,单元法向量计算比较简单,可以通过组成每个单元的任意两条叉乘向量并归一化来表示。对于点的法向量是由所有使用该点的单元法向量的平均值来表示。
  2. VTK中计算法向量的Filter是vtkPolyDataNormals()。该类针对单元为三角形或多边形类型的vtkPolyData数据进行计算。由于法向量分为点法向量和单元法向量,可以通过函数SetComputeCellNormals()和SetComputeNormals()来设置需要计算的法向量类型。
  3. 默认情况下计算点法向量,关闭单元法向量。
  4. 在计算法向量时需要注意法向量的方向,因为对于同一个平面来讲,可以有两个方向完全相反的法向量。一般根据单元的点顺序确定,采用右手定则来定义一个平面的法向量方向。因此计算平面的法向量的时候,法向量的方向与单元的点的顺序密切相关。必须保持单元的点的顺序一致,才会得到合理的法向量。当然,函数SetConsistency()可以设置自动调整模型的单元法向量。SetAutoOrientNormals()可以设置自动调整法线的方向。



2.代码

#include "vtkAutoInit.h" 
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);

#include <vtkSmartPointer.h>
#include <vtkPolyDataReader.h> 
#include <vtkPolyDataNormals.h> //计算法向量
#include <vtkMaskPoints.h>
#include <vtkArrowSource.h>
#include <vtkGlyph3D.h>
#include <vtkPointData.h>
#include <vtkProperty.h>
//
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>

int main()
{
	vtkSmartPointer<vtkPolyDataReader> plyReader =
		vtkSmartPointer<vtkPolyDataReader>::New();
	plyReader->SetFileName("data/fran_cut.vtk");
	plyReader->Update();

	vtkSmartPointer<vtkPolyDataNormals> normFilter =
		vtkSmartPointer<vtkPolyDataNormals>::New();
	normFilter->SetInputData(plyReader->GetOutput());
	normFilter->SetComputePointNormals(1);//开启点法向量计算
	normFilter->SetComputeCellNormals(0); //关闭单元法向量计算
	normFilter->SetAutoOrientNormals(1);
	normFilter->SetSplitting(0);
	normFilter->Update();

	vtkSmartPointer<vtkMaskPoints> mask =
		vtkSmartPointer<vtkMaskPoints>::New();
	mask->SetInputData(normFilter->GetOutput());
	mask->SetMaximumNumberOfPoints(300);
	mask->RandomModeOn();
	mask->Update();

	vtkSmartPointer<vtkArrowSource> arrow =
		vtkSmartPointer<vtkArrowSource>::New();
	arrow->Update(); //一定要更新 否则数据没有添加进来,程序会报错

	vtkSmartPointer<vtkGlyph3D> glyph =
		vtkSmartPointer<vtkGlyph3D>::New();
	glyph->SetInputData(mask->GetOutput());
	glyph->SetSourceData(arrow->GetOutput());//每一点用箭头代替
	glyph->SetVectorModeToUseNormal();//设置向量显示模式和法向量一致
	glyph->SetScaleFactor(0.01); //设置伸缩比例
	glyph->Update();

	vtkSmartPointer<vtkPolyDataMapper> mapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	mapper->SetInputData(plyReader->GetOutput());
	vtkSmartPointer<vtkPolyDataMapper> normMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	normMapper->SetInputData(normFilter->GetOutput());
	vtkSmartPointer<vtkPolyDataMapper> glyphMapper =
		vtkSmartPointer<vtkPolyDataMapper>::New();
	glyphMapper->SetInputData(glyph->GetOutput());

	vtkSmartPointer<vtkActor> actor =
		vtkSmartPointer<vtkActor>::New();
	actor->SetMapper(mapper);
	vtkSmartPointer<vtkActor> normActor =
		vtkSmartPointer<vtkActor>::New();
	normActor->SetMapper(normMapper);
	vtkSmartPointer<vtkActor> glyphActor =
		vtkSmartPointer<vtkActor>::New();
	glyphActor->SetMapper(glyphMapper);
	glyphActor->GetProperty()->SetColor(1, 0, 0);

	double origView[4] = { 0, 0, 0.33, 1 };
	double normView[4] = { 0.33, 0, 0.66, 1 };
	double glyphView[4] = { 0.66, 0, 1, 1 };
	vtkSmartPointer<vtkRenderer> origRender =
		vtkSmartPointer<vtkRenderer>::New();
	origRender->SetViewport(origView);
	origRender->AddActor(actor);
	origRender->SetBackground(1, 0, 0);
	vtkSmartPointer<vtkRenderer> normRender =
		vtkSmartPointer<vtkRenderer>::New();
	normRender->SetViewport(normView);
	normRender->AddActor(normActor);
	normRender->SetBackground(0, 1, 0);
	vtkSmartPointer<vtkRenderer> glyphRender =
		vtkSmartPointer<vtkRenderer>::New();
	glyphRender->SetViewport(glyphView);
	glyphRender->AddActor(glyphActor);
	glyphRender->AddActor(normActor);
	glyphRender->SetBackground(0, 0, 1);

	vtkSmartPointer<vtkRenderWindow> rw =
		vtkSmartPointer<vtkRenderWindow>::New();
	rw->AddRenderer(origRender);
	rw->AddRenderer(normRender);
	rw->AddRenderer(glyphRender);
	rw->SetWindowName("Calculating Point Norm & Cell Norm");
	rw->SetSize(960, 320);
	rw->Render();

	vtkSmartPointer<vtkRenderWindowInteractor> rwi =
		vtkSmartPointer<vtkRenderWindowInteractor>::New();
	rwi->SetRenderWindow(rw);
	rwi->Initialize();
	rwi->Start();

	return 0;
}



运行截图

在这里插入图片描述



3.关于类vtkGlyph3D

为每个输入点拷贝相应的方向和伸缩比例的轮廓几何体

vtkGlyph3D是一个过滤器,当拷贝几何体到每个输入时,它起到滤波的作用.glyph从过滤输入源中以多边形数据定义,glyph根据输入的矢量和法向量来确定方向,根据伸缩数据和矢量的大小来确定伸缩比例。当plygh较多时,可能通过对象源与其相应的定义信息来创建glyph表。.glyph表可以通过伸缩量或矢量大小来索引相应的glyph对象。

要使用VTKGlyph3D对象,我们首先需要提供一个输入集和对象源来定义glyph。然后决定是否glyph进行伸缩,以及怎样对其进行伸缩,接下来决定是否对glyph设置方向,以及如何根据矢量及法向量来设置它,最终决定我们是glyph表还是仅仅是单一的glyph。如果使用了glyph表,我们还需要考虑相应的索引值。

vtkGlyph3D实际上是一个符号化的算法工具,可以使用一个源(如球体)为输入数据集的每一个点生成一个符号,并且可以设置符号的方向以及缩放比例,简单来说就是对于你想关注的数据点添加符号标注,符号的样式由自己指定。比如有一个曲面数据,希望将曲面数据的每一点都用椎体标注出来并且椎体的方向表示法向量方向,这时候就可以使用vtkGlyph3D.



版权声明:本文为m0_45306991原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。