在读/写网格时可以使用OpenMesh :: IO :: Options类。 它通过位集中的启用/禁用位控制读写器模块的行为。 该类提供了一个用于启用,禁用和验证集合中的位的接口。 我们区分如下:
这些位在读取或写入时具有不同的效果。 文件格式本身由文件名的扩展名选择。
请注意,每个网格必须在加载相应选项之前请求标准属性。 例如,如果启用Options :: VertexNormal,则网格必须请求顶点法线。 否则,它们将不会被写入网格中。
Face Tex Coords不会被保存为每个面的属性,而是作为每个半边的属性。 因此,您必须请求“halfedge_texcoords2D”属性。
OBJ阅读器还可以读取* .mtl文件中有关纹理的信息(如果有)。 这些纹理信息(包括texturename和index)将保存在类型的属性中:
如果找到纹理,将自动创建此属性。 除了属性请求旁边,您无需定义其他选项来读取纹理信息。此外,如果请求属性“face_texture_index”,OBJ加载程序会在每个面上写入纹理索引。 纹理索引与纹理映射中写入的索引相同。 因此,可以通过纹理映射属性上的纹理索引到纹理名称,从面部获取纹理的名称。 但请记住,在加载网格之前,必须首先请求面纹理索引属性。
在下表中,您可以看到哪些读取器/写入器支持哪些选项(数据格式可能支持更多)。 ASCII不是一个真正的选项,如果没有定义二进制,将被选中。
*)可以读取非标准扩展顶点颜色(仅浮动):
**)只有具有基本类型的顶点和面属性。 请注意,您不必在加载前请求这些自定义属性。
***)没有读取操作存在。
Reading meshes
- 在读取文件时,模式位用于向读者提供建议或提示。 根据格式,我们可以帮助读者正确解释数据。 首先,我们可以告诉它该文件包含二进制数据。
- 此外,我们可以要求读者两个交换字节顺序。
- 默认情况下,将从文件中恢复几何体和拓扑。 该文件可能包含更多,特别是它可以提供法线或纹理坐标。 我们可以在阅读后检查属性位以找出可用的其他内容:
- 如果设置了属性位,那么它并不意味着它已经被恢复。 必须在阅读文件之前请求该属性。
Writing meshes
- 在写入网格时,模式位显然控制是否使用二进制变量和所需的字节顺序。 例如,如果我们选择二进制模式并想要交换字节顺序,我们设置
- 如果格式未指定字节顺序,则使用系统字节顺序。 如果格式不支持二进制存储,则忽略模式位。
- 如果格式支持存储符合标准属性的附加信息,我们可以使用属性位来告诉作者我们想要存储的内容。 如果我们想存储顶点法线,我们只需设置
- 最后,我们可以将数据写入文件
- 该方法在出错时返回false,这可能有三个不同的原因:
- 选择的格式不支持该选项
- 选定的标准属性不可用
- 一个'系统'错误就像:由于访问权限无法打开文件、写入期间磁盘空间耗尽
完整的源代码如下所示:
#include <iostream>
#include <iterator>
// -------------------- OpenMesh
#include <OpenMesh/Core/IO/MeshIO.hh>
#include <OpenMesh/Core/Mesh/TriMesh_ArrayKernelT.hh>
#include <OpenMesh/Tools/Utils/getopt.h>
// ----------------------------------------------------------------------------
using namespace OpenMesh;
// ----------------------------------------------------------------------------
typedef TriMesh_ArrayKernelT<> MyMesh;
// ----------------------------------------------------------------------------
#define CHKROPT( Option ) \
std::cout << " provides " << #Option \
<< (ropt.check(IO::Options:: Option)?": yes\n":": no\n")
#define CHKWOPT( Option ) \
std::cout << " write " << #Option \
<< (wopt.check(IO::Options:: Option)?": yes\n":": no\n")
#define MESHOPT( msg, tf ) \
std::cout << " " << msg << ": " << ((tf)?"yes\n":"no\n")
// ----------------------------------------------------------------------------
void parse_commandline( int _argc, char **_argv, MyMesh& _mesh,
IO::Options &ropt, IO::Options &wopt );
void usage_and_exit(int xcode);
// ----------------------------------------------------------------------------
int main(int argc, char **argv)
{
MyMesh mesh;
IO::Options ropt, wopt;
// -------------------- evaluate commandline
parse_commandline( argc, argv, mesh, ropt, wopt );
// -------------------- read mesh
if ( ! IO::read_mesh(mesh,argv[optind], ropt))
{
std::cerr << "Error loading mesh from file " << argv[optind] << std::endl;
return 1;
}
// -------------------- show options
std::cout << "File " << argv[optind] << std::endl;
std::cout << " is binary: "
<< (ropt.check(IO::Options::Binary) ? " yes\n" : " no\n");
std::cout << " byte order: ";
if (ropt.check(IO::Options::Swap))
std::cout << "swapped\n";
else if (ropt.check(IO::Options::LSB))
std::cout << "little endian\n";
else if (ropt.check(IO::Options::MSB))
std::cout << "big endian\n";
else
std::cout << "don't care\n";
std::cout << " provides VertexNormal"
<< ( // strange layout for doxygen
ropt.check(IO::Options::VertexNormal)
? ": yes\n":": no\n");
CHKROPT( VertexColor );
CHKROPT( VertexTexCoord );
CHKROPT( FaceNormal );
CHKROPT( FaceColor );
// -------------------- mesh stats
std::cout << "# Vertices: " << mesh.n_vertices() << std::endl;
std::cout << "# Edges : " << mesh.n_faces() << std::endl;
std::cout << "# Faces : " << mesh.n_faces() << std::endl;
// -------------------- show write options
std::cout << "Selected write options:\n";
std::cout << " use binary: "
<< (wopt.check(IO::Options::Binary) ? " yes\n" : " no\n");
std::cout << " byte order: ";
if (wopt.check(IO::Options::Swap))
std::cout << "swapped\n";
else if (wopt.check(IO::Options::LSB))
std::cout << "little endian\n";
else if (wopt.check(IO::Options::MSB))
std::cout << "big endian\n";
else
std::cout << "don't care\n";
std::cout << " write VertexNormal"
<< (wopt.check(IO::Options::VertexNormal) ? ": yes\n":": no\n");
CHKWOPT( VertexColor );
CHKWOPT( VertexTexCoord );
CHKWOPT( FaceNormal );
CHKWOPT( FaceColor );
// -------------------- show mesh capabilities
std::cout << "Mesh supports\n";
MESHOPT("vertex normals", mesh.has_vertex_normals());
MESHOPT("vertex colors", mesh.has_vertex_colors());
MESHOPT("texcoords", mesh.has_vertex_texcoords2D());
MESHOPT("face normals", mesh.has_face_normals());
MESHOPT("face colors", mesh.has_face_colors());
// -------------------- write mesh
std::cout << "Write mesh to " << argv[optind+1] << "..";
if ( !IO::write_mesh( mesh, argv[optind+1], wopt ) )
{
std::cerr << "Error" << std::endl;
std::cerr << "Possible reasons:\n";
std::cerr << "1. Chosen format cannot handle an option!\n";
std::cerr << "2. Mesh does not provide necessary information!\n";
std::cerr << "3. Or simply cannot open file for writing!\n";
return 1;
}
else
std::cout << "Ok.\n";
return 0;
}
// ----------------------------------------------------------------------------
void parse_commandline( int _argc, char **_argv, MyMesh& _mesh,
IO::Options &ropt, IO::Options &wopt )
{
int c;
while ((c=getopt(_argc, _argv, "bhsBF:LMSV:X:"))!=-1)
{
switch(c)
{
// -------------------- read options
// force binary input
case 'b':
ropt += IO::Options::Binary;
break;
// force swapping the byte order, when reading a binary file
case 's':
ropt += IO::Options::Swap;
break;
// -------------------- write options
// Write binary variant of format if possible
case 'B':
wopt += IO::Options::Binary;
break;
//
case 'F':
for(size_t i=0; optarg[i]; ++i)
switch(optarg[i]) {
case 'n' : wopt += IO::Options::FaceNormal; break;
case 'c' : wopt += IO::Options::FaceColor; break;
}
break;
// Use little endian when writing binary data
case 'L':
wopt += IO::Options::LSB;
break;
// Use big endian when writing binary data
case 'M':
wopt += IO::Options::MSB;
break;
// Swap byte order when writing binary data
case 'S':
wopt += IO::Options::Swap;
break;
//
case 'V':
{
for(size_t i=0; optarg[i]; ++i)
switch(optarg[i]) {
case 'n' : // dont't change layout!!
wopt += IO::Options::VertexNormal;
break;
case 't' : wopt += IO::Options::VertexTexCoord; break;
case 'c' : wopt += IO::Options::VertexColor; break;
}
break;
}
// -------------------- request mesh' standard properties
case 'X':
{
char entity='\0';
for(size_t i=0; optarg[i]; ++i)
switch(optarg[i]) {
case 'v':
case 'f': entity = optarg[i]; break;
case 'n':
switch(entity) {
case 'v': _mesh.request_vertex_normals(); break;
case 'f': _mesh.request_face_normals(); break;
}
break;
case 'c':
switch(entity) {
case 'v': _mesh.request_vertex_colors(); break;
case 'f': _mesh.request_face_colors(); break;
}
break;
case 't':
switch(entity) {
case 'v': _mesh.request_vertex_texcoords2D(); break;
}
break;
}
break;
}
// -------------------- help
case 'h':
usage_and_exit(0);
default:
usage_and_exit(1);
}
}
if ( _argc-optind != 2)
usage_and_exit(1);
}
// ----------------------------------------------------------------------------
void usage_and_exit(int xcode)
{
std::ostream &os = xcode ? std::cerr : std::cout;
os << "Usage: io_options [Options] <input> <output>\n"
<< std::endl;
os << " Read and write a mesh, using OpenMesh::IO::Options\n"
<< std::endl;
os << "Options:\n"
<< std::endl;
os << "a) read options\n"
<< std::endl
<< " -b\n"
<< "\tAssume input file is a binary file\n"
<< std::endl
<< " -s\n"
<< "\tSwap byte order when reading a binary file!\n"
<< std::endl;
os << "b) write options\n"
<< std::endl
<< " -B\n"
<< "\tWrite binary data\n"
<< std::endl
<< " -S\n"
<< "\tSwap byte order, when writing binary data\n"
<< std::endl
<< " -M/-L\n"
<< "\tUse MSB/LSB byte ordering, when writing binary data\n"
<< std::endl
<< " -V{n|t|c}\n"
<< "\tWrite vertex normals, texcoords, and/or colors\n"
<< std::endl
<< " -F{n|c}\n"
<< "\tWrite face normals, and/or colors\n"
<< std::endl;
os << "c) Mesh properties\n"
<< std::endl
<< " -Xv{n|c|t}\n"
<< "\tRequest vertex property normals|colors|texcoords\n"
<< std::endl
<< " -Xf{n|c}\n"
<< "\tRequest face property normals|colors\n"
<< std::endl;
exit(xcode);
}
// end of file
// ============================================================================