OpenMesh 教程:使用标准属性

使用标准属性

翻译,原文链接

本文包括

  • 如何添加和删除一个标准属性
  • 如何获取和设置标准属性的值

之前就已经知道,我们可以通过增加自定义属性的方式将额外的数据与网格进行绑定,OpenMesh 中也有不少内置的属性,姑且将之称为标准属性 (standard properties). 与自定义属性不同的是,标准属性具有一些特殊性质和不同的接口,本文将着重说明这些特别之处。

下表列出了不同网格要素 (entity) 能够使用的标准属性

VertexFaceEdgeHalfedge
ColorXXX
NormalXXX
Position (*)X
StatusXXXX
TexCoordXX

我们简单地用像request_face_normals()这样的函数来给某一网格要素添加属性,表中唯一的例外是 Position ,因为顶点坐标是必须一直保存的,所有它不能够人为的添加或删除。

接下来的例子,我们将展示:

  1. 给网格添加顶点法向量
  2. 读取网格文件
  3. 检查文件中是否包含顶点法向量以便确定是否需要重新计算法向量
  4. 将顶点沿着法向量方向移动一个单位长度
  5. std::cout 打印结果坐标

首先来添加顶点法向量

  mesh.request_vertex_normals();

同样也可以请求添加面法向量

mesh.request_face_normals();

如果读入的网格文件中没有顶点法向量,我们就需要用 update_normals 来计算法向量,我们也可以检查当前网格中有没有顶点法向量

if (!mesh.has_vertex_normals())
{
    std::cerr << "ERROR: Standard vertex property 'Normals' not available!\n";
    return 1;
}

如果不再需要法向量,可以用下面的函数删除它们

mesh.release_vertex_normals();

但是有一个问题,如果我们对顶点的某一状态属性做了两次请求,那么在调用相关 release 函数时又会发生什么呢?结果是第一次调用 release 函数时,并不会删除该属性,第二次调用时才会真正删除该属性。原因是 OpenMesh 中标准属性都有各自的引用计数 (reference counter),每调用一次 request函数,计数就加一;相反的每调用一次 release 函数,计数则减一;当计数为零时便删除该属性。

正如表格中所列,OpenMesh 中一共有9中可调用的标准动态属性, 它们 在OpenMesh::Concepts::KernelT 中都有各自的调用函数,具体如下:

  • request_edge_status()
  • request_edge_colors()
  • request_face_colors()
  • request_face_normals()
  • request_face_status()
  • request_face_texture_index()
  • request_halfedge_status()
  • request_halfedge_normals()
  • request_halfedge_texcoords1D()
  • request_halfedge_texcoords2D()
  • request_halfedge_texcoords3D()
  • request_vertex_colors()
  • request_vertex_normals()
  • request_vertex_status()
  • request_vertex_texcoords1D()
  • request_vertex_texcoords2D()
  • request_vertex_texcoords3D()

相应的删除函数为

  • release_edge_status()
  • release_edge_colors()
  • release_face_colors()
  • release_face_normals()
  • release_face_status()
  • release_face_texture_index()
  • release_halfedge_status()
  • release_halfedge_normals()
  • release_halfedge_texcoords1D()
  • release_halfedge_texcoords2D()
  • release_halfedge_texcoords3D()
  • release_vertex_colors()
  • release_vertex_normals()
  • release_vertex_status()
  • release_vertex_texcoords1D()
  • release_vertex_texcoords2D()
  • release_vertex_texcoords3D()

以及检查它们是否存在的函数

  • has_edge_status()
  • has_edge_colors()
  • has_face_colors()
  • has_face_normals()
  • has_face_status()
  • has_face_texture_index()
  • has_halfedge_status()
  • has_halfedge_normals()
  • has_halfedge_texcoords1D()
  • has_halfedge_texcoords2D()
  • has_halfedge_texcoords3D()
  • has_vertex_colors()
  • has_vertex_normals()
  • has_vertex_status()
  • has_vertex_texcoords1D()
  • has_vertex_texcoords2D()
  • has_vertex_texcoords3D()

其中状态属性 (status property) 可以用来标记几何元素,例如被选中 (selected) 或者已删除 (deleted),具体用法参见 Deleting geometry elements

现在我们已经知道如何添加和删除标准属性,那么该怎么获取它们的值呢?与自定义属性一样,我们需要用到网格对象,但不同的是,每一个标准属性都提供各自的 setget 函数,而不是像自定义属性一样用 property() 函数。这里我们看一下怎么将顶点沿着法线方向移动一个单位长度

for (MyMesh::VertexIter v_it = mesh.vertices_begin();
     v_it != mesh.vertices_end(); ++v_it)
{
    mesh.set_point( *v_it, mesh.point(*v_it)+mesh.normal(*v_it) );
}

get 函数需要输入一个要素 (entity) handle,set 函数则还需要额外输入一个待设定的值。从表中可以看到,并不是所有的要素有能够分配全部的标准属性,比如面通常是没有纹理坐标的,所以如果调用函数 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值