1. VCG Libary是Visulization and Computer Graphics Libary(可視化與計算機圖形學庫)的縮寫,是一個開源的C++模板庫,用於三角網格和四面體網格的控制、處理和OpenGL顯示。其中包含了超過100 000行的代碼。基於該庫,Visual Computing Lab開發了幾個著名的工具,如metro和MeshLab。
VCG Libary是專門為處理三角網格而設計的,庫很大,且提供了許多最先進的處理網格的功能,如:
*基於邊坍塌(edge-collapse)二次誤差的高質量網格簡化(simplfication);*高效的空間檢索數據結構(uniform grids, hashed grids, kdtree, ...);*先進的網格平滑和光順算法;*曲率計算;*紋理坐標優化;*Hausdorff距離計算;*測地路徑;*網格修復能力*等直面抽取和前沿的網格划分算法;*泊松圓盤采樣和其他的網格點采樣算法;*細分曲面。
VCG Lib的大部分由頭文件組成,下載后,將文件解壓到一個vcglib文件夾中,然后將vcglib文件夾放到你的編譯器的“include”目錄中。然后使用時,只要包含其中需要的文件即可。
同上圖,vcglib文件夾中,總共包含5個子文件夾:
*vcg:這是整個庫的核心,其中定義了所有的算法和數據結構。該部分所有的C++代碼都是STL支持的普通數據結構和算法,不包含任何其它標准庫之外的庫,而且可以發現,該部分只包含頭文件(.h);
*wrap:這里包含一些針對特定需求/上下文/庫的VCG概念的封裝。例如,所有的用於計算機硬盤上很多格式的網格數據的導入和導出;用OpenGL渲染三角形網格的代碼;普通GUI工具如跟蹤球,等等;
*apps:這個文件夾包含一些用VCG Lib開發的命令行程序應用。很多例子都能在MeshLab中找到,apps/simple文件夾包含了這些程序的一個基礎的子集,是一個初學者很好的入口點;
*docs:文檔(包括這個教程)
*eigenLib:線性代數的eigen庫最近的穩定版本的一個副本(相當於就是借用第三方庫了),VCGLib中的高級矩陣操作都是基於這個庫的。
需要說明的是, FFp(i)指向一個鄰接面。如果是下圖中的non-manifld 邊的情況,(奇異邊)則在一邊上有多余兩個面。這看起來在VCG中沒有支持。圖中頂點編號從0到2,以逆時針順序編號,邊i(i=0..2)的兩個端點分別為i和(i+1)%3,因此圖中面f0和面f1的公共邊對f0而言是0邊,對f1而言是1邊。
對於面f的每個邊i,vcg::face::FFAdj存儲以下信息:
- FFp(i):指向共享邊i的面的指針,若i是border,則該指針指向自己;
- FFi(i):在指向的面中i的索引。在共享邊的面中的索引。
例如在上圖中,有:
- f1->FFp(1) == f0
- f1->FFi(1) == 0
- f0->FFp(0) == f1
- f0->FFi(0) == 1
bool IsManifold(MyFace *f,int e) { return (f0 == f0->FFp(0)->FFp(f0->FFi(0)))}
Pos關系
三角網格中,Pos為一三元組,pos = {v,e,f},e是f的邊,v是e的端點。
下圖以小三角形的形式顯示了三角網格中的一些pos,在每個面中,每個小三角形指向一個頂點,倚靠一條邊,且在一個三角形面片中。
這樣就能保證任意給定一個pos c,若只改變c的三元組的一個分量,能夠唯一確定一個鄰居pos。
C2與C1,的Pos只有Vertex Component不同,即 C2 = FlipV(C1)

c2 = FlipV(c1),定點分量不同,即換頂點則在同一個三角形中同一條邊的另一個定點。 c0 = FlipE(c1),邊分量不同,即換邊則在同一個三角形中同一個定點的另一個邊。 c3 = FlipF(c0), 面分量不同,即換面則通過邊臨街另一個面。 CCW around v,(逆時針旋轉V) c4 = FlipE(FlipF(c0)),即C0換面換邊后為C4 c5 = FlipE(FlipF(c4)),即C4換面換邊后C5 Bounce(彈跳,遇到邊界情況) c6 = FlipE(FlipF(c5)),遇到邊界后彈回 CW around v (順時針旋轉V) c3 = FlipE(FlipF(c6)) c1 = FlipE(FlipF(c3)) Bounce(彈跳) c0 = FlipE(FlipF(c1)),遇到邊界彈回
當兩個flip嵌套操作的時候,根據pos與面的關系,可以實現順時針或逆時針的pos轉換。並且由於面-面鄰接關系的定義方式,當pos在border上的時候,FlipF操作會返回到pos本身所在的面。
VCG庫中廣泛使用成對的flip,mannifold定點的相鄰的ring環。
下面的例子使用pos來迭代一個點的周圍相關性。
sf/apps/sample/trimesh_pos_demo/trimesh_pos_demo.cpp #include <vcg/simplex/face/pos.h> // include the definition of pos ...includes to define your mesh type class MyVertex: ... class MyFace: public vcg::FaceSimp2<MyVertex,MyEdge,MyFace, vcg::face::VertexRef, vcg::face::FFAdj>{}; void OneRingNeighborhood( MyFace * f) { MyVertex * v = f->V(0); MyFace* start = f; vcg::face::Pos<MyFace> p(f,0,v);// constructor that takes face, edge and vertex do { p.FlipF(); p.FlipE(); }while(p.f!=start); }
注意:
(1)使用屬性vcg::vertex::VFAdj屬性,可以關聯的頂點指針指向面。(2)如果定點再邊界上,則上述方法行不通。即從C4開始,將會找到C5,C6,C3,即C3余C4在同一個面中。但是,如果遇到邊界,則會“彈”回來,即在這個圖中,可能會得到C5,C6,C3, C1,C0, C4的序列,這或許不能夠完成對一個定點的便利序列。
VCG提供以下的方法解決
Jumping Pos
Jumping Pos類似Pos,但在遇到border的時候不會反彈回去,而是跨到下一個border-face上去。下面這個例子中,上圖中的p會從f0跨到f2。
sf/apps/sample/trimesh_pos_demo/trimesh_pos_demo.cpp #include <vcg/simplex/face/jumping_pos.h> // include the definition of jumping pos //...includes to define your mesh type //class MyVertex: ... class MyFace: public vcg::FaceSimp2<MyVertex,MyEdge,MyFace, vcg::face::VertexRef,vcg::face::FFAdj>{}; void OneRingNeighborhoodJP( MyFace * f) { MyVertex * v = f->V(0); MyFace* start = f; vcg::face::JumpingPos<MyFace> p(f,0,v);// constructor that takes face, edge and vertex do { p.NextFE(); }while(p.f!=start); }
2. VF Adjacency(頂點-面, Vertex-Face 鄰接關系)
VCG lib中,頂點與面之間也實現了鄰接關系,即給定一個頂點v,可以找出所有與其關聯的面。
設v_star = (f0,f1,f2,…,fk)為一個列表,該列表中的元素都是與頂點v關聯的面。可以通過以下屬性索引v_star:
- vcg::vertex::VFAdj:這是一個頂點的屬性,包含了指向f0的指針
- vcg::face::VFAdj:這是面的屬性,該面三個頂點中的每一個頂點都包含了指向v_star列表中下一個面的指針

這兩個屬性不單是指針,他們同樣包含在指向面中定點的索引,和vcg::face::FFAdj同樣的效果。如上圖展示了實際的例子,與Face-Face adjacent相似,需要使用vcg::tri::UpdateTopology::VertexFace(MeshType& m)來初始化。
Vertex的VF鄰接關系
v.VFp() == f2 頂點的VFp是一個指針,指向此定點關聯的面的列表的第一個面。 v.VFi() == 0 定點的VFi是一個索引值,是所指向的面中的定點所在的序號
face的VF鄰接關系,即,面中的指定索引值i頂點,其所對應的鄰接面的序列的首個面的指針 f2->VFp(0) == f3 ,即f2面中的0索引定點,其所對應的臨界面的序列的首個面的指針,即面f3 f2->VFi(0) == 1 ,即f2面中的0索引點,其再所對應的鄰接面的首個面中的相應的該(本身)定點所在的序號。 f3->VFp(1) == f1 f3->VFi(1) == 2 f1->VFp(2) == f0 f1->VFi(2) == 2 f0->VFp(2) == NULL f0->VFi(2) == -1
VFIterator
VFIterator是一個簡單的迭代器,來遍歷一個頂點的所有鄰接三角形面,通過使用VFAdjacency屬性。其用法如下圖:
sf/apps/sample/trimesh_pos_demo/trimesh_vfiter_demo.cpp #include <vcg/simplex/face/pos.h> // include the definition of VFIterator //...includes to define your mesh type class MyVertex: public vcg::VertexSimp2<MyVertex,MyEdge,MyFace, vcg::vertex::VFAdj /*,... other attributes*/ >{}; class MyFace: public vcg::FaceSimp2<MyVertex,MyEdge,MyFace, vcg::face::VertexRef,vcg::face::VFAd>{}; void OneRingNeighborhoodVF( MyVertex * v) { vcg::face::VFIterator<MyFace> vfi(v); //initialize the iterator tohe first face for(;!vfi.End();++vfi) { MyFace* f = vfi.F(); // ...do something with face f } }
Stars and Rings
端點頂點的face和vertices集合,可以使用以下方式函數:
- vcg::face::VFOrderedStarFF
- vcg::face::VVStarVF
- vcg::face::VFStarVF
- vcg::face::VFExtendedStarVF
- vcg::face::EFStarFF
面面鄰接與點面鄰接中的少量的面的處理
以下陳述可以避免“沖突”,來幫助選擇最適合的臨街對象
endl;
