几个经典的数学库之一学习---VCGlib(2)
几个经典的数学库之一学习---VCGlib(2)
1. Optional Component(可选的组件)
有许多Vertex和Face的属性并不是一直都是必要的,如Face-Face的邻接关系。VCG库提供了一种可以指定可选组件的方法。如属性信息并不是静态保存在simplex(简素)中的,而是当被需要他们的时候,静态分配这些属性信息的。
定义使用这些组件,需要做以下两种事情: (1)使用在mesh的定义中使用经典的容器,从std::vector中继承 (2)在simplex的定义中使用指定的组分类型定义
当component被激活时,其能够被使用,即通过调用Enableing函数。VCG处理Optional Componnet采用两个机制:(1)Ocf(Optional component Fast),即使用指针对于每种“简素Simliex”,但是可以和non-optional 对象数据一样快。(2)Occ(Optional Component Compact),对于每个mesh,需要的内存空间非常小,但是这样的弊端是获取访问数据非常慢。
下面讨论两种方法。
Optional Component Fast
下面定义MyMesh,指定了定点和面的一些component。指定的属性vcg::vertex::InfoOcf 与 vcg::face::InfoOcf 是定点和面的第一个属性,并且我们使用vcg::vertex::vertex_Ocf 与 vcg::face::vectorOcf作为容器;
(www.cnblogs.com/icmzn提供)
class MyVertexOcf;
class MyFaceOcf;
struct MyUsedTypesOcf: public vcg::UsedTypes<
vcg::Use<MyVertexOcf>::AsVertexType,
vcg::Use<MyFaceOcf>::AsFaceType>{};
class MyVertexOcf : public vcg::Vertex< MyUsedTypesOcf,
vcg::vertex::InfoOcf, // <--- Note the use of the 'special' InfoOcf component
vcg::vertex::Coord3f, vcg::vertex::QualityfOcf,
vcg::vertex::Color4b, vcg::vertex::BitFlags,
vcg::vertex::Normal3f, vcg::vertex::VFAdjOcf >{};
class MyFaceOcf : public vcg::Face< MyUsedTypesOcf,
vcg::face::InfoOcf, // <--- Note the use of the 'special' InfoOcf component
vcg::face::FFAdjOcf, vcg::face::VFAdjOcf,
vcg::face::Color4bOcf, vcg::face::VertexRef,
vcg::face::BitFlags, vcg::face::Normal3fOcf > {};
// the mesh class must make use of the 'vector_ocf' containers instead of the classical std::vector
class MyMeshOcf : public vcg::tri::TriMesh< vcg::vertex::vector_ocf<MyVertexOcf>, vcg::face::vector_ocf<MyFaceOcf> > {};
在获取Optional Component中的数据是,需要首先调用EnalbeXX()来激活相应的可选属性。然后相应的属性可以被分配空间,并且获取。直到调用disAble()为止。
MyMeshOcf cmof;
assert(tri::HasFFAdjacency(cmof) == false);
cmof.face.EnableFFAdjacency();
assert(tri::HasFFAdjacency(cmof) == true);
在激活之前,获取的Componnent的数据,或者在关闭之后,相应的组件会抛出异常。
cmof.face.EnableNormal(); // remove this line and you will throw an exception for a missing 'normal' component
tri::UpdateNormal<MyMeshOcf>::PerVertexPerFace(cmof);
2. Bit Flags
对于mesh的每一种simplex(简素),都有一种BitFlags的组件,保存固定的32bit的矢量标识,用来分类判别的需要。可以使用下面相关的类:
- vcg::tri::UpdateFlags (defined in flag.h)
- vcg::tri::UpdateSelection (defined in selection.h)
IsD():删除标识
可以判定该简素对象是否被删除。因为mesh中的元素可以被Allocating和Deleting网格。
IsB(),ClearB(),SetB():边界标识
可以判定顶点或者面是否再边界上。这些bit不是默认计算获取,他们是连同拓扑一起或者不是一起计算后的结果。如果FF拓扑计算这些标识效率高。
这些标识的关联是,有许多的算法需要边界特征来计算是高效率的。而没有必要对整个FF拓扑结构进行全部运算。
IsS(), ClearS(), SetS():选择标识
IsV(), ClearV(), SetV():访问标识
访问标识,对于一些算法是很有用的。你不应该依赖这些标识的状态,或者人工设置当前的状态,因为任何的一种算法都可以清理这些标识以及更新这些标识。
使用tri::UpdateFlags<YourMeshClass>::VertexClearV(yourMesh),来清理所有的bits
用户自定义标识
如果用户定义私有的标识,通过NewBigFlag()函数方式,可以返回一个Mash(掩码)用来设置,清理,测试针对特定big。下面例子分配三个bit,对每一个face然后清理他们。
int e0bit = MyFace::NewBitFlag();
int e1bit = MyFace::NewBitFlag();
int e2bit = MyFace::NewBitFlag();
int ebit[3] = {e0bit,e1bit,e2bit};
for(MyMesh::FaceIterator fi=m.face.begin();fi!=m.face.end();++fi)
for(int i=0;i<3;++i)
(*fi).ClearUserBit(ebit[i]);
通过使用tri::UpdateFlags<YourMeshClass>::FaceClear(yourMesh,e0bit|e1bit|e2bit);来清理所有mesh的定点或者面的指定bit
3. Allocating and Deleting mesh elements
Creating elements
通过AddVertices and AddFaces functions 来给指定的mesh增加三角网格,或者增加元素。新添加的元素在mesh的最后,且函数返回第一个添加元素的指针。如果新添加元素引起vector重新内存分配,则指向该类的vector的指针将无效。这些函数管理安全的重新分配以及指针更新所有的保存在mesh内部的指针,即如果添加一些vectors,且引起了vertex vector的重新内存分配,则在face结构中的指针指向vector,这些指针将会自动进行更新通过Allocator Functions。所以,用户不能直接进行reallocate 或者resize vectors or face vectors.
class MyMesh : public vcg::tri::TriMesh< std::vector<MyVertex>, std::vector<MyFace> > {};
int main()
{
MyMesh m;
MyMesh::VertexIterator vi = vcg::tri::Allocator<MyMesh>::AddVertices(m,);
MyMesh::FaceIterator fi = vcg::tri::Allocator<MyMesh>::AddFaces(m,);
MyMesh::VertexPointer ivp[];
ivp[]=&*vi; vi->P()=MyMesh::CoordType ( 0.0, 0.0, 0.0); ++vi;
ivp[]=&*vi; vi->P()=MyMesh::CoordType ( 1.0, 0.0, 0.0); ++vi;
ivp[]=&*vi; vi->P()=MyMesh::CoordType ( 0.0, 1.0, 0.0); ++vi;
fi->V()=ivp[];
fi->V()=ivp[];
fi->V()=ivp[];
在platonic.h文件中有很多增加元素的例子。
如果用户内部的一些指针指向mesh元素,但是增加的元素可能无效这些指针,可以通过传入vcg::tri::Allocator函数,来更新这些内部的私有指针。
// a potentially dangerous pointer to a mesh element
MyMesh::FacePointer fp = &m.face[];
vcg::tri::Allocator<MyMesh>::PointerUpdater<MyMesh::FacePointer> pu;
// now the fp pointer could be no more valid due to eventual re-allocation of the m.face vector.
vcg::tri::Allocator<MyMesh>::AddVertices(m,);
vcg::tri::Allocator<MyMesh>::AddFaces(m,,pu);
// check if an update of the pointer is needed and do it.
if(pu.NeedUpdate()) pu.Update(fp);
Destroying Elements
vcglib采用 lazy Deletion Strategy(惰性删除策略),即在vector中的元素通过flagged处理,进行“预删除”,即它们仍然在这里。
标记deleted的mark元素,对生于的结构没有影响。因此如果标记顶点但是没有合适所有的face,且面依附这个已经removed的vertex,则用户创建了一个非一致的状态。
用户永远不要试图自行删除vertex,即自行进行删除标记,用户需要调用Allocator Utility Function。
// Now fill the mesh with an Icosahedron(二十面体) and then delete some faces
vcg::tri::Icosahedron(m);
vcg::tri::Allocator<MyMesh>::DeleteFace(m,m.face[]);
vcg::tri::Allocator<MyMesh>::DeleteFace(m,m.face[]);
如上面的例子,在一个二十面体重删除一些vertex。通过上述操作,faces的vertor仍然包含20个元素(二十面体重包含面的数量),但是m.FN()返回的是18面,因此如果算法中含有删除处理,则可能会发生容器中的数量不等于mesh中有效的元素数量。
m.vert.size() != m.VN()m.face.size() != m.FN()
因此,当用户扫描vertects和face的容器时,可能会遇到被deleted marked的元素,所以用户需要格外小心。通过调用IsD()进行检测判定处理。
// If you loop in a mesh with deleted elements you have to skip them!
MyMesh::CoordType b(,,);
for(fi = m.face.begin(); fi!=m.face.end(); ++fi )
{
if(!fi->IsD()) // <---- Check added
{
b += vcg::Barycenter(*fi);
}
}
在一些情形中,当用户遍历大量的mesh的元素时,通过上述isD()检测效率低,可以通过简便实用的两个garbage collection function函数,通过显示调用:
通过掉应上述两个函数,就不需要对mesh的元素进行isD()检测,直接进行操作,效率更高。
m.vert.size() == m.VN()m.face.size() == m.FN()
注意:
1. 如果在mesh中没有deleted标识的元素, compactor函数将直接返回(其内部通过判定,容器vector的size函数是否与元素数量匹配判定),所以在左右的高强度操作前调用compactor函数非常安全。
2. 如果不清楚deleted元素位置,则不能通过m.FN ()或者m_VN()函数来作为for函数的终止条件,因为m.FN() != m.face.size(),因为m.FN()是有效的face的数量,而m.face.size()是face的容器的元素数量,因为容器中可能包含deleted标记的元素,这deleted标记的元素不是有效的元素。下面的例子是WRONG!!!!
// WRONG WAY of iterating: FN() != m.face.size() if there are deleted elements
for(int i=;i<m.FN();++i)
{
if(!fi->IsD())
{
b += vcg::Barycenter(*fi);
}
}
How to copy a mesh
考虑到intricate nature (复杂的本质) of mesh, vcglib库禁止拷贝mesh作为一个简单的对象。
如果需要拷贝mesh,则必须使用附加的工具类: The Append Utility Class。
MyMesh m2;
vcg\complex\append.h文件中包含了工具类:Append的详细实现。还有可以实现可选的mesh,或者添加后一个mesh到前一个mesh中的工具。
4. Adding user defined attributes to mesh elements
User-Defined Attributes
vcglib提供简单的机制来关联user-defined 属性到“简素”simplicies以及mehs。
attributes以及components都是与simplex关联的数据,即components是静态定义的成员数据,attributes则是运行时run-time定义的,处理的数据。
二者的区别:1,conceptually(概念上) component是指来定义simplex(简素)的基本的信息,如position,normal,以及相关的信息。但是user-defined attribute是针对指定的算法而添加的可获取的数据信息,如一个定点可见的平均方向。2. pratically(事实上), 对于每一个optional Conponents,都有其本身non-optional 部分,而且可以通过simplex(简素)的成员函数可以获取,如Vi->N()。对于属性attribute则只能通过创建attribute然后返回。
// add a per-vertex attribute with type float named "Irradiance"
MyMesh::PerVertexAttributeHandle<float> named_hv = vcg::tri::Allocator<MyMesh>:: GetPerVertexAttribute<float> (m,std::string("Irradiance"));
可以通过handle或者name来删除属性。注意,handle的作用于并不干扰属性的内存的分配。如果没有显示地(explicitly)删除属性,该属性将会一直保留分配的内存,指导mesh被摧毁,及时没有任何handle可以处理。
// delete an attribute by name
vcg::tri::Allocator<MyMesh>::DeletePerVertexAttribute(m, "Radiosity");// delete an attribute by handle
上述两个方法可以同样适应于edges,faces以及mesh。仅仅通过替换PerVertex,PerFace,PerEdge,PerMesh等。如果增加属性但是没有指定名字且丢失handle,则将不会把handle重新返回。
对于Per-Mesh的指定的属性,可以通过稍微不同的方式获取:
// you can also have PerMesh attributes
MyMesh::PerMeshAttributeHandle<int> hm = vcg::tri::Allocator<MyMesh>:: GetPerMeshAttribute<int> (m,std::string("ADummyIntegerAttribute"));
// PerMesh attributes are accessed directly using the handle itself
hm() = ;
C++ type of a mesh and reflection
VCGlib 提供一系列的函数来实现reflection(反射),如在运行时获取mesh的类型。这些函数遵循以下格式: Has[attribute](mesh),然后返回一个boolean值,表示指定的属性是否存在。
因为VCGlib的反射机制考虑了可选组件optional components,因此HasPerVertexNormal(m)返回ture,如果vertex的类型包含属性vcg::vertex::Normal3f 或者如果包含属性作为opetional,vcg::vertex::Normal3fOCF 且 enabled。
5. Loading and saving meshes
VCGlib提供以下的文件格式进行导入导出:
import: PLY, STL, OFF, OBJ, 3DS, COLLADA, PTX, V3D, PTS, APTS, XYZ, GTS, TRI, ASC, X3D, X3DV, VRML, ALN
export: PLY, STL, OFF, OBJ, 3DS, COLLADA, VRML, DXF, GTS, U3D, IDTF, X3D
以下例子读取PLY的文件:
#include <wrap/io_trimesh/import.h>
// definition of type MyMesh
MyMesh m;
vcg::tri::io::ImporterPLY<MyMesh>::Open(m,"namefile_to_open.ply");
// ....
vcg::tri::io::ExporterPLY<MyMesh>::Save(m,"namefile_to_save.ply");
上述是最小要求的导入导出接口。额外的其他两个参数可以指定:mask以及callback。 callback 用于提供再长时间的导入/导出过程的回调处理。mask用来更好的指定/理解导入/导出的内容。
Saving Mask and Reading Mask
一般而言,所有的文件格式至少保留vertex位置信息,和相互之间关联(拓扑)信息。但是,这些信息之外,用户可能还保留其他信息保存在文件file中。VCGLib提供类vcg::tri::io::Mask,是bit名字的集合,用来指定components保存在file中,如vcg::tri::io::Mask::IOM_VERTColor。
当Saving, 且在Read Only模式下,mask指定来保存指定的component。如,当保存mesh normal中的每个定点的法相(用于渲染),但是保存在PLY文件中是浪费文件空间大小,则需要指定一个合适的mash,即Mask::IOM_VERTNormal bit clearled。显然,不是所有的格式能够保存所有可能的数据。例如,STL文件不能保存纹理texture coords或者每一个定点的color。所以需要首先知道需要保存的文件支持的保存的能力,通过函数ExporterXXX::GetExportMaskCapability(),返回一个bitMask,即表示该文件格式的能力。
当Loading, 且在WriteOnly模式下,可以返回给用户那些部分的数据从文件中load到mesh对象中。如mask的初始信息将被忽略。能够用来知道用来准备mesh对象需要提供的信息数据。如需要知道哪些(指定)optional components,所有的importer的函数:ImporterXXX::LoadMask(fileName, mask),将会填充mask,而不loading 文件。
Error Reporting
mesh的I/O 函数成功运行,则返回ZERO(0);当遇到失败或者致命的问题,则返回Error code代码。使用static const char * ErrorMsg(int error)函数返回可以用户阅读的错误代码描述,以及通过静态函数: bool ErrorCritical(int err)来获取Error Code是致命问题,还是警告问题。例如,在OBJ文件格式,由于文件中缺少材料描述,被认为非致命的问题,因为还可以获取模型几何信息用户建模。
VMI dump file
VMI,即Vcglib Mesh Image,并不是合适的文件格式,但是是一种简单的vcg::TRiMesh导出的文件格式。之所以认为其不是一个合适的文件格式,是因为其没有提供指定的版本用于关联VCGlib的版本库以及后端的解析能力。相反,VMI则保存所有的components,所有的历史components(Currently OCF类型),所有的点,面,mesh属性,但是算法可能会cash在n-step。则可以立即保存计算的结果在VMI文件中,然后在load 这个文件。
注意:当使用vcg::tri::ImporterVMI<MeshType>(...)来load VMI文件,则需要指定与vcg::tri::ExporterVMI<MeshType>(..)
导出的文件格式一致,否则会返回FALSE。
endl;
几个经典的数学库之一学习---VCGlib(2)的更多相关文章
- 几个经典的数学库之一学习---VCGlib(3)
Camera and shot abstraction for managing views 视图的定义,以及mesh的操作说明. Shot(镜头) and camera(相机) shot摄像结构以及 ...
- 几个经典的数学库之一学习---VCGlib(1)
1. VCG Libary是Visulization and Computer Graphics Libary(可视化与计算机图形学库)的缩写,是一个开源的C++模板库,用于三角网格和四面体网格的控制 ...
- DirectX11 学习笔记6 - 使用D3DXMATH数学库的一个样例
这个样例是在之前的样例基础上 .把之前d3dx10math数学库换成了最新的d3dxmath.长处就不说了.先上效果图 所有代码.以及效果文件 文件结构 所有代码: 依照上图的文件顺序 #pragma ...
- <泛> C++3D数学库设计详解 向量篇
// 注:本内容为作者原创,禁止在其他网站复述内容以及用于商业盈利,如需引用,请标明出处:http://www.cnblogs.com/lv_anchoret/ Preface 为了支持光线追踪的学习 ...
- GEOS库的学习之一:介绍和编译
对GEOS库的学习,源于一个项目:要在c++中判断二维平面中两个多边形的关系(无论凹凸).也就是判断两个多边形是否相交.相容等.听起来很简单,可实现起来却比较难,而项目又催得紧.于是我去搜索了一下,看 ...
- 标准模板库(STL)学习探究之stack
标准模板库(STL)学习探究之stack queue priority_queue list map/multimap dequeue string
- 标准模板库(STL)学习探究之vector容器
标准模板库(STL)学习探究之vector容器 C++ Vectors vector是C++标准模板库中的部分内容,它是一个多功能的,能够操作多种数据结构和算法的模板类和函数库.vector之所以被 ...
- 微软数学库XNAMATH(DirectXMath)
这篇文章只是对着MSDN文档的一些吐槽和总结记录,个人笔记之类的 运行库与头文件 老实说,这个数学库微软还是更像蛮频繁的,我这里有的最早版本是伴随DX9的,在这个头文件里面 最近在使用DXUT,顺便也 ...
- 一个很cool的C#的高性能数学库
High Performance Math Library for C# and .NET是一个很cool的C#的高性能数学库,3D效果也很不错,下图是首页上的一个例子.他也有一个交互的网页,你可以自 ...
随机推荐
- [转]被玩坏的innerHTML、innerText、textContent和value属性
一.前言 由于innerText并非W3C标准属性,因此我们无法在FireFox中使用它,一般情况下我们可以使用textContent来代替,但它两者是否就能完全等同呢?在坑爹的表单元素(如input ...
- spark性能调优 数据倾斜 内存不足 oom解决办法
[重要] Spark性能调优——扩展篇 : http://blog.csdn.net/zdy0_2004/article/details/51705043
- 疯狂JAVA——第六章 面向对象(下)
6.1包装类 java为了照顾程序员的传统习惯,所以提供了八种基本数据类型.但也带来不方便,例如所有引用类型都继承自Object类,都可当做Object类型变量使用.但基本数据类型的变量就不可以.如果 ...
- Asp.net中FileUpload控件实现图片上传并带预览显示
单一图片上传——“选择”+“上传”,.NET默认模式: 1.实现原理: 采用FileUpload控件默认的使用方式,先由“选择”按钮选择图片,然后单击“上传”按钮完成上传,并可在“上传”按钮的 ...
- c++流操作
非缓冲标准出错流对象cerr和缓冲标准出错流对象clog,它们都是来自于ostream类的对象,用于输出错信息.cerr和clog之间的不同之处在于cerr是不经过缓冲区直接向显示器输出有关信息,而c ...
- python内置函数之attr【反射】
#Auther Bob#--*--conding:utf-8 --*-- #我们来循序渐进的学习反射 import s1 #阶段1# def run():# url = input("请输入 ...
- iOS - OC - 字典快速遍历
1. [dic enumerateKeysAndObjectsUsingBlock:^(id _Nonnull key, id _Nonnull obj, BOOL * _Nonnull stop ...
- Spring框架的Bean管理的配置文件方式
1. id属性和name属性的区别 * id -- Bean起个名字,在约束中采用ID的约束,唯一 * 取值要求:必须以字母开始,可以使用字母.数字.连字符.下划线.句话.冒号 id:不能出现特殊字符 ...
- 在iframe框架中全屏不好使的原因
遇到的问题:我是在iframe框架中添加了一个插件在360和火狐中不好使,将allowfullscreen="true" 属性配置好就没问题了: 可能出现的原因:将allowful ...
- DB2数据库常用命令数据库学习
DB2数据库常用命令数据库学习你可以用 get snapshot for locks on XXX 看是那个表锁了,再从相关的操作去查原因吧 db2pd -d 库名 -locks和db2pd -d 库 ...