【OpenMesh】使用網格的屬性和特征


例子主要展示如何改變位置,法向量,顏色和紋理的數據類型。
在之前的指南中我們學習使用標准屬性,通過調用適合的請求方法。不像自定義屬性,用戶通過傳遞數據類型到句柄來指定數據類型(比如,MyMesh::FPropHandleT< int>),標准屬性的數據類型定義為網格特征。我們可以和特征一起定制和擴展網格數據結構。我們通過兩方面做到這一點。

  • 改變位置(Position),法向量(Normal),顏色(Color),和紋理坐標(Texture coordinate不知道翻譯對了沒)的數據類型。
  • 擴展網格實體,包括頂點,面,邊和Halfedge.

我們開始吧。每一個定制特性應該繼承自默認特性。

struct MyTraits : OpenMesh::DefaultTraits

之前提到的,我們可以為基本數據類型改變基礎數據結構 MyMesh::Point, MyMesh::Normal, MyMesh::Color, and MyMesh::TexCoord。我們可以使用提供的向量類或者我們使用其他類庫提供的類。這里我們簡單的替換Position和Normal的默認類型OpenMesh::Vec3f為OpenMesh::Vec3d

typedef OpenMesh::Vec3d Point;
typedef OpenMesh::Vec3d Normal;

(通常,Point和Normal向量最好用相同的標量類型,比如在這里使用double型。不然我們將要必須考慮向量類的實現。)
注意,這些設置覆蓋父類的特征!正如我們通常繼承DefaultTraits,讓我們仔細看看。
實際上,OpenMesh::DefaultTraits僅僅是一個沒有內容的類。它只是為Point,Normal,TexCoord和Color以及一個屬性定義了類型,我們一直隱式地使用它們:

// HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge );

屬性PrevHalfedge是不同的,因為它沒有控制屬性。然而,它對網格類型的最終結果有個很大的影響,因為它在Halfedge結構中添加了額外的信息。影響有兩點:
快速地訪問前一個Halfedge
添加內存消耗(居然不是一個優點……)
使用這個特點取決於我們的需要。一種情況是我們需要訪問前一個Halfedge非常便利,這是網格的成員變量函數add_face().當前一個Halfedge可用的時候,成員函數的執行時間迅速下降。通常我們希望有這個信息。但是為了節約內存,我們可以輕松的移除這個特性

// HalfedgeAttributes( OpenMesh::Attributes::None );

然后我們需要少於8Byte的空間存儲一條邊,這就節省很多了,通過歐拉方程可以知道V-E+F=2(1-g),對於一個三角形網格,g=0,邊的數目幾乎是三倍的頂點數,既E=3V。
完整的代碼:

#include <iostream>
#include <typeinfo>
// --------------------
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Core/Geometry/VectorT.hh>
#ifndef DOXY_IGNORE_THIS
// Define my personal traits
struct MyTraits : OpenMesh::DefaultTraits
{
// Let Point and Normal be a vector of doubles
typedef OpenMesh::Vec3d Point;
typedef OpenMesh::Vec3d Normal;
// Already defined in OpenMesh::DefaultTraits
// HalfedgeAttributes( OpenMesh::Attributes::PrevHalfedge );

// Uncomment next line to disable attribute PrevHalfedge
// HalfedgeAttributes( OpenMesh::Attributes::None );
//
// or
//
// HalfedgeAttributes( 0 );
};
#endif
// Define my mesh with the new traits!
typedef OpenMesh::TriMesh_ArrayKernelT<MyTraits> MyMesh;
// ------------------------------------------------------------------ main ----
int main(int argc, char **argv)
{
MyMesh mesh;
if (argc!=2)
{
std::cerr << "Usage: " << argv[0] << " <input>\n";
return 1;
}
// Just make sure that point element type is double
if ( typeid( OpenMesh::vector_traits<MyMesh::Point>::value_type ) 
!= typeid(double) )
{
std::cerr << "Ouch! ERROR! Data type is wrong!\n";
return 1;
}
// Make sure that normal element type is double
if ( typeid( OpenMesh::vector_traits<MyMesh::Normal>::value_type ) 
!= typeid(double) )
{
std::cerr << "Ouch! ERROR! Data type is wrong!\n";
return 1;
}
// Add vertex normals as default property (ref. previous tutorial)
mesh.request_vertex_normals();
// Add face normals as default property
mesh.request_face_normals();
// load a mesh
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 ) &&
mesh.has_face_normals() && mesh.has_vertex_normals() )
{
// let the mesh update the normals
mesh.update_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;
}
return 0;
}




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM