法向量计算
三维平面的法向量是指垂直于该平面的三维向量。曲面在某点P处的法向量为垂直于该点切平面的向量。对于一个网格模型,每个点和单元cell都可以计算一个法向量,在三维计算机图形学中法向量一个重要的应用是光照和阴影计算。在计算网格模型法向量时,单元cell法向量计算比较简单,可以通过组成每个单元cell的任意两条边的叉乘向量并归一化来表示。而对于点的法向量,则是由所有使用该点的单元法向量的平均值来表示。
VTK中计算法向量的Filter为vtkPolyDataNormals。该类针对单元为三角形或者多边形类型的vtkPolyData数据进行计算。由于法向量分为点法向量和单元法向量,可以通过函数SetComputeCellNormals和SetComputePointNormals来设置需要计算的法向量类型。默认情况下计算点法向量,关闭单元法向量计算。另外默认开始对锐边缘(sharp Edge)的处理。如果检测到存在锐边缘,则会将其分裂,因此模型的数据可能发生变化。可以通过SetSplitting函数关闭该功能。
示例演示
我们对比计算法向量前后模型显示 并符号化显示法向量。
/**********************************************************************
Copyright (c) Mr.Bin. All rights reserved.
For more information visit: http://blog.csdn.net/webzhuce
**********************************************************************/
#include <vtkSmartPointer.h>
#include <vtkActor.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkPolyDataReader.h>
#include <vtkFloatArray.h>
#include <vtkPointData.h>
#include <vtkPolyDataNormals.h>
#include <vtkGlyph3D.h>
#include <vtkArrowSource.h>
#include <vtkMaskPoints.h>
#include <vtkProperty.h>
//test data : ../data/fran_cut.vtk
int main(int argc, char *argv[])
{
vtkNew<vtkPolyDataReader> reader;
reader->SetFileName("E:/github/Study-VTK/data/fran_cut.vtk");
reader->Update();
vtkNew<vtkPolyDataNormals> normfilter;
normfilter->SetInputData(reader->GetOutput());
normfilter->SetComputePointNormals(1);
normfilter->SetComputeCellNormals(0);
normfilter->SetAutoOrientNormals(1);
normfilter->SetSplitting(0);
normfilter->Update();
vtkNew<vtkMaskPoints> mask;
mask->SetInputData(normfilter->GetOutput());
mask->SetMaximumNumberOfPoints(300);
mask->RandomModeOn();
mask->Update();
vtkNew<vtkArrowSource> arrow;
arrow->Update();
vtkNew<vtkGlyph3D> glyph;
glyph->SetInputData(mask->GetOutput());
glyph->SetSourceData(arrow->GetOutput());
glyph->SetVectorModeToUseNormal();
glyph->SetScaleFactor(0.01);
glyph->Update();
vtkNew<vtkPolyDataMapper> originmapper;
originmapper->SetInputData(reader->GetOutput());
vtkNew<vtkActor> originactor;
originactor->SetMapper(originmapper);
vtkNew<vtkPolyDataMapper> normedmapper;
normedmapper->SetInputData(normfilter->GetOutput());
vtkNew<vtkActor> normedactor;
normedactor->SetMapper(normedmapper);
vtkNew<vtkPolyDataMapper> glyphmapper;
glyphmapper->SetInputData(glyph->GetOutput());
vtkNew<vtkActor> glyphactor;
glyphactor->SetMapper(glyphmapper);
glyphactor->GetProperty()->SetColor(1., 0.,0.);
double originalviewport[4] = {0.0, 0.0, 0.33, 1.0};
double normviewport[4] = {0.33, 0.0, 0.66, 1.0};
double glphviewport[4] = {0.66, 0.0, 1.0, 1.0};
vtkNew<vtkRenderer> originalrenderer;
originalrenderer->SetViewport(originalviewport);
originalrenderer->AddActor(originactor);
originalrenderer->ResetCamera();
originalrenderer->SetBackground(1.0, 1.0, 1.0);
vtkNew<vtkRenderer> normedrenderer;
normedrenderer->SetViewport(normviewport);
normedrenderer->AddActor(normedactor);
normedrenderer->ResetCamera();
normedrenderer->SetBackground(1.0, 1.0, 1.0);
vtkNew<vtkRenderer> glyphRenderer;
glyphRenderer->SetViewport(glphviewport);
glyphRenderer->AddActor(glyphactor);
glyphRenderer->AddActor(normedactor);
glyphRenderer->ResetCamera();
glyphRenderer->SetBackground(1.0, 1.0, 1.0);
vtkNew<vtkRenderWindow> renderwindow;
renderwindow->AddRenderer(originalrenderer);
renderwindow->AddRenderer(normedrenderer);
renderwindow->AddRenderer(glyphRenderer);
renderwindow->SetSize(640, 320);
renderwindow->Render();
renderwindow->SetWindowName("PolyDataNormal");
vtkNew<vtkRenderWindowInteractor> renderwindowinteractor;
renderwindowinteractor->SetRenderWindow(renderwindow);
renderwindowinteractor->Initialize();
renderwindowinteractor->Start();
return EXIT_SUCCESS;
}
运行结果
左图1为原始图,左图2为计算法向量后。如图所示,加入法向量后,模型显示得更加平滑。
参考资料
- VTK图形图像开发进阶[M]