VCG lib提供了很多对mesh进行编码的方式,最常见的就是由一个顶点(vertices )集合和一个三角形(triangles )集合构成,(即三角形构成三角形网格,四面体构成四面体网格)。如下面这行代码就是VCG中定义mesh类型的一个例子:
class MyMesh : public vcg::tri::TriMesh< std::vector , std::vector , std::vector > {};
其中vcg::tri::TriMesh是三角形网格的基本类型,结合如下模板参数进行具体定义:
也就是说,定义一个网格类型的时候,我们只需要继承vcg::tri::TriMesh,并提供包含编码网格元素的容器即可。在下面这个例子中,我们仍然使用元素类型为MyEdge(顾名思义,就是我们自定义的边的类型)的vector来表示边的集合。注意,VCG中并没有预先定义一个顺序来传递顶点,面,边容器参数,也就是说我们上面这样写只是惯例而已,也可以不按照这个顺序来传递参数。
#include
#include
class MyVertex; class MyEdge; class MyFace;
struct MyUsedTypes : public vcg::UsedTypes ::AsVertexType,
vcg::Use ::AsEdgeType,
vcg::Use ::AsFaceType>{};
class MyVertex : public vcg::Vertex< MyUsedTypes, vcg::vertex::Coord3f, vcg::vertex::Normal3f, vcg::vertex::BitFlags >{};
class MyFace : public vcg::Face< MyUsedTypes, vcg::face::FFAdj, vcg::face::VertexRef, vcg::face::BitFlags > {};
class MyEdge : public vcg::Edge< MyUsedTypes> {};
class MyMesh : public vcg::tri::TriMesh< std::vector , std::vector , std::vector > {};
其中,对vertex、edge、face类型的理解是深入使用VCG lib的关键点。无论是vertex、edge、face还是tetrahedron都是用户自定义的包含一系列特性的集合(collection)。举个例子,你可能期望vertex中包含vertex的(x,y,z)坐标,但是对于该vertex处的surface normal和color等有时候需要,有时候又不需要。VCG lib就为我们提供了十分便捷优雅的方式来定义需要存储在vertex、face、edge种的一些特性,如下面这个例子就按照复杂度递增的方式展示了如何有效的定义MyVertex:
#include <vcg/complex/complex.h>
class MyVertex; class MyEdge; class MyFace;
struct MyUsedTypes : public vcg::UsedTypes<vcg::Use<MyVertex> ::AsVertexType,
vcg::Use<MyEdge> ::AsEdgeType,
vcg::Use<MyFace> ::AsFaceType>{};
class MyVertex0 : public vcg::Vertex< MyUsedTypes, vcg::vertex::Coord3f, vcg::vertex::Normal3f >{};
class MyVertex1 : public vcg::Vertex< MyUsedTypes, vcg::vertex::Coord3f, vcg::vertex::Normal3f, vcg::vertex::BitFlags >{};
class MyVertex2 : public vcg::Vertex< MyUsedTypes, vcg::vertex::Coord3f, vcg::vertex::Color4b, vcg::vertex::CurvatureDirf,
vcg::vertex::Qualityf, vcg::vertex::Normal3f, vcg::vertex::BitFlags >{};
定义的三个顶点类型分别存储了如下信息:
vcg::Vertex是VCG中vertex的基类,vcg::UsedTypes声明了mesh定义中使用的vertex、face、edge等类型。这其实是我们自定义的实体类型(MyVertex,MyEdge,MyFace和在mesh定义中使用的一些其他类)之间的一个映射,或者说这就是一个中间层吧,这样可以给予开发人员更大的灵活性(题外话,不是有大牛说过吗:计算机中的任何问题都可以通过增加一层来解决。这儿的思路是一致的)。还有些其他的属性(components)是为一些简单的几何类型开发的,在vcg/simplex文件夹中,完整的列表可以参看 Vertex Components, Edge Components 和Face Components的官网页面。我们可以在利用这些成分来组装我们需要的vertex/edge/face,进行构建完整的mesh类型。下面是一个完整的例子:
#include
#include
// io
#include
#include
class MyVertex; class MyEdge; class MyFace;
struct MyUsedTypes : public vcg::UsedTypes ::AsVertexType,
vcg::Use ::AsEdgeType,
vcg::Use ::AsFaceType>{};
class MyVertex : public vcg::Vertex< MyUsedTypes, vcg::vertex::Coord3f, vcg::vertex::Normal3f, vcg::vertex::BitFlags >{};
class MyFace : public vcg::Face< MyUsedTypes, vcg::face::FFAdj, vcg::face::VertexRef, vcg::face::BitFlags > {};
class MyEdge : public vcg::Edge< MyUsedTypes> {};
class MyMesh : public vcg::tri::TriMesh< std::vector , std::vector , std::vector > {};
int main(int argc, char **argv)
{
if (argc < 2)
{
printf("Usage trimesh_base \n" );
return -1;
}
MyMesh m;
if (vcg::tri::io::ImporterOFF::Open(m, argv[1]) != vcg::tri::io::ImporterOFF::NoError)
{
printf("Error reading file %s\n", argv[1]);
exit(0);
}
vcg::tri::RequirePerVertexNormal(m);
vcg::tri::UpdateNormal::PerVertexNormalized(m);
printf("Input mesh vn:%i fn:%i\n", m.VN(), m.FN());
printf("Mesh has %i vert and %i faces\n", m.VN(), m.FN());
return 0;
}
注意:vcg::face::VertexRef 是存储了三个指向mesh中vertex的指针。