【OpenMesh】文件读取和写入

原文出处:http://openmesh.org/Documentation/OpenMesh-Doc-Latest/mesh_io.html

这一节讲的是从文件中读取网格数据和写入网格数据到文件的方法。

响应的函数定义在名字空间OpenMesh::MeshIO中。这一节分成三部分。第一步给出例子讲述如何使用IOManager,第二步讲述IOManager的背景信息,第三步展示如何添加模块到IOManager。

第一步IOManager快速开始

复制以下代码到工程中。
注意:
  • 如果你静态链接OpenMesh,你必须添加OM_STATIC_BUILD到你的应用程序中。这保证读取器和写入器正确初始化。
  • IOManager使用文件名扩展名来决定哪一个写入器或者读取器被使用。比如,如果传送的文件是"inoutmesh.obj",OBJ-File 写入器和读取器会被使用来进行文件操作。
#include <OpenMesh/Core/IO/MeshIO.hh>
MyMesh mesh;
if (!OpenMesh::IO::read_mesh(mesh, "some input file")) 
{
std::cerr << "read error\n";
exit(1);
}
// do something with your mesh ...
if (!OpenMesh::IO::write_mesh(mesh, "some output file")) 
{
std::cerr << "write error\n";
exit(1);
}

第二步IOManager的理论

通常网格数据的读取器和写入器流程通常是直接写入数据结构和相对应的支持文件格式。这种方法有一个显著的缺点,就是目标是不同的数据结构或者添加的是另一种文件格式的时候会导致代码冗余。

IOManager扮演者接口的角色,通过读取器和写入器以及输入输出模块连接一边是持久性数据而另一边是任意数据结构。


任意格式的持久性数据首先被读取模块转化。数据之后通过特定的接口被传送到目标数据结构。写入数据的过程也是相似的。IOManager控制整个过程。读取器和写入器模块对用户是不可见的。然而输入输出模块必须被显示的指定,因为这些模块是针对特定的数据结构的。

数据结构和持久性数据的完全分离使得代码维护和功能扩展非常容易,第三步将会体现。

第三步如何扩展IOManager

添加支持新文件

添加支持新文件涉及到添加读取器和写入器模块。读取器模块继承于OpenMesh::IO::BaseReader。接口模块通常这样定义。
class BaseReader
{
public:
virtual std::string get_description() const = 0;
virtual std::string get_extensions() const = 0;
virtual std::string get_magic() const { return std::string(""); }
virtual bool read(std::istream& _is, BaseImporter& _bi) const = 0;
virtual bool read(const std::string& _filename, BaseImporter& _bi) const = 0;
...
};
基于文件扩展名和文件头信息,IOManager决定哪一个读取器模块被使用。读取器模块解析格式和信息会被传送到目标数据结构,通过继承类OpenMesh::IO::BaseImporter。
写入器模块继承自 OpenMesh::IO::BaseWriter以及和读取器一样的工作方法。

添加新的数据结构

输入器从读取器接收数据。读取器模块通过特定的接口传送信息:
class BaseImporter
{
public:
virtual void add_vertex (const OpenMesh::Vec3f&) {};
virtual void add_normal (const OpenMesh::Vec3f&) {};
virtual void add_texture (const OpenMesh::Vec2f&) {};
virtual void add_face (const FaceType&) {};
};
输入器负责填充目标数据结构。从数据结构输出信息更像是输入数据。写入器模块必须能够迭代全部的向量/坐标/面。因此一个输出器必须提供迭代器:
class BaseExporter
{
public:
virtual void update() = 0;

virtual PVertexIter const_vertices_begin() = 0;
virtual PVertexIter const_vertices_end() = 0;

virtual PTexCoordIter const_texcoords_begin() = 0;
virtual PTexCoordIter const_texcoords_end() = 0;
virtual PIdxFaceIter const_idx_faces_begin() = 0;
virtual PIdxFaceIter const_idx_faces_end() = 0;
virtual PFaceIter const_set_faces_begin() = 0;
virtual PFaceIter const_set_faces_end() = 0;
virtual unsigned int n_faces() = 0;
virtual unsigned int n_vertices() = 0;
virtual unsigned int n_texcoords() = 0;
};
这可能需要输出器缓存引用的数据。update()函数应该在每一个BaseWriter::save()之前被调用来确保缓存数据被更新。
更多信息参考OpenMesh的IO子目录。
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
在使用OpenMesh读取.obj文件和纹理时,我们可以使用以下步骤: 第一步是使用OpenMesh的函数打开.obj文件,可以使用类似于下面的代码: ```cpp #include <iostream> #include <OpenMesh/Core/IO/MeshIO.hh> #include <OpenMesh/Core/Mesh/PolyMesh_ArrayKernelT.hh> typedef OpenMesh::PolyMesh_ArrayKernelT<> MyMesh; int main() { // 创建一个网格对象 MyMesh mesh; // 从.obj文件读取网格数据 if (!OpenMesh::IO::read_mesh(mesh, "filename.obj")) { std::cerr << "无法读取文件!" << std::endl; return 1; } // 打印顶点和面的数量 std::cout << "顶点数量: " << mesh.n_vertices() << std::endl; std::cout << "面数量: " << mesh.n_faces() << std::endl; return 0; } ``` 这样就可以使用OpenMesh读取.obj文件并打印出顶点和面的数量。 第二步是读取纹理信息。对于纹理信息,我们可以使用OpenMesh库的属性(Property)特性。可以使用以下代码读取.obj文件中的纹理坐标: ```cpp MyMesh::TexCoord2D texCoord; // 获取属性句柄 MyMesh::VertexHandle vh; // 检查是否有纹理坐标 if (mesh.has_vertex_texcoords2D()) { // 获取纹理坐标 texCoord = mesh.texcoord2D(vh); std::cout << "纹理坐标: " << texCoord[0] << ", " << texCoord[1] << std::endl; } ``` 当然,你也可以根据自己的需求进一步扩展代码,例如读取法线、颜色等其他属性信息。 总之,OpenMesh提供了方便的函数来读取.obj文件和纹理信息,你可以根据你的需求来使用它们。希望这个简短的回答对你有帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值