VTK_Learning_圖形基本操作進階_法向量計算

1.點法向量和單元法向量

三維平面的法向量是指垂直於該平面的三維向量。曲面在某點P處的法向量爲垂直於該點切平面的向量。對於一個網格模型,其每一個點和單元都可以計算一個法向量,在三維計算機圖形學中法向量一個重要應用是光照和陰影計算。對於網格模型,模型是有一定數量的面片(單元)來逼近的,面片越多,則模型越精細;反之,則越粗糙。在計算網格模型的法向量時,單元法向量計算比較簡單,可以通過組成每個單元的任意兩條邊的叉乘向量並歸一化來表示。而,對於點的法向量,則是由所有使用該點的單元法向量的平均值來表示。
VTK中計算法向量的Filter是vtkPolyDataNormals()。該類針對單元爲 三角形或者多邊形類型的vtkPolyData數據進行計算。由於法向量分爲點法向量和單元法向量,可以通過函數SetComputeCellNormals()和SetComputePointNormals()來設置需要計算的法向量類型。
默認情況下計算點法向量,關閉單元法向量計算。
示例演示了一個vtkPolyData模型的點法向量和單位法向量的計算:
 

#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
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("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;
}

輸出結果如下圖所示:

在計算法向量時需要注意一個問題,即法向量的方向。因爲對於同一個平面來講,可以有兩個方向完全相反的法向量。一般是根據單元的點的順序確定,採用右手定則來定義一個平面的法向量方向。因此計算平面方向量的時候,法向量的方向與單元的點的順序密切相關。必須保持單元的點順序一致,纔會得到合理的法向量。當然,函數SetConsistency()可以設置自動調整模型的單元法向量。SetAutoOrientNormals()可以設置自動調整法線的方向
 

 2.關於類vtkGlyph3D

詳細描述:爲每個輸入點拷貝相應方向和伸縮比例的輪廓幾何體
vtkGlyph3d是一個過濾器,當拷貝幾何體到每個輸入點時,它起到濾波作用.glyph從過濾輸入源中以多邊形數據形式定義,glyph根據輸入的矢量和法向量來確定方向,根據伸縮數據和矢量大小來確定伸縮比例.當glyph較多時,可能通過對象源與其相應的定義信息來創建glyph表.glyph表可以通過伸縮值或矢量大小來索引相應的gpyph對象.
要使用vtkGlyph3D對象,我們首先需要提供一個輸入集和一個對象源來定義ghyph.然後決定是否對ghyph進行伸縮,以及怎樣對其進行伸縮,接下來決定是否對glyph設置方向,以及如何根據矢量及法向量來設置它,最終決定我們是用glyph表還是僅僅是單一的ghyph.如果使用了glyph表,我們還需要考慮相應的索引值.

vtkGlyph3D 實際上是一種符號化的算法工具,可以使用一個源(如球體)爲輸入數據集的每一個點生成一個符號,並且可以設置符號的方向以及縮放比例,簡單點說就是對於你想關注的數據點添加符號標註,符號的樣式由自己指定。比如你有一個曲面數據,希望將曲面數據的每個點都用錐體標註出來並且錐體的方向表示該點的法向量方向,這個時候就可以使用vtkGlyph3D。
 

3.本例的注意事項與經驗談 

注意算法執行之後,要注意及時更新,Update()一下!!! 

4. 符號化Glyphing再談

前文提到一個事,就是用符號化操作顯示單元的法向量。
模型的法向量數據是向量數據,因此法向量不能像前面講到的通過顏色映射來顯示。但是可以通過符號化(Glyphing)技術將法向量圖形化顯示。Glyphing是一種基於圖形的可視化技術,這些圖像可以是簡單的基本圖形,如具有方向的椎體,也可以是更加複雜的圖像。VTK中就是應用vtkGlyph3D類實現該功能的,並且可以支持Glyphing圖形的縮放、着色、設置空間姿態等。使用該類時,需要接受兩個輸入:一個是需要顯示的幾何數據點集合;另一個是Glyph圖形數據,爲vtkPolyData數據。
                

由於讀入的模型數據比較大,點比較多,因此使用vtkMaskPoints類採樣部分數據,該類保留輸入數據中的點數據及其屬性,並支持點數據的採樣。爲了減小計算量,隨機採樣了300個點做Glyphing顯示。將其輸出作爲vtkGlyph3D的輸入數據,而SetSourceData()設置了一個VTKArrowSource數據作爲源數據,這樣的效果是在輸入數據的每一個點處會顯示一個Glyph圖形,這裏我選用的就是箭頭圖形。vtkGlyph3D::SetVectorModeToUseNormal()指定要使用法向量數據來控制Glyph圖形方向。vtkGlyph3D::SetScaleFactor()則控制Glyph圖形的大小。
 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章