正如我们已经看到的,我们可以通过属性将其他数据绑定到网格实体。 OpenMesh提供了一组所谓的标准属性。 与自定义属性不同,它们具有一些特殊功能和不同的界面。下表列出了所有可用的标准属性以及可以使用它的合适实体。
要向实体添加标准属性,只需使用适当的请求方法,例如request_face_normals()。 唯一的例外是位置(*)。 它无法添加,因为它永久可用,因此也无法删除。
在这个例子中我们将做如下工作:
- 将顶点法线添加到网格对象
- 加载文件
- 检查文件是否提供顶点法线,否则计算它们
- 沿着法线方向移动每个顶点一个单位长度
- 将结果位置打印到std :: cout
让我们从向网格添加顶点法线开始:
以类似的方式,我们可以请求其他标准属性。 例如,面法线:
我们需要它们用update_normals()计算顶点法线,如果文件没有提供任何可用的信息。我们可以使用标准属性做更多事情。 我们可以验证网格是否已经具有属性顶点法线。
使用后我们再次删除它们
如果例如顶点状态属性已被请求两次会发生什么? 第一个版本什么都不做,但第二个版本将删除它。 标准属性有一个引用计数器,每个请求递增1,每个版本递减1。 如果计数器达到0,则属性将从内存中删除。
常用的申请属性与释放属性以及测试属性存在的函数
status属性用于标记几何元素,即选择或删除。
现在我们知道如何添加和删除标准属性,但我们如何访问它们? 我们再次需要网格对象。 与自定义属性不同,我们使用网格成员函数property()访问它,对于每个标准属性,网格提供了get和set方法。 我们在前三个教程中已经使用了一对get / set方法,我们计算了顶点位置的新位置。 在这里,我们沿着法线方向移动所有顶点的单位长度:
get-methods接受实体句柄并返回所需属性的值,set-methods需要一个额外的参数来将新值传递给属性。 根据该表,并非每对get / set方法都适用于每个实体。 例如,face通常没有纹理坐标,因此在编译代码时调用mesh.texcoord2D(_face_handle)将导致错误。
具体的示例代码如下所示:
#include <iostream>
// --------------------
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
typedef OpenMesh::TriMesh_ArrayKernelT<> MyMesh;
int main(int argc, char **argv)
{
MyMesh mesh;
if (argc!=2)
{
std::cerr << "Usage: " << argv[0] << " <input>\n";
return 1;
}
// request vertex normals, so the mesh reader can use normal information
// if available
mesh.request_vertex_normals();
// assure we have vertex normals
if (!mesh.has_vertex_normals())
{
std::cerr << "ERROR: Standard vertex property 'Normals' not available!\n";
return 1;
}
OpenMesh::IO::Options opt;
if ( ! OpenMesh::IO::read_mesh(mesh,argv[1], opt))
{
std::cerr << "Error loading mesh from file " << argv[1] << std::endl;
return 1;
}
// If the file did not provide vertex normals, then calculate them
if ( !opt.check( OpenMesh::IO::Options::VertexNormal ) )
{
// we need face normals to update the vertex normals
mesh.request_face_normals();
// let the mesh update the normals
mesh.update_normals();
// dispose the face normals, as we don't need them anymore
mesh.release_face_normals();
}
// move all vertices one unit length along it's normal direction
for (MyMesh::VertexIter v_it = mesh.vertices_begin();
v_it != mesh.vertices_end(); ++v_it)
{
std::cout << "Vertex #" << *v_it << ": " << mesh.point( *v_it );
mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) );
std::cout << " moved to " << mesh.point( *v_it ) << std::endl;
}
// don't need the normals anymore? Remove them!
mesh.release_vertex_normals();
// just check if it really works
if (mesh.has_vertex_normals())
{
std::cerr << "Ouch! ERROR! Shouldn't have any vertex normals anymore!\n";
return 1;
}
return 0;
}