在读/写网格时可以使用OpenMesh :: IO :: Options类。 它通过位集中的启用/禁用位控制读写器模块的行为。 该类提供了一个用于启用,禁用和验证集合中的位的接口。 我们区分如下:
这些位在读取或写入时具有不同的效果。 文件格式本身由文件名的扩展名选择。
请注意,每个网格必须在加载相应选项之前请求标准属性。 例如,如果启用Options :: VertexNormal,则网格必须请求顶点法线。 否则,它们将不会被写入网格中。
Face Tex Coords不会被保存为每个面的属性,而是作为每个半边的属性。 因此,您必须请求“halfedge_texcoords2D”属性。
OBJ阅读器还可以读取* .mtl文件中有关纹理的信息(如果有)。 这些纹理信息(包括texturename和index)将保存在类型的属性中:
如果找到纹理,将自动创建此属性。 除了属性请求旁边,您无需定义其他选项来读取纹理信息。此外,如果请求属性“face_texture_index”,OBJ加载程序会在每个面上写入纹理索引。 纹理索引与纹理映射中写入的索引相同。 因此,可以通过纹理映射属性上的纹理索引到纹理名称,从面部获取纹理的名称。 但请记住,在加载网格之前,必须首先请求面纹理索引属性。
在下表中,您可以看到哪些读取器/写入器支持哪些选项(数据格式可能支持更多)。 ASCII不是一个真正的选项,如果没有定义二进制,将被选中。
*)可以读取非标准扩展顶点颜色(仅浮动):
**)只有具有基本类型的顶点和面属性。 请注意,您不必在加载前请求这些自定义属性。
***)没有读取操作存在。
完整的源代码如下所示:
#include
#include
// -------------------- OpenMesh
#include
#include
#include
// ----------------------------------------------------------------------------
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]